PageSourceSearch

https://www.nlgebiedslabel.nl/wp-content/themes/glb/assets/js/components.js?ver=1.0.0

js nlgebiedslabel.nl collected 2026-10-08 04:36:41 UTC 488,978 bytes, 15,224 lines download raw bytes

vendor: 5,872 bytes, lines 1-246
1/*!
2 * imagesLoaded PACKAGED v4.1.4
3 * JavaScript is all like "You images are done yet or what?"
4 * MIT License
5 */
6
7/**
8 * EvEmitter v1.1.0
9 * Lil' event emitter
10 * MIT License
11 */
12
13/* jshint unused: true, undef: true, strict: true */
14
15( function( global, factory ) {
16  // universal module definition
17  /* jshint strict: false */ /* globals define, module, window */
18  if ( typeof define == 'function' && define.amd ) {
19    // AMD - RequireJS
20    define( 'ev-emitter/ev-emitter',factory );
21  } else if ( typeof module == 'object' && module.exports ) {
22    // CommonJS - Browserify, Webpack
23    module.exports = factory();
24  } else {
25    // Browser globals
26    global.EvEmitter = factory();
27  }
28
29}( typeof window != 'undefined' ? window : this, function() {
30
31
32
33function EvEmitter() {}
34
35var proto = EvEmitter.prototype;
36
37proto.on = function( eventName, listener ) {
38  if ( !eventName || !listener ) {
39    return;
40  }
41  // set events hash
42  var events = this._events = this._events || {};
43  // set listeners array
44  var listeners = events[ eventName ] = events[ eventName ] || [];
45  // only add once
46  if ( listeners.indexOf( listener ) == -1 ) {
47    listeners.push( listener );
48  }
49
50  return this;
51};
52
53proto.once = function( eventName, listener ) {
54  if ( !eventName || !listener ) {
55    return;
56  }
57  // add event
58  this.on( eventName, listener );
59  // set once flag
60  // set onceEvents hash
61  var onceEvents = this._onceEvents = this._onceEvents || {};
62  // set onceListeners object
63  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
64  // set flag
65  onceListeners[ listener ] = true;
66
67  return this;
68};
69
70proto.off = function( eventName, listener ) {
71  var listeners = this._events && this._events[ eventName ];
72  if ( !listeners || !listeners.length ) {
73    return;
74  }
75  var index = listeners.indexOf( listener );
76  if ( index != -1 ) {
77    listeners.splice( index, 1 );
78  }
79
80  return this;
81};
82
83proto.emitEvent = function( eventName, args ) {
84  var listeners = this._events && this._events[ eventName ];
85  if ( !listeners || !listeners.length ) {
86    return;
87  }
88  // copy over to avoid interference if .off() in listener
89  listeners = listeners.slice(0);
90  args = args || [];
91  // once stuff
92  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
93
94  for ( var i=0; i < listeners.length; i++ ) {
95    var listener = listeners[i]
96    var isOnce = onceListeners && onceListeners[ listener ];
97    if ( isOnce ) {
98      // remove listener
99      // remove before trigger to prevent recursion
100      this.off( eventName, listener );
101      // unset once flag
102      delete onceListeners[ listener ];
103    }
104    // trigger listener
105    listener.apply( this, args );
106  }
107
108  return this;
109};
110
111proto.allOff = function() {
112  delete this._events;
113  delete this._onceEvents;
114};
115
116return EvEmitter;
117
118}));
119
120/*!
121 * imagesLoaded v4.1.4
122 * JavaScript is all like "You images are done yet or what?"
123 * MIT License
124 */
125
126( function( window, factory ) { 'use strict';
127  // universal module definition
128
129  /*global define: false, module: false, require: false */
130
131  if ( typeof define == 'function' && define.amd ) {
132    // AMD
133    define( [
134      'ev-emitter/ev-emitter'
135    ], function( EvEmitter ) {
136      return factory( window, EvEmitter );
137    });
138  } else if ( typeof module == 'object' && module.exports ) {
139    // CommonJS
140    module.exports = factory(
141      window,
142      require('ev-emitter')
143    );
144  } else {
145    // browser global
146    window.imagesLoaded = factory(
147      window,
148      window.EvEmitter
149    );
150  }
151
152})( typeof window !== 'undefined' ? window : this,
153
154// --------------------------  factory -------------------------- //
155
156function factory( window, EvEmitter ) {
157
158
159
160var $ = window.jQuery;
161var console = window.console;
162
163// -------------------------- helpers -------------------------- //
164
165// extend objects
166function extend( a, b ) {
167  for ( var prop in b ) {
168    a[ prop ] = b[ prop ];
169  }
170  return a;
171}
172
173var arraySlice = Array.prototype.slice;
174
175// turn element or nodeList into an array
176function makeArray( obj ) {
177  if ( Array.isArray( obj ) ) {
178    // use object if already an array
179    return obj;
180  }
181
182  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
183  if ( isArrayLike ) {
184    // convert nodeList to array
185    return arraySlice.call( obj );
186  }
187
188  // array of single index
189  return [ obj ];
190}
191
192// -------------------------- imagesLoaded -------------------------- //
193
194/**
195 * @param {Array, Element, NodeList, String} elem
196 * @param {Object or Function} options - if function, use as callback
197 * @param {Function} onAlways - callback function
198 */
199function ImagesLoaded( elem, options, onAlways ) {
200  // coerce ImagesLoaded() without new, to be new ImagesLoaded()
201  if ( !( this instanceof ImagesLoaded ) ) {
202    return new ImagesLoaded( elem, options, onAlways );
203  }
204  // use elem as selector string
205  var queryElem = elem;
206  if ( typeof elem == 'string' ) {
207    queryElem = document.querySelectorAll( elem );
208  }
209  // bail if bad element
210  if ( !queryElem ) {
211    console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) );
212    return;
213  }
214
215  this.elements = makeArray( queryElem );
216  this.options = extend( {}, this.options );
217  // shift arguments if no options set
218  if ( typeof options == 'function' ) {
219    onAlways = options;
220  } else {
221    extend( this.options, options );
222  }
223
224  if ( onAlways ) {
225    this.on( 'always', onAlways );
226  }
227
228  this.getImages();
229
230  if ( $ ) {
231    // add jQuery Deferred object
232    this.jqDeferred = new $.Deferred();
233  }
234
235  // HACK check async to allow time to bind listeners
236  setTimeout( this.check.bind( this ) );
237}
238
239ImagesLoaded.prototype = Object.create( EvEmitter.prototype );
240
241ImagesLoaded.prototype.options = {};
242
243ImagesLoaded.prototype.getImages = function() {
244  this.images = [];
245
246  // filter & find items if we have an item selector
vendor: 4,347 bytes, lines 247-403
247  this.elements.forEach( this.addElementImages, this );
248};
249
250/**
251 * @param {Node} element
252 */
253ImagesLoaded.prototype.addElementImages = function( elem ) {
254  // filter siblings
255  if ( elem.nodeName == 'IMG' ) {
256    this.addImage( elem );
257  }
258  // get background image on element
259  if ( this.options.background === true ) {
260    this.addElementBackgroundImages( elem );
261  }
262
263  // find children
264  // no non-element nodes, #143
265  var nodeType = elem.nodeType;
266  if ( !nodeType || !elementNodeTypes[ nodeType ] ) {
267    return;
268  }
269  var childImgs = elem.querySelectorAll('img');
270  // concat childElems to filterFound array
271  for ( var i=0; i < childImgs.length; i++ ) {
272    var img = childImgs[i];
273    this.addImage( img );
274  }
275
276  // get child background images
277  if ( typeof this.options.background == 'string' ) {
278    var children = elem.querySelectorAll( this.options.background );
279    for ( i=0; i < children.length; i++ ) {
280      var child = children[i];
281      this.addElementBackgroundImages( child );
282    }
283  }
284};
285
286var elementNodeTypes = {
287  1: true,
288  9: true,
289  11: true
290};
291
292ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
293  var style = getComputedStyle( elem );
294  if ( !style ) {
295    // Firefox returns null if in a hidden iframe https://bugzil.la/548397
296    return;
297  }
298  // get url inside url("...")
299  var reURL = /url\((['"])?(.*?)\1\)/gi;
300  var matches = reURL.exec( style.backgroundImage );
301  while ( matches !== null ) {
302    var url = matches && matches[2];
303    if ( url ) {
304      this.addBackground( url, elem );
305    }
306    matches = reURL.exec( style.backgroundImage );
307  }
308};
309
310/**
311 * @param {Image} img
312 */
313ImagesLoaded.prototype.addImage = function( img ) {
314  var loadingImage = new LoadingImage( img );
315  this.images.push( loadingImage );
316};
317
318ImagesLoaded.prototype.addBackground = function( url, elem ) {
319  var background = new Background( url, elem );
320  this.images.push( background );
321};
322
323ImagesLoaded.prototype.check = function() {
324  var _this = this;
325  this.progressedCount = 0;
326  this.hasAnyBroken = false;
327  // complete if no images
328  if ( !this.images.length ) {
329    this.complete();
330    return;
331  }
332
333  function onProgress( image, elem, message ) {
334    // HACK - Chrome triggers event before object properties have changed. #83
335    setTimeout( function() {
336      _this.progress( image, elem, message );
337    });
338  }
339
340  this.images.forEach( function( loadingImage ) {
341    loadingImage.once( 'progress', onProgress );
342    loadingImage.check();
343  });
344};
345
346ImagesLoaded.prototype.progress = function( image, elem, message ) {
347  this.progressedCount++;
348  this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
349  // progress event
350  this.emitEvent( 'progress', [ this, image, elem ] );
351  if ( this.jqDeferred && this.jqDeferred.notify ) {
352    this.jqDeferred.notify( this, image );
353  }
354  // check if completed
355  if ( this.progressedCount == this.images.length ) {
356    this.complete();
357  }
358
359  if ( this.options.debug && console ) {
360    console.log( 'progress: ' + message, image, elem );
361  }
362};
363
364ImagesLoaded.prototype.complete = function() {
365  var eventName = this.hasAnyBroken ? 'fail' : 'done';
366  this.isComplete = true;
367  this.emitEvent( eventName, [ this ] );
368  this.emitEvent( 'always', [ this ] );
369  if ( this.jqDeferred ) {
370    var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
371    this.jqDeferred[ jqMethod ]( this );
372  }
373};
374
375// --------------------------  -------------------------- //
376
377function LoadingImage( img ) {
378  this.img = img;
379}
380
381LoadingImage.prototype = Object.create( EvEmitter.prototype );
382
383LoadingImage.prototype.check = function() {
384  // If complete is true and browser supports natural sizes,
385  // try to check for image status manually.
386  var isComplete = this.getIsImageComplete();
387  if ( isComplete ) {
388    // report based on naturalWidth
389    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
390    return;
391  }
392
393  // If none of the checks above matched, simulate loading on detached element.
394  this.proxyImage = new Image();
395  this.proxyImage.addEventListener( 'load', this );
396  this.proxyImage.addEventListener( 'error', this );
397  // bind to image as well for Firefox. #191
398  this.img.addEventListener( 'load', this );
399  this.img.addEventListener( 'error', this );
400  this.proxyImage.src = this.img.src;
401};
402
403LoadingImage.prototype.getIsImageComplete = function() {
vendor: 2,759 bytes, lines 404-506
404  // check for non-zero, non-undefined naturalWidth
405  // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671
406  return this.img.complete && this.img.naturalWidth;
407};
408
409LoadingImage.prototype.confirm = function( isLoaded, message ) {
410  this.isLoaded = isLoaded;
411  this.emitEvent( 'progress', [ this, this.img, message ] );
412};
413
414// ----- events ----- //
415
416// trigger specified handler for event type
417LoadingImage.prototype.handleEvent = function( event ) {
418  var method = 'on' + event.type;
419  if ( this[ method ] ) {
420    this[ method ]( event );
421  }
422};
423
424LoadingImage.prototype.onload = function() {
425  this.confirm( true, 'onload' );
426  this.unbindEvents();
427};
428
429LoadingImage.prototype.onerror = function() {
430  this.confirm( false, 'onerror' );
431  this.unbindEvents();
432};
433
434LoadingImage.prototype.unbindEvents = function() {
435  this.proxyImage.removeEventListener( 'load', this );
436  this.proxyImage.removeEventListener( 'error', this );
437  this.img.removeEventListener( 'load', this );
438  this.img.removeEventListener( 'error', this );
439};
440
441// -------------------------- Background -------------------------- //
442
443function Background( url, element ) {
444  this.url = url;
445  this.element = element;
446  this.img = new Image();
447}
448
449// inherit LoadingImage prototype
450Background.prototype = Object.create( LoadingImage.prototype );
451
452Background.prototype.check = function() {
453  this.img.addEventListener( 'load', this );
454  this.img.addEventListener( 'error', this );
455  this.img.src = this.url;
456  // check if image is already complete
457  var isComplete = this.getIsImageComplete();
458  if ( isComplete ) {
459    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
460    this.unbindEvents();
461  }
462};
463
464Background.prototype.unbindEvents = function() {
465  this.img.removeEventListener( 'load', this );
466  this.img.removeEventListener( 'error', this );
467};
468
469Background.prototype.confirm = function( isLoaded, message ) {
470  this.isLoaded = isLoaded;
471  this.emitEvent( 'progress', [ this, this.element, message ] );
472};
473
474// -------------------------- jQuery -------------------------- //
475
476ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
477  jQuery = jQuery || window.jQuery;
478  if ( !jQuery ) {
479    return;
480  }
481  // set local variable
482  $ = jQuery;
483  // $().imagesLoaded()
484  $.fn.imagesLoaded = function( options, callback ) {
485    var instance = new ImagesLoaded( this, options, callback );
486    return instance.jqDeferred.promise( $(this) );
487  };
488};
489// try making plugin
490ImagesLoaded.makeJQueryPlugin();
491
492// --------------------------  -------------------------- //
493
494return ImagesLoaded;
495
496});
497
498
499/*!
500 * Isotope PACKAGED v3.0.6
501 *
502 * Licensed GPLv3 for open source use
503 * or Isotope Commercial License for commercial use
504 *
505 * https://isotope.metafizzy.co
506 * Copyright 2010-2018 Metafizzy
vendor: 39,423 bytes, lines 506-2068
506
507 */
508
509/**
510 * Bridget makes jQuery widgets
511 * v2.0.1
512 * MIT license
513 */
514
515/* jshint browser: true, strict: true, undef: true, unused: true */
516
517( function( window, factory ) {
518  // universal module definition
519  /*jshint strict: false */ /* globals define, module, require */
520  if ( typeof define == 'function' && define.amd ) {
521    // AMD
522    define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
523      return factory( window, jQuery );
524    });
525  } else if ( typeof module == 'object' && module.exports ) {
526    // CommonJS
527    module.exports = factory(
528      window,
529      require('jquery')
530    );
531  } else {
532    // browser global
533    window.jQueryBridget = factory(
534      window,
535      window.jQuery
536    );
537  }
538
539}( window, function factory( window, jQuery ) {
540'use strict';
541
542// ----- utils ----- //
543
544var arraySlice = Array.prototype.slice;
545
546// helper function for logging errors
547// $.error breaks jQuery chaining
548var console = window.console;
549var logError = typeof console == 'undefined' ? function() {} :
550  function( message ) {
551    console.error( message );
552  };
553
554// ----- jQueryBridget ----- //
555
556function jQueryBridget( namespace, PluginClass, $ ) {
557  $ = $ || jQuery || window.jQuery;
558  if ( !$ ) {
559    return;
560  }
561
562  // add option method -> $().plugin('option', {...})
563  if ( !PluginClass.prototype.option ) {
564    // option setter
565    PluginClass.prototype.option = function( opts ) {
566      // bail out if not an object
567      if ( !$.isPlainObject( opts ) ){
568        return;
569      }
570      this.options = $.extend( true, this.options, opts );
571    };
572  }
573
574  // make jQuery plugin
575  $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
576    if ( typeof arg0 == 'string' ) {
577      // method call $().plugin( 'methodName', { options } )
578      // shift arguments by 1
579      var args = arraySlice.call( arguments, 1 );
580      return methodCall( this, arg0, args );
581    }
582    // just $().plugin({ options })
583    plainCall( this, arg0 );
584    return this;
585  };
586
587  // $().plugin('methodName')
588  function methodCall( $elems, methodName, args ) {
589    var returnValue;
590    var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
591
592    $elems.each( function( i, elem ) {
593      // get instance
594      var instance = $.data( elem, namespace );
595      if ( !instance ) {
596        logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
597          pluginMethodStr );
598        return;
599      }
600
601      var method = instance[ methodName ];
602      if ( !method || methodName.charAt(0) == '_' ) {
603        logError( pluginMethodStr + ' is not a valid method' );
604        return;
605      }
606
607      // apply method, get return value
608      var value = method.apply( instance, args );
609      // set return value if value is returned, use only first value
610      returnValue = returnValue === undefined ? value : returnValue;
611    });
612
613    return returnValue !== undefined ? returnValue : $elems;
614  }
615
616  function plainCall( $elems, options ) {
617    $elems.each( function( i, elem ) {
618      var instance = $.data( elem, namespace );
619      if ( instance ) {
620        // set options & init
621        instance.option( options );
622        instance._init();
623      } else {
624        // initialize new instance
625        instance = new PluginClass( elem, options );
626        $.data( elem, namespace, instance );
627      }
628    });
629  }
630
631  updateJQuery( $ );
632
633}
634
635// ----- updateJQuery ----- //
636
637// set $.bridget for v1 backwards compatibility
638function updateJQuery( $ ) {
639  if ( !$ || ( $ && $.bridget ) ) {
640    return;
641  }
642  $.bridget = jQueryBridget;
643}
644
645updateJQuery( jQuery || window.jQuery );
646
647// -----  ----- //
648
649return jQueryBridget;
650
651}));
652
653/**
654 * EvEmitter v1.1.0
655 * Lil' event emitter
656 * MIT License
657 */
658
659/* jshint unused: true, undef: true, strict: true */
660
661( function( global, factory ) {
662  // universal module definition
663  /* jshint strict: false */ /* globals define, module, window */
664  if ( typeof define == 'function' && define.amd ) {
665    // AMD - RequireJS
666    define( 'ev-emitter/ev-emitter',factory );
667  } else if ( typeof module == 'object' && module.exports ) {
668    // CommonJS - Browserify, Webpack
669    module.exports = factory();
670  } else {
671    // Browser globals
672    global.EvEmitter = factory();
673  }
674
675}( typeof window != 'undefined' ? window : this, function() {
676
677
678
679function EvEmitter() {}
680
681var proto = EvEmitter.prototype;
682
683proto.on = function( eventName, listener ) {
684  if ( !eventName || !listener ) {
685    return;
686  }
687  // set events hash
688  var events = this._events = this._events || {};
689  // set listeners array
690  var listeners = events[ eventName ] = events[ eventName ] || [];
691  // only add once
692  if ( listeners.indexOf( listener ) == -1 ) {
693    listeners.push( listener );
694  }
695
696  return this;
697};
698
699proto.once = function( eventName, listener ) {
700  if ( !eventName || !listener ) {
701    return;
702  }
703  // add event
704  this.on( eventName, listener );
705  // set once flag
706  // set onceEvents hash
707  var onceEvents = this._onceEvents = this._onceEvents || {};
708  // set onceListeners object
709  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
710  // set flag
711  onceListeners[ listener ] = true;
712
713  return this;
714};
715
716proto.off = function( eventName, listener ) {
717  var listeners = this._events && this._events[ eventName ];
718  if ( !listeners || !listeners.length ) {
719    return;
720  }
721  var index = listeners.indexOf( listener );
722  if ( index != -1 ) {
723    listeners.splice( index, 1 );
724  }
725
726  return this;
727};
728
729proto.emitEvent = function( eventName, args ) {
730  var listeners = this._events && this._events[ eventName ];
731  if ( !listeners || !listeners.length ) {
732    return;
733  }
734  // copy over to avoid interference if .off() in listener
735  listeners = listeners.slice(0);
736  args = args || [];
737  // once stuff
738  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
739
740  for ( var i=0; i < listeners.length; i++ ) {
741    var listener = listeners[i]
742    var isOnce = onceListeners && onceListeners[ listener ];
743    if ( isOnce ) {
744      // remove listener
745      // remove before trigger to prevent recursion
746      this.off( eventName, listener );
747      // unset once flag
748      delete onceListeners[ listener ];
749    }
750    // trigger listener
751    listener.apply( this, args );
752  }
753
754  return this;
755};
756
757proto.allOff = function() {
758  delete this._events;
759  delete this._onceEvents;
760};
761
762return EvEmitter;
763
764}));
765
766/*!
767 * getSize v2.0.3
768 * measure size of elements
769 * MIT license
770 */
771
772/* jshint browser: true, strict: true, undef: true, unused: true */
773/* globals console: false */
774
775( function( window, factory ) {
776  /* jshint strict: false */ /* globals define, module */
777  if ( typeof define == 'function' && define.amd ) {
778    // AMD
779    define( 'get-size/get-size',factory );
780  } else if ( typeof module == 'object' && module.exports ) {
781    // CommonJS
782    module.exports = factory();
783  } else {
784    // browser global
785    window.getSize = factory();
786  }
787
788})( window, function factory() {
789'use strict';
790
791// -------------------------- helpers -------------------------- //
792
793// get a number from a string, not a percentage
794function getStyleSize( value ) {
795  var num = parseFloat( value );
796  // not a percent like '100%', and a number
797  var isValid = value.indexOf('%') == -1 && !isNaN( num );
798  return isValid && num;
799}
800
801function noop() {}
802
803var logError = typeof console == 'undefined' ? noop :
804  function( message ) {
805    console.error( message );
806  };
807
808// -------------------------- measurements -------------------------- //
809
810var measurements = [
811  'paddingLeft',
812  'paddingRight',
813  'paddingTop',
814  'paddingBottom',
815  'marginLeft',
816  'marginRight',
817  'marginTop',
818  'marginBottom',
819  'borderLeftWidth',
820  'borderRightWidth',
821  'borderTopWidth',
822  'borderBottomWidth'
823];
824
825var measurementsLength = measurements.length;
826
827function getZeroSize() {
828  var size = {
829    width: 0,
830    height: 0,
831    innerWidth: 0,
832    innerHeight: 0,
833    outerWidth: 0,
834    outerHeight: 0
835  };
836  for ( var i=0; i < measurementsLength; i++ ) {
837    var measurement = measurements[i];
838    size[ measurement ] = 0;
839  }
840  return size;
841}
842
843// -------------------------- getStyle -------------------------- //
844
845/**
846 * getStyle, get style of element, check for Firefox bug
847 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
848 */
849function getStyle( elem ) {
850  var style = getComputedStyle( elem );
851  if ( !style ) {
852    logError( 'Style returned ' + style +
853      '. Are you running this code in a hidden iframe on Firefox? ' +
854      'See https://bit.ly/getsizebug1' );
855  }
856  return style;
857}
858
859// -------------------------- setup -------------------------- //
860
861var isSetup = false;
862
863var isBoxSizeOuter;
864
865/**
866 * setup
867 * check isBoxSizerOuter
868 * do on first getSize() rather than on page load for Firefox bug
869 */
870function setup() {
871  // setup once
872  if ( isSetup ) {
873    return;
874  }
875  isSetup = true;
876
877  // -------------------------- box sizing -------------------------- //
878
879  /**
880   * Chrome & Safari measure the outer-width on style.width on border-box elems
881   * IE11 & Firefox<29 measures the inner-width
882   */
883  var div = document.createElement('div');
884  div.style.width = '200px';
885  div.style.padding = '1px 2px 3px 4px';
886  div.style.borderStyle = 'solid';
887  div.style.borderWidth = '1px 2px 3px 4px';
888  div.style.boxSizing = 'border-box';
889
890  var body = document.body || document.documentElement;
891  body.appendChild( div );
892  var style = getStyle( div );
893  // round value for browser zoom. desandro/masonry#928
894  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
895  getSize.isBoxSizeOuter = isBoxSizeOuter;
896
897  body.removeChild( div );
898}
899
900// -------------------------- getSize -------------------------- //
901
902function getSize( elem ) {
903  setup();
904
905  // use querySeletor if elem is string
906  if ( typeof elem == 'string' ) {
907    elem = document.querySelector( elem );
908  }
909
910  // do not proceed on non-objects
911  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
912    return;
913  }
914
915  var style = getStyle( elem );
916
917  // if hidden, everything is 0
918  if ( style.display == 'none' ) {
919    return getZeroSize();
920  }
921
922  var size = {};
923  size.width = elem.offsetWidth;
924  size.height = elem.offsetHeight;
925
926  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
927
928  // get all measurements
929  for ( var i=0; i < measurementsLength; i++ ) {
930    var measurement = measurements[i];
931    var value = style[ measurement ];
932    var num = parseFloat( value );
933    // any 'auto', 'medium' value will be 0
934    size[ measurement ] = !isNaN( num ) ? num : 0;
935  }
936
937  var paddingWidth = size.paddingLeft + size.paddingRight;
938  var paddingHeight = size.paddingTop + size.paddingBottom;
939  var marginWidth = size.marginLeft + size.marginRight;
940  var marginHeight = size.marginTop + size.marginBottom;
941  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
942  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
943
944  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
945
946  // overwrite width and height if we can get it from style
947  var styleWidth = getStyleSize( style.width );
948  if ( styleWidth !== false ) {
949    size.width = styleWidth +
950      // add padding and border unless it's already including it
951      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
952  }
953
954  var styleHeight = getStyleSize( style.height );
955  if ( styleHeight !== false ) {
956    size.height = styleHeight +
957      // add padding and border unless it's already including it
958      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
959  }
960
961  size.innerWidth = size.width - ( paddingWidth + borderWidth );
962  size.innerHeight = size.height - ( paddingHeight + borderHeight );
963
964  size.outerWidth = size.width + marginWidth;
965  size.outerHeight = size.height + marginHeight;
966
967  return size;
968}
969
970return getSize;
971
972});
973
974/**
975 * matchesSelector v2.0.2
976 * matchesSelector( element, '.selector' )
977 * MIT license
978 */
979
980/*jshint browser: true, strict: true, undef: true, unused: true */
981
982( function( window, factory ) {
983  /*global define: false, module: false */
984  'use strict';
985  // universal module definition
986  if ( typeof define == 'function' && define.amd ) {
987    // AMD
988    define( 'desandro-matches-selector/matches-selector',factory );
989  } else if ( typeof module == 'object' && module.exports ) {
990    // CommonJS
991    module.exports = factory();
992  } else {
993    // browser global
994    window.matchesSelector = factory();
995  }
996
997}( window, function factory() {
998  'use strict';
999
1000  var matchesMethod = ( function() {
1001    var ElemProto = window.Element.prototype;
1002    // check for the standard method name first
1003    if ( ElemProto.matches ) {
1004      return 'matches';
1005    }
1006    // check un-prefixed
1007    if ( ElemProto.matchesSelector ) {
1008      return 'matchesSelector';
1009    }
1010    // check vendor prefixes
1011    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1012
1013    for ( var i=0; i < prefixes.length; i++ ) {
1014      var prefix = prefixes[i];
1015      var method = prefix + 'MatchesSelector';
1016      if ( ElemProto[ method ] ) {
1017        return method;
1018      }
1019    }
1020  })();
1021
1022  return function matchesSelector( elem, selector ) {
1023    return elem[ matchesMethod ]( selector );
1024  };
1025
1026}));
1027
1028/**
1029 * Fizzy UI utils v2.0.7
1030 * MIT license
1031 */
1032
1033/*jshint browser: true, undef: true, unused: true, strict: true */
1034
1035( function( window, factory ) {
1036  // universal module definition
1037  /*jshint strict: false */ /*globals define, module, require */
1038
1039  if ( typeof define == 'function' && define.amd ) {
1040    // AMD
1041    define( 'fizzy-ui-utils/utils',[
1042      'desandro-matches-selector/matches-selector'
1043    ], function( matchesSelector ) {
1044      return factory( window, matchesSelector );
1045    });
1046  } else if ( typeof module == 'object' && module.exports ) {
1047    // CommonJS
1048    module.exports = factory(
1049      window,
1050      require('desandro-matches-selector')
1051    );
1052  } else {
1053    // browser global
1054    window.fizzyUIUtils = factory(
1055      window,
1056      window.matchesSelector
1057    );
1058  }
1059
1060}( window, function factory( window, matchesSelector ) {
1061
1062
1063
1064var utils = {};
1065
1066// ----- extend ----- //
1067
1068// extends objects
1069utils.extend = function( a, b ) {
1070  for ( var prop in b ) {
1071    a[ prop ] = b[ prop ];
1072  }
1073  return a;
1074};
1075
1076// ----- modulo ----- //
1077
1078utils.modulo = function( num, div ) {
1079  return ( ( num % div ) + div ) % div;
1080};
1081
1082// ----- makeArray ----- //
1083
1084var arraySlice = Array.prototype.slice;
1085
1086// turn element or nodeList into an array
1087utils.makeArray = function( obj ) {
1088  if ( Array.isArray( obj ) ) {
1089    // use object if already an array
1090    return obj;
1091  }
1092  // return empty array if undefined or null. #6
1093  if ( obj === null || obj === undefined ) {
1094    return [];
1095  }
1096
1097  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
1098  if ( isArrayLike ) {
1099    // convert nodeList to array
1100    return arraySlice.call( obj );
1101  }
1102
1103  // array of single index
1104  return [ obj ];
1105};
1106
1107// ----- removeFrom ----- //
1108
1109utils.removeFrom = function( ary, obj ) {
1110  var index = ary.indexOf( obj );
1111  if ( index != -1 ) {
1112    ary.splice( index, 1 );
1113  }
1114};
1115
1116// ----- getParent ----- //
1117
1118utils.getParent = function( elem, selector ) {
1119  while ( elem.parentNode && elem != document.body ) {
1120    elem = elem.parentNode;
1121    if ( matchesSelector( elem, selector ) ) {
1122      return elem;
1123    }
1124  }
1125};
1126
1127// ----- getQueryElement ----- //
1128
1129// use element as selector string
1130utils.getQueryElement = function( elem ) {
1131  if ( typeof elem == 'string' ) {
1132    return document.querySelector( elem );
1133  }
1134  return elem;
1135};
1136
1137// ----- handleEvent ----- //
1138
1139// enable .ontype to trigger from .addEventListener( elem, 'type' )
1140utils.handleEvent = function( event ) {
1141  var method = 'on' + event.type;
1142  if ( this[ method ] ) {
1143    this[ method ]( event );
1144  }
1145};
1146
1147// ----- filterFindElements ----- //
1148
1149utils.filterFindElements = function( elems, selector ) {
1150  // make array of elems
1151  elems = utils.makeArray( elems );
1152  var ffElems = [];
1153
1154  elems.forEach( function( elem ) {
1155    // check that elem is an actual element
1156    if ( !( elem instanceof HTMLElement ) ) {
1157      return;
1158    }
1159    // add elem if no selector
1160    if ( !selector ) {
1161      ffElems.push( elem );
1162      return;
1163    }
1164    // filter & find items if we have a selector
1165    // filter
1166    if ( matchesSelector( elem, selector ) ) {
1167      ffElems.push( elem );
1168    }
1169    // find children
1170    var childElems = elem.querySelectorAll( selector );
1171    // concat childElems to filterFound array
1172    for ( var i=0; i < childElems.length; i++ ) {
1173      ffElems.push( childElems[i] );
1174    }
1175  });
1176
1177  return ffElems;
1178};
1179
1180// ----- debounceMethod ----- //
1181
1182utils.debounceMethod = function( _class, methodName, threshold ) {
1183  threshold = threshold || 100;
1184  // original method
1185  var method = _class.prototype[ methodName ];
1186  var timeoutName = methodName + 'Timeout';
1187
1188  _class.prototype[ methodName ] = function() {
1189    var timeout = this[ timeoutName ];
1190    clearTimeout( timeout );
1191
1192    var args = arguments;
1193    var _this = this;
1194    this[ timeoutName ] = setTimeout( function() {
1195      method.apply( _this, args );
1196      delete _this[ timeoutName ];
1197    }, threshold );
1198  };
1199};
1200
1201// ----- docReady ----- //
1202
1203utils.docReady = function( callback ) {
1204  var readyState = document.readyState;
1205  if ( readyState == 'complete' || readyState == 'interactive' ) {
1206    // do async to allow for other scripts to run. metafizzy/flickity#441
1207    setTimeout( callback );
1208  } else {
1209    document.addEventListener( 'DOMContentLoaded', callback );
1210  }
1211};
1212
1213// ----- htmlInit ----- //
1214
1215// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1216utils.toDashed = function( str ) {
1217  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1218    return $1 + '-' + $2;
1219  }).toLowerCase();
1220};
1221
1222var console = window.console;
1223/**
1224 * allow user to initialize classes via [data-namespace] or .js-namespace class
1225 * htmlInit( Widget, 'widgetName' )
1226 * options are parsed from data-namespace-options
1227 */
1228utils.htmlInit = function( WidgetClass, namespace ) {
1229  utils.docReady( function() {
1230    var dashedNamespace = utils.toDashed( namespace );
1231    var dataAttr = 'data-' + dashedNamespace;
1232    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
1233    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
1234    var elems = utils.makeArray( dataAttrElems )
1235      .concat( utils.makeArray( jsDashElems ) );
1236    var dataOptionsAttr = dataAttr + '-options';
1237    var jQuery = window.jQuery;
1238
1239    elems.forEach( function( elem ) {
1240      var attr = elem.getAttribute( dataAttr ) ||
1241        elem.getAttribute( dataOptionsAttr );
1242      var options;
1243      try {
1244        options = attr && JSON.parse( attr );
1245      } catch ( error ) {
1246        // log error, do not initialize
1247        if ( console ) {
1248          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
1249          ': ' + error );
1250        }
1251        return;
1252      }
1253      // initialize
1254      var instance = new WidgetClass( elem, options );
1255      // make available via $().data('namespace')
1256      if ( jQuery ) {
1257        jQuery.data( elem, namespace, instance );
1258      }
1259    });
1260
1261  });
1262};
1263
1264// -----  ----- //
1265
1266return utils;
1267
1268}));
1269
1270/**
1271 * Outlayer Item
1272 */
1273
1274( function( window, factory ) {
1275  // universal module definition
1276  /* jshint strict: false */ /* globals define, module, require */
1277  if ( typeof define == 'function' && define.amd ) {
1278    // AMD - RequireJS
1279    define( 'outlayer/item',[
1280        'ev-emitter/ev-emitter',
1281        'get-size/get-size'
1282      ],
1283      factory
1284    );
1285  } else if ( typeof module == 'object' && module.exports ) {
1286    // CommonJS - Browserify, Webpack
1287    module.exports = factory(
1288      require('ev-emitter'),
1289      require('get-size')
1290    );
1291  } else {
1292    // browser global
1293    window.Outlayer = {};
1294    window.Outlayer.Item = factory(
1295      window.EvEmitter,
1296      window.getSize
1297    );
1298  }
1299
1300}( window, function factory( EvEmitter, getSize ) {
1301'use strict';
1302
1303// ----- helpers ----- //
1304
1305function isEmptyObj( obj ) {
1306  for ( var prop in obj ) {
1307    return false;
1308  }
1309  prop = null;
1310  return true;
1311}
1312
1313// -------------------------- CSS3 support -------------------------- //
1314
1315
1316var docElemStyle = document.documentElement.style;
1317
1318var transitionProperty = typeof docElemStyle.transition == 'string' ?
1319  'transition' : 'WebkitTransition';
1320var transformProperty = typeof docElemStyle.transform == 'string' ?
1321  'transform' : 'WebkitTransform';
1322
1323var transitionEndEvent = {
1324  WebkitTransition: 'webkitTransitionEnd',
1325  transition: 'transitionend'
1326}[ transitionProperty ];
1327
1328// cache all vendor properties that could have vendor prefix
1329var vendorProperties = {
1330  transform: transformProperty,
1331  transition: transitionProperty,
1332  transitionDuration: transitionProperty + 'Duration',
1333  transitionProperty: transitionProperty + 'Property',
1334  transitionDelay: transitionProperty + 'Delay'
1335};
1336
1337// -------------------------- Item -------------------------- //
1338
1339function Item( element, layout ) {
1340  if ( !element ) {
1341    return;
1342  }
1343
1344  this.element = element;
1345  // parent layout class, i.e. Masonry, Isotope, or Packery
1346  this.layout = layout;
1347  this.position = {
1348    x: 0,
1349    y: 0
1350  };
1351
1352  this._create();
1353}
1354
1355// inherit EvEmitter
1356var proto = Item.prototype = Object.create( EvEmitter.prototype );
1357proto.constructor = Item;
1358
1359proto._create = function() {
1360  // transition objects
1361  this._transn = {
1362    ingProperties: {},
1363    clean: {},
1364    onEnd: {}
1365  };
1366
1367  this.css({
1368    position: 'absolute'
1369  });
1370};
1371
1372// trigger specified handler for event type
1373proto.handleEvent = function( event ) {
1374  var method = 'on' + event.type;
1375  if ( this[ method ] ) {
1376    this[ method ]( event );
1377  }
1378};
1379
1380proto.getSize = function() {
1381  this.size = getSize( this.element );
1382};
1383
1384/**
1385 * apply CSS styles to element
1386 * @param {Object} style
1387 */
1388proto.css = function( style ) {
1389  var elemStyle = this.element.style;
1390
1391  for ( var prop in style ) {
1392    // use vendor property if available
1393    var supportedProp = vendorProperties[ prop ] || prop;
1394    elemStyle[ supportedProp ] = style[ prop ];
1395  }
1396};
1397
1398 // measure position, and sets it
1399proto.getPosition = function() {
1400  var style = getComputedStyle( this.element );
1401  var isOriginLeft = this.layout._getOption('originLeft');
1402  var isOriginTop = this.layout._getOption('originTop');
1403  var xValue = style[ isOriginLeft ? 'left' : 'right' ];
1404  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
1405  var x = parseFloat( xValue );
1406  var y = parseFloat( yValue );
1407  // convert percent to pixels
1408  var layoutSize = this.layout.size;
1409  if ( xValue.indexOf('%') != -1 ) {
1410    x = ( x / 100 ) * layoutSize.width;
1411  }
1412  if ( yValue.indexOf('%') != -1 ) {
1413    y = ( y / 100 ) * layoutSize.height;
1414  }
1415  // clean up 'auto' or other non-integer values
1416  x = isNaN( x ) ? 0 : x;
1417  y = isNaN( y ) ? 0 : y;
1418  // remove padding from measurement
1419  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1420  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1421
1422  this.position.x = x;
1423  this.position.y = y;
1424};
1425
1426// set settled position, apply padding
1427proto.layoutPosition = function() {
1428  var layoutSize = this.layout.size;
1429  var style = {};
1430  var isOriginLeft = this.layout._getOption('originLeft');
1431  var isOriginTop = this.layout._getOption('originTop');
1432
1433  // x
1434  var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
1435  var xProperty = isOriginLeft ? 'left' : 'right';
1436  var xResetProperty = isOriginLeft ? 'right' : 'left';
1437
1438  var x = this.position.x + layoutSize[ xPadding ];
1439  // set in percentage or pixels
1440  style[ xProperty ] = this.getXValue( x );
1441  // reset other property
1442  style[ xResetProperty ] = '';
1443
1444  // y
1445  var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
1446  var yProperty = isOriginTop ? 'top' : 'bottom';
1447  var yResetProperty = isOriginTop ? 'bottom' : 'top';
1448
1449  var y = this.position.y + layoutSize[ yPadding ];
1450  // set in percentage or pixels
1451  style[ yProperty ] = this.getYValue( y );
1452  // reset other property
1453  style[ yResetProperty ] = '';
1454
1455  this.css( style );
1456  this.emitEvent( 'layout', [ this ] );
1457};
1458
1459proto.getXValue = function( x ) {
1460  var isHorizontal = this.layout._getOption('horizontal');
1461  return this.layout.options.percentPosition && !isHorizontal ?
1462    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
1463};
1464
1465proto.getYValue = function( y ) {
1466  var isHorizontal = this.layout._getOption('horizontal');
1467  return this.layout.options.percentPosition && isHorizontal ?
1468    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
1469};
1470
1471proto._transitionTo = function( x, y ) {
1472  this.getPosition();
1473  // get current x & y from top/left
1474  var curX = this.position.x;
1475  var curY = this.position.y;
1476
1477  var didNotMove = x == this.position.x && y == this.position.y;
1478
1479  // save end position
1480  this.setPosition( x, y );
1481
1482  // if did not move and not transitioning, just go to layout
1483  if ( didNotMove && !this.isTransitioning ) {
1484    this.layoutPosition();
1485    return;
1486  }
1487
1488  var transX = x - curX;
1489  var transY = y - curY;
1490  var transitionStyle = {};
1491  transitionStyle.transform = this.getTranslate( transX, transY );
1492
1493  this.transition({
1494    to: transitionStyle,
1495    onTransitionEnd: {
1496      transform: this.layoutPosition
1497    },
1498    isCleaning: true
1499  });
1500};
1501
1502proto.getTranslate = function( x, y ) {
1503  // flip cooridinates if origin on right or bottom
1504  var isOriginLeft = this.layout._getOption('originLeft');
1505  var isOriginTop = this.layout._getOption('originTop');
1506  x = isOriginLeft ? x : -x;
1507  y = isOriginTop ? y : -y;
1508  return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1509};
1510
1511// non transition + transform support
1512proto.goTo = function( x, y ) {
1513  this.setPosition( x, y );
1514  this.layoutPosition();
1515};
1516
1517proto.moveTo = proto._transitionTo;
1518
1519proto.setPosition = function( x, y ) {
1520  this.position.x = parseFloat( x );
1521  this.position.y = parseFloat( y );
1522};
1523
1524// ----- transition ----- //
1525
1526/**
1527 * @param {Object} style - CSS
1528 * @param {Function} onTransitionEnd
1529 */
1530
1531// non transition, just trigger callback
1532proto._nonTransition = function( args ) {
1533  this.css( args.to );
1534  if ( args.isCleaning ) {
1535    this._removeStyles( args.to );
1536  }
1537  for ( var prop in args.onTransitionEnd ) {
1538    args.onTransitionEnd[ prop ].call( this );
1539  }
1540};
1541
1542/**
1543 * proper transition
1544 * @param {Object} args - arguments
1545 *   @param {Object} to - style to transition to
1546 *   @param {Object} from - style to start transition from
1547 *   @param {Boolean} isCleaning - removes transition styles after transition
1548 *   @param {Function} onTransitionEnd - callback
1549 */
1550proto.transition = function( args ) {
1551  // redirect to nonTransition if no transition duration
1552  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1553    this._nonTransition( args );
1554    return;
1555  }
1556
1557  var _transition = this._transn;
1558  // keep track of onTransitionEnd callback by css property
1559  for ( var prop in args.onTransitionEnd ) {
1560    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1561  }
1562  // keep track of properties that are transitioning
1563  for ( prop in args.to ) {
1564    _transition.ingProperties[ prop ] = true;
1565    // keep track of properties to clean up when transition is done
1566    if ( args.isCleaning ) {
1567      _transition.clean[ prop ] = true;
1568    }
1569  }
1570
1571  // set from styles
1572  if ( args.from ) {
1573    this.css( args.from );
1574    // force redraw. http://blog.alexmaccaw.com/css-transitions
1575    var h = this.element.offsetHeight;
1576    // hack for JSHint to hush about unused var
1577    h = null;
1578  }
1579  // enable transition
1580  this.enableTransition( args.to );
1581  // set styles that are transitioning
1582  this.css( args.to );
1583
1584  this.isTransitioning = true;
1585
1586};
1587
1588// dash before all cap letters, including first for
1589// WebkitTransform => -webkit-transform
1590function toDashedAll( str ) {
1591  return str.replace( /([A-Z])/g, function( $1 ) {
1592    return '-' + $1.toLowerCase();
1593  });
1594}
1595
1596var transitionProps = 'opacity,' + toDashedAll( transformProperty );
1597
1598proto.enableTransition = function(/* style */) {
1599  // HACK changing transitionProperty during a transition
1600  // will cause transition to jump
1601  if ( this.isTransitioning ) {
1602    return;
1603  }
1604
1605  // make `transition: foo, bar, baz` from style object
1606  // HACK un-comment this when enableTransition can work
1607  // while a transition is happening
1608  // var transitionValues = [];
1609  // for ( var prop in style ) {
1610  //   // dash-ify camelCased properties like WebkitTransition
1611  //   prop = vendorProperties[ prop ] || prop;
1612  //   transitionValues.push( toDashedAll( prop ) );
1613  // }
1614  // munge number to millisecond, to match stagger
1615  var duration = this.layout.options.transitionDuration;
1616  duration = typeof duration == 'number' ? duration + 'ms' : duration;
1617  // enable transition styles
1618  this.css({
1619    transitionProperty: transitionProps,
1620    transitionDuration: duration,
1621    transitionDelay: this.staggerDelay || 0
1622  });
1623  // listen for transition end event
1624  this.element.addEventListener( transitionEndEvent, this, false );
1625};
1626
1627// ----- events ----- //
1628
1629proto.onwebkitTransitionEnd = function( event ) {
1630  this.ontransitionend( event );
1631};
1632
1633proto.onotransitionend = function( event ) {
1634  this.ontransitionend( event );
1635};
1636
1637// properties that I munge to make my life easier
1638var dashedVendorProperties = {
1639  '-webkit-transform': 'transform'
1640};
1641
1642proto.ontransitionend = function( event ) {
1643  // disregard bubbled events from children
1644  if ( event.target !== this.element ) {
1645    return;
1646  }
1647  var _transition = this._transn;
1648  // get property name of transitioned property, convert to prefix-free
1649  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1650
1651  // remove property that has completed transitioning
1652  delete _transition.ingProperties[ propertyName ];
1653  // check if any properties are still transitioning
1654  if ( isEmptyObj( _transition.ingProperties ) ) {
1655    // all properties have completed transitioning
1656    this.disableTransition();
1657  }
1658  // clean style
1659  if ( propertyName in _transition.clean ) {
1660    // clean up style
1661    this.element.style[ event.propertyName ] = '';
1662    delete _transition.clean[ propertyName ];
1663  }
1664  // trigger onTransitionEnd callback
1665  if ( propertyName in _transition.onEnd ) {
1666    var onTransitionEnd = _transition.onEnd[ propertyName ];
1667    onTransitionEnd.call( this );
1668    delete _transition.onEnd[ propertyName ];
1669  }
1670
1671  this.emitEvent( 'transitionEnd', [ this ] );
1672};
1673
1674proto.disableTransition = function() {
1675  this.removeTransitionStyles();
1676  this.element.removeEventListener( transitionEndEvent, this, false );
1677  this.isTransitioning = false;
1678};
1679
1680/**
1681 * removes style property from element
1682 * @param {Object} style
1683**/
1684proto._removeStyles = function( style ) {
1685  // clean up transition styles
1686  var cleanStyle = {};
1687  for ( var prop in style ) {
1688    cleanStyle[ prop ] = '';
1689  }
1690  this.css( cleanStyle );
1691};
1692
1693var cleanTransitionStyle = {
1694  transitionProperty: '',
1695  transitionDuration: '',
1696  transitionDelay: ''
1697};
1698
1699proto.removeTransitionStyles = function() {
1700  // remove transition
1701  this.css( cleanTransitionStyle );
1702};
1703
1704// ----- stagger ----- //
1705
1706proto.stagger = function( delay ) {
1707  delay = isNaN( delay ) ? 0 : delay;
1708  this.staggerDelay = delay + 'ms';
1709};
1710
1711// ----- show/hide/remove ----- //
1712
1713// remove element from DOM
1714proto.removeElem = function() {
1715  this.element.parentNode.removeChild( this.element );
1716  // remove display: none
1717  this.css({ display: '' });
1718  this.emitEvent( 'remove', [ this ] );
1719};
1720
1721proto.remove = function() {
1722  // just remove element if no transition support or no transition
1723  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1724    this.removeElem();
1725    return;
1726  }
1727
1728  // start transition
1729  this.once( 'transitionEnd', function() {
1730    this.removeElem();
1731  });
1732  this.hide();
1733};
1734
1735proto.reveal = function() {
1736  delete this.isHidden;
1737  // remove display: none
1738  this.css({ display: '' });
1739
1740  var options = this.layout.options;
1741
1742  var onTransitionEnd = {};
1743  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
1744  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
1745
1746  this.transition({
1747    from: options.hiddenStyle,
1748    to: options.visibleStyle,
1749    isCleaning: true,
1750    onTransitionEnd: onTransitionEnd
1751  });
1752};
1753
1754proto.onRevealTransitionEnd = function() {
1755  // check if still visible
1756  // during transition, item may have been hidden
1757  if ( !this.isHidden ) {
1758    this.emitEvent('reveal');
1759  }
1760};
1761
1762/**
1763 * get style property use for hide/reveal transition end
1764 * @param {String} styleProperty - hiddenStyle/visibleStyle
1765 * @returns {String}
1766 */
1767proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
1768  var optionStyle = this.layout.options[ styleProperty ];
1769  // use opacity
1770  if ( optionStyle.opacity ) {
1771    return 'opacity';
1772  }
1773  // get first property
1774  for ( var prop in optionStyle ) {
1775    return prop;
1776  }
1777};
1778
1779proto.hide = function() {
1780  // set flag
1781  this.isHidden = true;
1782  // remove display: none
1783  this.css({ display: '' });
1784
1785  var options = this.layout.options;
1786
1787  var onTransitionEnd = {};
1788  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
1789  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
1790
1791  this.transition({
1792    from: options.visibleStyle,
1793    to: options.hiddenStyle,
1794    // keep hidden stuff hidden
1795    isCleaning: true,
1796    onTransitionEnd: onTransitionEnd
1797  });
1798};
1799
1800proto.onHideTransitionEnd = function() {
1801  // check if still hidden
1802  // during transition, item may have been un-hidden
1803  if ( this.isHidden ) {
1804    this.css({ display: 'none' });
1805    this.emitEvent('hide');
1806  }
1807};
1808
1809proto.destroy = function() {
1810  this.css({
1811    position: '',
1812    left: '',
1813    right: '',
1814    top: '',
1815    bottom: '',
1816    transition: '',
1817    transform: ''
1818  });
1819};
1820
1821return Item;
1822
1823}));
1824
1825/*!
1826 * Outlayer v2.1.1
1827 * the brains and guts of a layout library
1828 * MIT license
1829 */
1830
1831( function( window, factory ) {
1832  'use strict';
1833  // universal module definition
1834  /* jshint strict: false */ /* globals define, module, require */
1835  if ( typeof define == 'function' && define.amd ) {
1836    // AMD - RequireJS
1837    define( 'outlayer/outlayer',[
1838        'ev-emitter/ev-emitter',
1839        'get-size/get-size',
1840        'fizzy-ui-utils/utils',
1841        './item'
1842      ],
1843      function( EvEmitter, getSize, utils, Item ) {
1844        return factory( window, EvEmitter, getSize, utils, Item);
1845      }
1846    );
1847  } else if ( typeof module == 'object' && module.exports ) {
1848    // CommonJS - Browserify, Webpack
1849    module.exports = factory(
1850      window,
1851      require('ev-emitter'),
1852      require('get-size'),
1853      require('fizzy-ui-utils'),
1854      require('./item')
1855    );
1856  } else {
1857    // browser global
1858    window.Outlayer = factory(
1859      window,
1860      window.EvEmitter,
1861      window.getSize,
1862      window.fizzyUIUtils,
1863      window.Outlayer.Item
1864    );
1865  }
1866
1867}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
1868'use strict';
1869
1870// ----- vars ----- //
1871
1872var console = window.console;
1873var jQuery = window.jQuery;
1874var noop = function() {};
1875
1876// -------------------------- Outlayer -------------------------- //
1877
1878// globally unique identifiers
1879var GUID = 0;
1880// internal store of all Outlayer intances
1881var instances = {};
1882
1883
1884/**
1885 * @param {Element, String} element
1886 * @param {Object} options
1887 * @constructor
1888 */
1889function Outlayer( element, options ) {
1890  var queryElement = utils.getQueryElement( element );
1891  if ( !queryElement ) {
1892    if ( console ) {
1893      console.error( 'Bad element for ' + this.constructor.namespace +
1894        ': ' + ( queryElement || element ) );
1895    }
1896    return;
1897  }
1898  this.element = queryElement;
1899  // add jQuery
1900  if ( jQuery ) {
1901    this.$element = jQuery( this.element );
1902  }
1903
1904  // options
1905  this.options = utils.extend( {}, this.constructor.defaults );
1906  this.option( options );
1907
1908  // add id for Outlayer.getFromElement
1909  var id = ++GUID;
1910  this.element.outlayerGUID = id; // expando
1911  instances[ id ] = this; // associate via id
1912
1913  // kick it off
1914  this._create();
1915
1916  var isInitLayout = this._getOption('initLayout');
1917  if ( isInitLayout ) {
1918    this.layout();
1919  }
1920}
1921
1922// settings are for internal use only
1923Outlayer.namespace = 'outlayer';
1924Outlayer.Item = Item;
1925
1926// default options
1927Outlayer.defaults = {
1928  containerStyle: {
1929    position: 'relative'
1930  },
1931  initLayout: true,
1932  originLeft: true,
1933  originTop: true,
1934  resize: true,
1935  resizeContainer: true,
1936  // item options
1937  transitionDuration: '0.4s',
1938  hiddenStyle: {
1939    opacity: 0,
1940    transform: 'scale(0.001)'
1941  },
1942  visibleStyle: {
1943    opacity: 1,
1944    transform: 'scale(1)'
1945  }
1946};
1947
1948var proto = Outlayer.prototype;
1949// inherit EvEmitter
1950utils.extend( proto, EvEmitter.prototype );
1951
1952/**
1953 * set options
1954 * @param {Object} opts
1955 */
1956proto.option = function( opts ) {
1957  utils.extend( this.options, opts );
1958};
1959
1960/**
1961 * get backwards compatible option value, check old name
1962 */
1963proto._getOption = function( option ) {
1964  var oldOption = this.constructor.compatOptions[ option ];
1965  return oldOption && this.options[ oldOption ] !== undefined ?
1966    this.options[ oldOption ] : this.options[ option ];
1967};
1968
1969Outlayer.compatOptions = {
1970  // currentName: oldName
1971  initLayout: 'isInitLayout',
1972  horizontal: 'isHorizontal',
1973  layoutInstant: 'isLayoutInstant',
1974  originLeft: 'isOriginLeft',
1975  originTop: 'isOriginTop',
1976  resize: 'isResizeBound',
1977  resizeContainer: 'isResizingContainer'
1978};
1979
1980proto._create = function() {
1981  // get items from children
1982  this.reloadItems();
1983  // elements that affect layout, but are not laid out
1984  this.stamps = [];
1985  this.stamp( this.options.stamp );
1986  // set container style
1987  utils.extend( this.element.style, this.options.containerStyle );
1988
1989  // bind resize method
1990  var canBindResize = this._getOption('resize');
1991  if ( canBindResize ) {
1992    this.bindResize();
1993  }
1994};
1995
1996// goes through all children again and gets bricks in proper order
1997proto.reloadItems = function() {
1998  // collection of item elements
1999  this.items = this._itemize( this.element.children );
2000};
2001
2002
2003/**
2004 * turn elements into Outlayer.Items to be used in layout
2005 * @param {Array or NodeList or HTMLElement} elems
2006 * @returns {Array} items - collection of new Outlayer Items
2007 */
2008proto._itemize = function( elems ) {
2009
2010  var itemElems = this._filterFindItemElements( elems );
2011  var Item = this.constructor.Item;
2012
2013  // create new Outlayer Items for collection
2014  var items = [];
2015  for ( var i=0; i < itemElems.length; i++ ) {
2016    var elem = itemElems[i];
2017    var item = new Item( elem, this );
2018    items.push( item );
2019  }
2020
2021  return items;
2022};
2023
2024/**
2025 * get item elements to be used in layout
2026 * @param {Array or NodeList or HTMLElement} elems
2027 * @returns {Array} items - item elements
2028 */
2029proto._filterFindItemElements = function( elems ) {
2030  return utils.filterFindElements( elems, this.options.itemSelector );
2031};
2032
2033/**
2034 * getter method for getting item elements
2035 * @returns {Array} elems - collection of item elements
2036 */
2037proto.getItemElements = function() {
2038  return this.items.map( function( item ) {
2039    return item.element;
2040  });
2041};
2042
2043// ----- init & layout ----- //
2044
2045/**
2046 * lays out all items
2047 */
2048proto.layout = function() {
2049  this._resetLayout();
2050  this._manageStamps();
2051
2052  // don't animate first layout
2053  var layoutInstant = this._getOption('layoutInstant');
2054  var isInstant = layoutInstant !== undefined ?
2055    layoutInstant : !this._isLayoutInited;
2056  this.layoutItems( this.items, isInstant );
2057
2058  // flag for initalized
2059  this._isLayoutInited = true;
2060};
2061
2062// _init is alias for layout
2063proto._init = proto.layout;
2064
2065/**
2066 * logic before any new layout
2067 */
2068proto._resetLayout = function() {
vendor: 13,499 bytes, lines 2069-2637
2069  this.getSize();
2070};
2071
2072
2073proto.getSize = function() {
2074  this.size = getSize( this.element );
2075};
2076
2077/**
2078 * get measurement from option, for columnWidth, rowHeight, gutter
2079 * if option is String -> get element from selector string, & get size of element
2080 * if option is Element -> get size of element
2081 * else use option as a number
2082 *
2083 * @param {String} measurement
2084 * @param {String} size - width or height
2085 * @private
2086 */
2087proto._getMeasurement = function( measurement, size ) {
2088  var option = this.options[ measurement ];
2089  var elem;
2090  if ( !option ) {
2091    // default to 0
2092    this[ measurement ] = 0;
2093  } else {
2094    // use option as an element
2095    if ( typeof option == 'string' ) {
2096      elem = this.element.querySelector( option );
2097    } else if ( option instanceof HTMLElement ) {
2098      elem = option;
2099    }
2100    // use size of element, if element
2101    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
2102  }
2103};
2104
2105/**
2106 * layout a collection of item elements
2107 * @api public
2108 */
2109proto.layoutItems = function( items, isInstant ) {
2110  items = this._getItemsForLayout( items );
2111
2112  this._layoutItems( items, isInstant );
2113
2114  this._postLayout();
2115};
2116
2117/**
2118 * get the items to be laid out
2119 * you may want to skip over some items
2120 * @param {Array} items
2121 * @returns {Array} items
2122 */
2123proto._getItemsForLayout = function( items ) {
2124  return items.filter( function( item ) {
2125    return !item.isIgnored;
2126  });
2127};
2128
2129/**
2130 * layout items
2131 * @param {Array} items
2132 * @param {Boolean} isInstant
2133 */
2134proto._layoutItems = function( items, isInstant ) {
2135  this._emitCompleteOnItems( 'layout', items );
2136
2137  if ( !items || !items.length ) {
2138    // no items, emit event with empty array
2139    return;
2140  }
2141
2142  var queue = [];
2143
2144  items.forEach( function( item ) {
2145    // get x/y object from method
2146    var position = this._getItemLayoutPosition( item );
2147    // enqueue
2148    position.item = item;
2149    position.isInstant = isInstant || item.isLayoutInstant;
2150    queue.push( position );
2151  }, this );
2152
2153  this._processLayoutQueue( queue );
2154};
2155
2156/**
2157 * get item layout position
2158 * @param {Outlayer.Item} item
2159 * @returns {Object} x and y position
2160 */
2161proto._getItemLayoutPosition = function( /* item */ ) {
2162  return {
2163    x: 0,
2164    y: 0
2165  };
2166};
2167
2168/**
2169 * iterate over array and position each item
2170 * Reason being - separating this logic prevents 'layout invalidation'
2171 * thx @paul_irish
2172 * @param {Array} queue
2173 */
2174proto._processLayoutQueue = function( queue ) {
2175  this.updateStagger();
2176  queue.forEach( function( obj, i ) {
2177    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
2178  }, this );
2179};
2180
2181// set stagger from option in milliseconds number
2182proto.updateStagger = function() {
2183  var stagger = this.options.stagger;
2184  if ( stagger === null || stagger === undefined ) {
2185    this.stagger = 0;
2186    return;
2187  }
2188  this.stagger = getMilliseconds( stagger );
2189  return this.stagger;
2190};
2191
2192/**
2193 * Sets position of item in DOM
2194 * @param {Outlayer.Item} item
2195 * @param {Number} x - horizontal position
2196 * @param {Number} y - vertical position
2197 * @param {Boolean} isInstant - disables transitions
2198 */
2199proto._positionItem = function( item, x, y, isInstant, i ) {
2200  if ( isInstant ) {
2201    // if not transition, just set CSS
2202    item.goTo( x, y );
2203  } else {
2204    item.stagger( i * this.stagger );
2205    item.moveTo( x, y );
2206  }
2207};
2208
2209/**
2210 * Any logic you want to do after each layout,
2211 * i.e. size the container
2212 */
2213proto._postLayout = function() {
2214  this.resizeContainer();
2215};
2216
2217proto.resizeContainer = function() {
2218  var isResizingContainer = this._getOption('resizeContainer');
2219  if ( !isResizingContainer ) {
2220    return;
2221  }
2222  var size = this._getContainerSize();
2223  if ( size ) {
2224    this._setContainerMeasure( size.width, true );
2225    this._setContainerMeasure( size.height, false );
2226  }
2227};
2228
2229/**
2230 * Sets width or height of container if returned
2231 * @returns {Object} size
2232 *   @param {Number} width
2233 *   @param {Number} height
2234 */
2235proto._getContainerSize = noop;
2236
2237/**
2238 * @param {Number} measure - size of width or height
2239 * @param {Boolean} isWidth
2240 */
2241proto._setContainerMeasure = function( measure, isWidth ) {
2242  if ( measure === undefined ) {
2243    return;
2244  }
2245
2246  var elemSize = this.size;
2247  // add padding and border width if border box
2248  if ( elemSize.isBorderBox ) {
2249    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2250      elemSize.borderLeftWidth + elemSize.borderRightWidth :
2251      elemSize.paddingBottom + elemSize.paddingTop +
2252      elemSize.borderTopWidth + elemSize.borderBottomWidth;
2253  }
2254
2255  measure = Math.max( measure, 0 );
2256  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2257};
2258
2259/**
2260 * emit eventComplete on a collection of items events
2261 * @param {String} eventName
2262 * @param {Array} items - Outlayer.Items
2263 */
2264proto._emitCompleteOnItems = function( eventName, items ) {
2265  var _this = this;
2266  function onComplete() {
2267    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
2268  }
2269
2270  var count = items.length;
2271  if ( !items || !count ) {
2272    onComplete();
2273    return;
2274  }
2275
2276  var doneCount = 0;
2277  function tick() {
2278    doneCount++;
2279    if ( doneCount == count ) {
2280      onComplete();
2281    }
2282  }
2283
2284  // bind callback
2285  items.forEach( function( item ) {
2286    item.once( eventName, tick );
2287  });
2288};
2289
2290/**
2291 * emits events via EvEmitter and jQuery events
2292 * @param {String} type - name of event
2293 * @param {Event} event - original event
2294 * @param {Array} args - extra arguments
2295 */
2296proto.dispatchEvent = function( type, event, args ) {
2297  // add original event to arguments
2298  var emitArgs = event ? [ event ].concat( args ) : args;
2299  this.emitEvent( type, emitArgs );
2300
2301  if ( jQuery ) {
2302    // set this.$element
2303    this.$element = this.$element || jQuery( this.element );
2304    if ( event ) {
2305      // create jQuery event
2306      var $event = jQuery.Event( event );
2307      $event.type = type;
2308      this.$element.trigger( $event, args );
2309    } else {
2310      // just trigger with type if no event available
2311      this.$element.trigger( type, args );
2312    }
2313  }
2314};
2315
2316// -------------------------- ignore & stamps -------------------------- //
2317
2318
2319/**
2320 * keep item in collection, but do not lay it out
2321 * ignored items do not get skipped in layout
2322 * @param {Element} elem
2323 */
2324proto.ignore = function( elem ) {
2325  var item = this.getItem( elem );
2326  if ( item ) {
2327    item.isIgnored = true;
2328  }
2329};
2330
2331/**
2332 * return item to layout collection
2333 * @param {Element} elem
2334 */
2335proto.unignore = function( elem ) {
2336  var item = this.getItem( elem );
2337  if ( item ) {
2338    delete item.isIgnored;
2339  }
2340};
2341
2342/**
2343 * adds elements to stamps
2344 * @param {NodeList, Array, Element, or String} elems
2345 */
2346proto.stamp = function( elems ) {
2347  elems = this._find( elems );
2348  if ( !elems ) {
2349    return;
2350  }
2351
2352  this.stamps = this.stamps.concat( elems );
2353  // ignore
2354  elems.forEach( this.ignore, this );
2355};
2356
2357/**
2358 * removes elements to stamps
2359 * @param {NodeList, Array, or Element} elems
2360 */
2361proto.unstamp = function( elems ) {
2362  elems = this._find( elems );
2363  if ( !elems ){
2364    return;
2365  }
2366
2367  elems.forEach( function( elem ) {
2368    // filter out removed stamp elements
2369    utils.removeFrom( this.stamps, elem );
2370    this.unignore( elem );
2371  }, this );
2372};
2373
2374/**
2375 * finds child elements
2376 * @param {NodeList, Array, Element, or String} elems
2377 * @returns {Array} elems
2378 */
2379proto._find = function( elems ) {
2380  if ( !elems ) {
2381    return;
2382  }
2383  // if string, use argument as selector string
2384  if ( typeof elems == 'string' ) {
2385    elems = this.element.querySelectorAll( elems );
2386  }
2387  elems = utils.makeArray( elems );
2388  return elems;
2389};
2390
2391proto._manageStamps = function() {
2392  if ( !this.stamps || !this.stamps.length ) {
2393    return;
2394  }
2395
2396  this._getBoundingRect();
2397
2398  this.stamps.forEach( this._manageStamp, this );
2399};
2400
2401// update boundingLeft / Top
2402proto._getBoundingRect = function() {
2403  // get bounding rect for container element
2404  var boundingRect = this.element.getBoundingClientRect();
2405  var size = this.size;
2406  this._boundingRect = {
2407    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2408    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2409    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2410    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2411  };
2412};
2413
2414/**
2415 * @param {Element} stamp
2416**/
2417proto._manageStamp = noop;
2418
2419/**
2420 * get x/y position of element relative to container element
2421 * @param {Element} elem
2422 * @returns {Object} offset - has left, top, right, bottom
2423 */
2424proto._getElementOffset = function( elem ) {
2425  var boundingRect = elem.getBoundingClientRect();
2426  var thisRect = this._boundingRect;
2427  var size = getSize( elem );
2428  var offset = {
2429    left: boundingRect.left - thisRect.left - size.marginLeft,
2430    top: boundingRect.top - thisRect.top - size.marginTop,
2431    right: thisRect.right - boundingRect.right - size.marginRight,
2432    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2433  };
2434  return offset;
2435};
2436
2437// -------------------------- resize -------------------------- //
2438
2439// enable event handlers for listeners
2440// i.e. resize -> onresize
2441proto.handleEvent = utils.handleEvent;
2442
2443/**
2444 * Bind layout to window resizing
2445 */
2446proto.bindResize = function() {
2447  window.addEventListener( 'resize', this );
2448  this.isResizeBound = true;
2449};
2450
2451/**
2452 * Unbind layout to window resizing
2453 */
2454proto.unbindResize = function() {
2455  window.removeEventListener( 'resize', this );
2456  this.isResizeBound = false;
2457};
2458
2459proto.onresize = function() {
2460  this.resize();
2461};
2462
2463utils.debounceMethod( Outlayer, 'onresize', 100 );
2464
2465proto.resize = function() {
2466  // don't trigger if size did not change
2467  // or if resize was unbound. See #9
2468  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
2469    return;
2470  }
2471
2472  this.layout();
2473};
2474
2475/**
2476 * check if layout is needed post layout
2477 * @returns Boolean
2478 */
2479proto.needsResizeLayout = function() {
2480  var size = getSize( this.element );
2481  // check that this.size and size are there
2482  // IE8 triggers resize on body size change, so they might not be
2483  var hasSizes = this.size && size;
2484  return hasSizes && size.innerWidth !== this.size.innerWidth;
2485};
2486
2487// -------------------------- methods -------------------------- //
2488
2489/**
2490 * add items to Outlayer instance
2491 * @param {Array or NodeList or Element} elems
2492 * @returns {Array} items - Outlayer.Items
2493**/
2494proto.addItems = function( elems ) {
2495  var items = this._itemize( elems );
2496  // add items to collection
2497  if ( items.length ) {
2498    this.items = this.items.concat( items );
2499  }
2500  return items;
2501};
2502
2503/**
2504 * Layout newly-appended item elements
2505 * @param {Array or NodeList or Element} elems
2506 */
2507proto.appended = function( elems ) {
2508  var items = this.addItems( elems );
2509  if ( !items.length ) {
2510    return;
2511  }
2512  // layout and reveal just the new items
2513  this.layoutItems( items, true );
2514  this.reveal( items );
2515};
2516
2517/**
2518 * Layout prepended elements
2519 * @param {Array or NodeList or Element} elems
2520 */
2521proto.prepended = function( elems ) {
2522  var items = this._itemize( elems );
2523  if ( !items.length ) {
2524    return;
2525  }
2526  // add items to beginning of collection
2527  var previousItems = this.items.slice(0);
2528  this.items = items.concat( previousItems );
2529  // start new layout
2530  this._resetLayout();
2531  this._manageStamps();
2532  // layout new stuff without transition
2533  this.layoutItems( items, true );
2534  this.reveal( items );
2535  // layout previous items
2536  this.layoutItems( previousItems );
2537};
2538
2539/**
2540 * reveal a collection of items
2541 * @param {Array of Outlayer.Items} items
2542 */
2543proto.reveal = function( items ) {
2544  this._emitCompleteOnItems( 'reveal', items );
2545  if ( !items || !items.length ) {
2546    return;
2547  }
2548  var stagger = this.updateStagger();
2549  items.forEach( function( item, i ) {
2550    item.stagger( i * stagger );
2551    item.reveal();
2552  });
2553};
2554
2555/**
2556 * hide a collection of items
2557 * @param {Array of Outlayer.Items} items
2558 */
2559proto.hide = function( items ) {
2560  this._emitCompleteOnItems( 'hide', items );
2561  if ( !items || !items.length ) {
2562    return;
2563  }
2564  var stagger = this.updateStagger();
2565  items.forEach( function( item, i ) {
2566    item.stagger( i * stagger );
2567    item.hide();
2568  });
2569};
2570
2571/**
2572 * reveal item elements
2573 * @param {Array}, {Element}, {NodeList} items
2574 */
2575proto.revealItemElements = function( elems ) {
2576  var items = this.getItems( elems );
2577  this.reveal( items );
2578};
2579
2580/**
2581 * hide item elements
2582 * @param {Array}, {Element}, {NodeList} items
2583 */
2584proto.hideItemElements = function( elems ) {
2585  var items = this.getItems( elems );
2586  this.hide( items );
2587};
2588
2589/**
2590 * get Outlayer.Item, given an Element
2591 * @param {Element} elem
2592 * @param {Function} callback
2593 * @returns {Outlayer.Item} item
2594 */
2595proto.getItem = function( elem ) {
2596  // loop through items to get the one that matches
2597  for ( var i=0; i < this.items.length; i++ ) {
2598    var item = this.items[i];
2599    if ( item.element == elem ) {
2600      // return item
2601      return item;
2602    }
2603  }
2604};
2605
2606/**
2607 * get collection of Outlayer.Items, given Elements
2608 * @param {Array} elems
2609 * @returns {Array} items - Outlayer.Items
2610 */
2611proto.getItems = function( elems ) {
2612  elems = utils.makeArray( elems );
2613  var items = [];
2614  elems.forEach( function( elem ) {
2615    var item = this.getItem( elem );
2616    if ( item ) {
2617      items.push( item );
2618    }
2619  }, this );
2620
2621  return items;
2622};
2623
2624/**
2625 * remove element(s) from instance and DOM
2626 * @param {Array or NodeList or Element} elems
2627 */
2628proto.remove = function( elems ) {
2629  var removeItems = this.getItems( elems );
2630
2631  this._emitCompleteOnItems( 'remove', removeItems );
2632
2633  // bail if no items to remove
2634  if ( !removeItems || !removeItems.length ) {
2635    return;
2636  }
2637
vendor: 38,285 bytes, lines 2638-4061
2638  removeItems.forEach( function( item ) {
2639    item.remove();
2640    // remove item from collection
2641    utils.removeFrom( this.items, item );
2642  }, this );
2643};
2644
2645// ----- destroy ----- //
2646
2647// remove and disable Outlayer instance
2648proto.destroy = function() {
2649  // clean up dynamic styles
2650  var style = this.element.style;
2651  style.height = '';
2652  style.position = '';
2653  style.width = '';
2654  // destroy items
2655  this.items.forEach( function( item ) {
2656    item.destroy();
2657  });
2658
2659  this.unbindResize();
2660
2661  var id = this.element.outlayerGUID;
2662  delete instances[ id ]; // remove reference to instance by id
2663  delete this.element.outlayerGUID;
2664  // remove data for jQuery
2665  if ( jQuery ) {
2666    jQuery.removeData( this.element, this.constructor.namespace );
2667  }
2668
2669};
2670
2671// -------------------------- data -------------------------- //
2672
2673/**
2674 * get Outlayer instance from element
2675 * @param {Element} elem
2676 * @returns {Outlayer}
2677 */
2678Outlayer.data = function( elem ) {
2679  elem = utils.getQueryElement( elem );
2680  var id = elem && elem.outlayerGUID;
2681  return id && instances[ id ];
2682};
2683
2684
2685// -------------------------- create Outlayer class -------------------------- //
2686
2687/**
2688 * create a layout class
2689 * @param {String} namespace
2690 */
2691Outlayer.create = function( namespace, options ) {
2692  // sub-class Outlayer
2693  var Layout = subclass( Outlayer );
2694  // apply new options and compatOptions
2695  Layout.defaults = utils.extend( {}, Outlayer.defaults );
2696  utils.extend( Layout.defaults, options );
2697  Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );
2698
2699  Layout.namespace = namespace;
2700
2701  Layout.data = Outlayer.data;
2702
2703  // sub-class Item
2704  Layout.Item = subclass( Item );
2705
2706  // -------------------------- declarative -------------------------- //
2707
2708  utils.htmlInit( Layout, namespace );
2709
2710  // -------------------------- jQuery bridge -------------------------- //
2711
2712  // make into jQuery plugin
2713  if ( jQuery && jQuery.bridget ) {
2714    jQuery.bridget( namespace, Layout );
2715  }
2716
2717  return Layout;
2718};
2719
2720function subclass( Parent ) {
2721  function SubClass() {
2722    Parent.apply( this, arguments );
2723  }
2724
2725  SubClass.prototype = Object.create( Parent.prototype );
2726  SubClass.prototype.constructor = SubClass;
2727
2728  return SubClass;
2729}
2730
2731// ----- helpers ----- //
2732
2733// how many milliseconds are in each unit
2734var msUnits = {
2735  ms: 1,
2736  s: 1000
2737};
2738
2739// munge time-like parameter into millisecond number
2740// '0.4s' -> 40
2741function getMilliseconds( time ) {
2742  if ( typeof time == 'number' ) {
2743    return time;
2744  }
2745  var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
2746  var num = matches && matches[1];
2747  var unit = matches && matches[2];
2748  if ( !num.length ) {
2749    return 0;
2750  }
2751  num = parseFloat( num );
2752  var mult = msUnits[ unit ] || 1;
2753  return num * mult;
2754}
2755
2756// ----- fin ----- //
2757
2758// back in global
2759Outlayer.Item = Item;
2760
2761return Outlayer;
2762
2763}));
2764
2765/**
2766 * Isotope Item
2767**/
2768
2769( function( window, factory ) {
2770  // universal module definition
2771  /* jshint strict: false */ /*globals define, module, require */
2772  if ( typeof define == 'function' && define.amd ) {
2773    // AMD
2774    define( 'isotope-layout/js/item',[
2775        'outlayer/outlayer'
2776      ],
2777      factory );
2778  } else if ( typeof module == 'object' && module.exports ) {
2779    // CommonJS
2780    module.exports = factory(
2781      require('outlayer')
2782    );
2783  } else {
2784    // browser global
2785    window.Isotope = window.Isotope || {};
2786    window.Isotope.Item = factory(
2787      window.Outlayer
2788    );
2789  }
2790
2791}( window, function factory( Outlayer ) {
2792'use strict';
2793
2794// -------------------------- Item -------------------------- //
2795
2796// sub-class Outlayer Item
2797function Item() {
2798  Outlayer.Item.apply( this, arguments );
2799}
2800
2801var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
2802
2803var _create = proto._create;
2804proto._create = function() {
2805  // assign id, used for original-order sorting
2806  this.id = this.layout.itemGUID++;
2807  _create.call( this );
2808  this.sortData = {};
2809};
2810
2811proto.updateSortData = function() {
2812  if ( this.isIgnored ) {
2813    return;
2814  }
2815  // default sorters
2816  this.sortData.id = this.id;
2817  // for backward compatibility
2818  this.sortData['original-order'] = this.id;
2819  this.sortData.random = Math.random();
2820  // go thru getSortData obj and apply the sorters
2821  var getSortData = this.layout.options.getSortData;
2822  var sorters = this.layout._sorters;
2823  for ( var key in getSortData ) {
2824    var sorter = sorters[ key ];
2825    this.sortData[ key ] = sorter( this.element, this );
2826  }
2827};
2828
2829var _destroy = proto.destroy;
2830proto.destroy = function() {
2831  // call super
2832  _destroy.apply( this, arguments );
2833  // reset display, #741
2834  this.css({
2835    display: ''
2836  });
2837};
2838
2839return Item;
2840
2841}));
2842
2843/**
2844 * Isotope LayoutMode
2845 */
2846
2847( function( window, factory ) {
2848  // universal module definition
2849  /* jshint strict: false */ /*globals define, module, require */
2850  if ( typeof define == 'function' && define.amd ) {
2851    // AMD
2852    define( 'isotope-layout/js/layout-mode',[
2853        'get-size/get-size',
2854        'outlayer/outlayer'
2855      ],
2856      factory );
2857  } else if ( typeof module == 'object' && module.exports ) {
2858    // CommonJS
2859    module.exports = factory(
2860      require('get-size'),
2861      require('outlayer')
2862    );
2863  } else {
2864    // browser global
2865    window.Isotope = window.Isotope || {};
2866    window.Isotope.LayoutMode = factory(
2867      window.getSize,
2868      window.Outlayer
2869    );
2870  }
2871
2872}( window, function factory( getSize, Outlayer ) {
2873  'use strict';
2874
2875  // layout mode class
2876  function LayoutMode( isotope ) {
2877    this.isotope = isotope;
2878    // link properties
2879    if ( isotope ) {
2880      this.options = isotope.options[ this.namespace ];
2881      this.element = isotope.element;
2882      this.items = isotope.filteredItems;
2883      this.size = isotope.size;
2884    }
2885  }
2886
2887  var proto = LayoutMode.prototype;
2888
2889  /**
2890   * some methods should just defer to default Outlayer method
2891   * and reference the Isotope instance as `this`
2892  **/
2893  var facadeMethods = [
2894    '_resetLayout',
2895    '_getItemLayoutPosition',
2896    '_manageStamp',
2897    '_getContainerSize',
2898    '_getElementOffset',
2899    'needsResizeLayout',
2900    '_getOption'
2901  ];
2902
2903  facadeMethods.forEach( function( methodName ) {
2904    proto[ methodName ] = function() {
2905      return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
2906    };
2907  });
2908
2909  // -----  ----- //
2910
2911  // for horizontal layout modes, check vertical size
2912  proto.needsVerticalResizeLayout = function() {
2913    // don't trigger if size did not change
2914    var size = getSize( this.isotope.element );
2915    // check that this.size and size are there
2916    // IE8 triggers resize on body size change, so they might not be
2917    var hasSizes = this.isotope.size && size;
2918    return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
2919  };
2920
2921  // ----- measurements ----- //
2922
2923  proto._getMeasurement = function() {
2924    this.isotope._getMeasurement.apply( this, arguments );
2925  };
2926
2927  proto.getColumnWidth = function() {
2928    this.getSegmentSize( 'column', 'Width' );
2929  };
2930
2931  proto.getRowHeight = function() {
2932    this.getSegmentSize( 'row', 'Height' );
2933  };
2934
2935  /**
2936   * get columnWidth or rowHeight
2937   * segment: 'column' or 'row'
2938   * size 'Width' or 'Height'
2939  **/
2940  proto.getSegmentSize = function( segment, size ) {
2941    var segmentName = segment + size;
2942    var outerSize = 'outer' + size;
2943    // columnWidth / outerWidth // rowHeight / outerHeight
2944    this._getMeasurement( segmentName, outerSize );
2945    // got rowHeight or columnWidth, we can chill
2946    if ( this[ segmentName ] ) {
2947      return;
2948    }
2949    // fall back to item of first element
2950    var firstItemSize = this.getFirstItemSize();
2951    this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
2952      // or size of container
2953      this.isotope.size[ 'inner' + size ];
2954  };
2955
2956  proto.getFirstItemSize = function() {
2957    var firstItem = this.isotope.filteredItems[0];
2958    return firstItem && firstItem.element && getSize( firstItem.element );
2959  };
2960
2961  // ----- methods that should reference isotope ----- //
2962
2963  proto.layout = function() {
2964    this.isotope.layout.apply( this.isotope, arguments );
2965  };
2966
2967  proto.getSize = function() {
2968    this.isotope.getSize();
2969    this.size = this.isotope.size;
2970  };
2971
2972  // -------------------------- create -------------------------- //
2973
2974  LayoutMode.modes = {};
2975
2976  LayoutMode.create = function( namespace, options ) {
2977
2978    function Mode() {
2979      LayoutMode.apply( this, arguments );
2980    }
2981
2982    Mode.prototype = Object.create( proto );
2983    Mode.prototype.constructor = Mode;
2984
2985    // default options
2986    if ( options ) {
2987      Mode.options = options;
2988    }
2989
2990    Mode.prototype.namespace = namespace;
2991    // register in Isotope
2992    LayoutMode.modes[ namespace ] = Mode;
2993
2994    return Mode;
2995  };
2996
2997  return LayoutMode;
2998
2999}));
3000
3001/*!
3002 * Masonry v4.2.1
3003 * Cascading grid layout library
3004 * https://masonry.desandro.com
3005 * MIT License
3006 * by David DeSandro
3007 */
3008
3009( function( window, factory ) {
3010  // universal module definition
3011  /* jshint strict: false */ /*globals define, module, require */
3012  if ( typeof define == 'function' && define.amd ) {
3013    // AMD
3014    define( 'masonry-layout/masonry',[
3015        'outlayer/outlayer',
3016        'get-size/get-size'
3017      ],
3018      factory );
3019  } else if ( typeof module == 'object' && module.exports ) {
3020    // CommonJS
3021    module.exports = factory(
3022      require('outlayer'),
3023      require('get-size')
3024    );
3025  } else {
3026    // browser global
3027    window.Masonry = factory(
3028      window.Outlayer,
3029      window.getSize
3030    );
3031  }
3032
3033}( window, function factory( Outlayer, getSize ) {
3034
3035
3036
3037// -------------------------- masonryDefinition -------------------------- //
3038
3039  // create an Outlayer layout class
3040  var Masonry = Outlayer.create('masonry');
3041  // isFitWidth -> fitWidth
3042  Masonry.compatOptions.fitWidth = 'isFitWidth';
3043
3044  var proto = Masonry.prototype;
3045
3046  proto._resetLayout = function() {
3047    this.getSize();
3048    this._getMeasurement( 'columnWidth', 'outerWidth' );
3049    this._getMeasurement( 'gutter', 'outerWidth' );
3050    this.measureColumns();
3051
3052    // reset column Y
3053    this.colYs = [];
3054    for ( var i=0; i < this.cols; i++ ) {
3055      this.colYs.push( 0 );
3056    }
3057
3058    this.maxY = 0;
3059    this.horizontalColIndex = 0;
3060  };
3061
3062  proto.measureColumns = function() {
3063    this.getContainerWidth();
3064    // if columnWidth is 0, default to outerWidth of first item
3065    if ( !this.columnWidth ) {
3066      var firstItem = this.items[0];
3067      var firstItemElem = firstItem && firstItem.element;
3068      // columnWidth fall back to item of first element
3069      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
3070        // if first elem has no width, default to size of container
3071        this.containerWidth;
3072    }
3073
3074    var columnWidth = this.columnWidth += this.gutter;
3075
3076    // calculate columns
3077    var containerWidth = this.containerWidth + this.gutter;
3078    var cols = containerWidth / columnWidth;
3079    // fix rounding errors, typically with gutters
3080    var excess = columnWidth - containerWidth % columnWidth;
3081    // if overshoot is less than a pixel, round up, otherwise floor it
3082    var mathMethod = excess && excess < 1 ? 'round' : 'floor';
3083    cols = Math[ mathMethod ]( cols );
3084    this.cols = Math.max( cols, 1 );
3085  };
3086
3087  proto.getContainerWidth = function() {
3088    // container is parent if fit width
3089    var isFitWidth = this._getOption('fitWidth');
3090    var container = isFitWidth ? this.element.parentNode : this.element;
3091    // check that this.size and size are there
3092    // IE8 triggers resize on body size change, so they might not be
3093    var size = getSize( container );
3094    this.containerWidth = size && size.innerWidth;
3095  };
3096
3097  proto._getItemLayoutPosition = function( item ) {
3098    item.getSize();
3099    // how many columns does this brick span
3100    var remainder = item.size.outerWidth % this.columnWidth;
3101    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
3102    // round if off by 1 pixel, otherwise use ceil
3103    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
3104    colSpan = Math.min( colSpan, this.cols );
3105    // use horizontal or top column position
3106    var colPosMethod = this.options.horizontalOrder ?
3107      '_getHorizontalColPosition' : '_getTopColPosition';
3108    var colPosition = this[ colPosMethod ]( colSpan, item );
3109    // position the brick
3110    var position = {
3111      x: this.columnWidth * colPosition.col,
3112      y: colPosition.y
3113    };
3114    // apply setHeight to necessary columns
3115    var setHeight = colPosition.y + item.size.outerHeight;
3116    var setMax = colSpan + colPosition.col;
3117    for ( var i = colPosition.col; i < setMax; i++ ) {
3118      this.colYs[i] = setHeight;
3119    }
3120
3121    return position;
3122  };
3123
3124  proto._getTopColPosition = function( colSpan ) {
3125    var colGroup = this._getTopColGroup( colSpan );
3126    // get the minimum Y value from the columns
3127    var minimumY = Math.min.apply( Math, colGroup );
3128
3129    return {
3130      col: colGroup.indexOf( minimumY ),
3131      y: minimumY,
3132    };
3133  };
3134
3135  /**
3136   * @param {Number} colSpan - number of columns the element spans
3137   * @returns {Array} colGroup
3138   */
3139  proto._getTopColGroup = function( colSpan ) {
3140    if ( colSpan < 2 ) {
3141      // if brick spans only one column, use all the column Ys
3142      return this.colYs;
3143    }
3144
3145    var colGroup = [];
3146    // how many different places could this brick fit horizontally
3147    var groupCount = this.cols + 1 - colSpan;
3148    // for each group potential horizontal position
3149    for ( var i = 0; i < groupCount; i++ ) {
3150      colGroup[i] = this._getColGroupY( i, colSpan );
3151    }
3152    return colGroup;
3153  };
3154
3155  proto._getColGroupY = function( col, colSpan ) {
3156    if ( colSpan < 2 ) {
3157      return this.colYs[ col ];
3158    }
3159    // make an array of colY values for that one group
3160    var groupColYs = this.colYs.slice( col, col + colSpan );
3161    // and get the max value of the array
3162    return Math.max.apply( Math, groupColYs );
3163  };
3164
3165  // get column position based on horizontal index. #873
3166  proto._getHorizontalColPosition = function( colSpan, item ) {
3167    var col = this.horizontalColIndex % this.cols;
3168    var isOver = colSpan > 1 && col + colSpan > this.cols;
3169    // shift to next row if item can't fit on current row
3170    col = isOver ? 0 : col;
3171    // don't let zero-size items take up space
3172    var hasSize = item.size.outerWidth && item.size.outerHeight;
3173    this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
3174
3175    return {
3176      col: col,
3177      y: this._getColGroupY( col, colSpan ),
3178    };
3179  };
3180
3181  proto._manageStamp = function( stamp ) {
3182    var stampSize = getSize( stamp );
3183    var offset = this._getElementOffset( stamp );
3184    // get the columns that this stamp affects
3185    var isOriginLeft = this._getOption('originLeft');
3186    var firstX = isOriginLeft ? offset.left : offset.right;
3187    var lastX = firstX + stampSize.outerWidth;
3188    var firstCol = Math.floor( firstX / this.columnWidth );
3189    firstCol = Math.max( 0, firstCol );
3190    var lastCol = Math.floor( lastX / this.columnWidth );
3191    // lastCol should not go over if multiple of columnWidth #425
3192    lastCol -= lastX % this.columnWidth ? 0 : 1;
3193    lastCol = Math.min( this.cols - 1, lastCol );
3194    // set colYs to bottom of the stamp
3195
3196    var isOriginTop = this._getOption('originTop');
3197    var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
3198      stampSize.outerHeight;
3199    for ( var i = firstCol; i <= lastCol; i++ ) {
3200      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
3201    }
3202  };
3203
3204  proto._getContainerSize = function() {
3205    this.maxY = Math.max.apply( Math, this.colYs );
3206    var size = {
3207      height: this.maxY
3208    };
3209
3210    if ( this._getOption('fitWidth') ) {
3211      size.width = this._getContainerFitWidth();
3212    }
3213
3214    return size;
3215  };
3216
3217  proto._getContainerFitWidth = function() {
3218    var unusedCols = 0;
3219    // count unused columns
3220    var i = this.cols;
3221    while ( --i ) {
3222      if ( this.colYs[i] !== 0 ) {
3223        break;
3224      }
3225      unusedCols++;
3226    }
3227    // fit container to columns that have been used
3228    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
3229  };
3230
3231  proto.needsResizeLayout = function() {
3232    var previousWidth = this.containerWidth;
3233    this.getContainerWidth();
3234    return previousWidth != this.containerWidth;
3235  };
3236
3237  return Masonry;
3238
3239}));
3240
3241/*!
3242 * Masonry layout mode
3243 * sub-classes Masonry
3244 * https://masonry.desandro.com
3245 */
3246
3247( function( window, factory ) {
3248  // universal module definition
3249  /* jshint strict: false */ /*globals define, module, require */
3250  if ( typeof define == 'function' && define.amd ) {
3251    // AMD
3252    define( 'isotope-layout/js/layout-modes/masonry',[
3253        '../layout-mode',
3254        'masonry-layout/masonry'
3255      ],
3256      factory );
3257  } else if ( typeof module == 'object' && module.exports ) {
3258    // CommonJS
3259    module.exports = factory(
3260      require('../layout-mode'),
3261      require('masonry-layout')
3262    );
3263  } else {
3264    // browser global
3265    factory(
3266      window.Isotope.LayoutMode,
3267      window.Masonry
3268    );
3269  }
3270
3271}( window, function factory( LayoutMode, Masonry ) {
3272'use strict';
3273
3274// -------------------------- masonryDefinition -------------------------- //
3275
3276  // create an Outlayer layout class
3277  var MasonryMode = LayoutMode.create('masonry');
3278
3279  var proto = MasonryMode.prototype;
3280
3281  var keepModeMethods = {
3282    _getElementOffset: true,
3283    layout: true,
3284    _getMeasurement: true
3285  };
3286
3287  // inherit Masonry prototype
3288  for ( var method in Masonry.prototype ) {
3289    // do not inherit mode methods
3290    if ( !keepModeMethods[ method ] ) {
3291      proto[ method ] = Masonry.prototype[ method ];
3292    }
3293  }
3294
3295  var measureColumns = proto.measureColumns;
3296  proto.measureColumns = function() {
3297    // set items, used if measuring first item
3298    this.items = this.isotope.filteredItems;
3299    measureColumns.call( this );
3300  };
3301
3302  // point to mode options for fitWidth
3303  var _getOption = proto._getOption;
3304  proto._getOption = function( option ) {
3305    if ( option == 'fitWidth' ) {
3306      return this.options.isFitWidth !== undefined ?
3307        this.options.isFitWidth : this.options.fitWidth;
3308    }
3309    return _getOption.apply( this.isotope, arguments );
3310  };
3311
3312  return MasonryMode;
3313
3314}));
3315
3316/**
3317 * fitRows layout mode
3318 */
3319
3320( function( window, factory ) {
3321  // universal module definition
3322  /* jshint strict: false */ /*globals define, module, require */
3323  if ( typeof define == 'function' && define.amd ) {
3324    // AMD
3325    define( 'isotope-layout/js/layout-modes/fit-rows',[
3326        '../layout-mode'
3327      ],
3328      factory );
3329  } else if ( typeof exports == 'object' ) {
3330    // CommonJS
3331    module.exports = factory(
3332      require('../layout-mode')
3333    );
3334  } else {
3335    // browser global
3336    factory(
3337      window.Isotope.LayoutMode
3338    );
3339  }
3340
3341}( window, function factory( LayoutMode ) {
3342'use strict';
3343
3344var FitRows = LayoutMode.create('fitRows');
3345
3346var proto = FitRows.prototype;
3347
3348proto._resetLayout = function() {
3349  this.x = 0;
3350  this.y = 0;
3351  this.maxY = 0;
3352  this._getMeasurement( 'gutter', 'outerWidth' );
3353};
3354
3355proto._getItemLayoutPosition = function( item ) {
3356  item.getSize();
3357
3358  var itemWidth = item.size.outerWidth + this.gutter;
3359  // if this element cannot fit in the current row
3360  var containerWidth = this.isotope.size.innerWidth + this.gutter;
3361  if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
3362    this.x = 0;
3363    this.y = this.maxY;
3364  }
3365
3366  var position = {
3367    x: this.x,
3368    y: this.y
3369  };
3370
3371  this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
3372  this.x += itemWidth;
3373
3374  return position;
3375};
3376
3377proto._getContainerSize = function() {
3378  return { height: this.maxY };
3379};
3380
3381return FitRows;
3382
3383}));
3384
3385/**
3386 * vertical layout mode
3387 */
3388
3389( function( window, factory ) {
3390  // universal module definition
3391  /* jshint strict: false */ /*globals define, module, require */
3392  if ( typeof define == 'function' && define.amd ) {
3393    // AMD
3394    define( 'isotope-layout/js/layout-modes/vertical',[
3395        '../layout-mode'
3396      ],
3397      factory );
3398  } else if ( typeof module == 'object' && module.exports ) {
3399    // CommonJS
3400    module.exports = factory(
3401      require('../layout-mode')
3402    );
3403  } else {
3404    // browser global
3405    factory(
3406      window.Isotope.LayoutMode
3407    );
3408  }
3409
3410}( window, function factory( LayoutMode ) {
3411'use strict';
3412
3413var Vertical = LayoutMode.create( 'vertical', {
3414  horizontalAlignment: 0
3415});
3416
3417var proto = Vertical.prototype;
3418
3419proto._resetLayout = function() {
3420  this.y = 0;
3421};
3422
3423proto._getItemLayoutPosition = function( item ) {
3424  item.getSize();
3425  var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
3426    this.options.horizontalAlignment;
3427  var y = this.y;
3428  this.y += item.size.outerHeight;
3429  return { x: x, y: y };
3430};
3431
3432proto._getContainerSize = function() {
3433  return { height: this.y };
3434};
3435
3436return Vertical;
3437
3438}));
3439
3440/*!
3441 * Isotope v3.0.6
3442 *
3443 * Licensed GPLv3 for open source use
3444 * or Isotope Commercial License for commercial use
3445 *
3446 * https://isotope.metafizzy.co
3447 * Copyright 2010-2018 Metafizzy
3448 */
3449
3450( function( window, factory ) {
3451  // universal module definition
3452  /* jshint strict: false */ /*globals define, module, require */
3453  if ( typeof define == 'function' && define.amd ) {
3454    // AMD
3455    define( [
3456        'outlayer/outlayer',
3457        'get-size/get-size',
3458        'desandro-matches-selector/matches-selector',
3459        'fizzy-ui-utils/utils',
3460        'isotope-layout/js/item',
3461        'isotope-layout/js/layout-mode',
3462        // include default layout modes
3463        'isotope-layout/js/layout-modes/masonry',
3464        'isotope-layout/js/layout-modes/fit-rows',
3465        'isotope-layout/js/layout-modes/vertical'
3466      ],
3467      function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
3468        return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
3469      });
3470  } else if ( typeof module == 'object' && module.exports ) {
3471    // CommonJS
3472    module.exports = factory(
3473      window,
3474      require('outlayer'),
3475      require('get-size'),
3476      require('desandro-matches-selector'),
3477      require('fizzy-ui-utils'),
3478      require('isotope-layout/js/item'),
3479      require('isotope-layout/js/layout-mode'),
3480      // include default layout modes
3481      require('isotope-layout/js/layout-modes/masonry'),
3482      require('isotope-layout/js/layout-modes/fit-rows'),
3483      require('isotope-layout/js/layout-modes/vertical')
3484    );
3485  } else {
3486    // browser global
3487    window.Isotope = factory(
3488      window,
3489      window.Outlayer,
3490      window.getSize,
3491      window.matchesSelector,
3492      window.fizzyUIUtils,
3493      window.Isotope.Item,
3494      window.Isotope.LayoutMode
3495    );
3496  }
3497
3498}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
3499  Item, LayoutMode ) {
3500
3501
3502
3503// -------------------------- vars -------------------------- //
3504
3505var jQuery = window.jQuery;
3506
3507// -------------------------- helpers -------------------------- //
3508
3509var trim = String.prototype.trim ?
3510  function( str ) {
3511    return str.trim();
3512  } :
3513  function( str ) {
3514    return str.replace( /^\s+|\s+$/g, '' );
3515  };
3516
3517// -------------------------- isotopeDefinition -------------------------- //
3518
3519  // create an Outlayer layout class
3520  var Isotope = Outlayer.create( 'isotope', {
3521    layoutMode: 'masonry',
3522    isJQueryFiltering: true,
3523    sortAscending: true
3524  });
3525
3526  Isotope.Item = Item;
3527  Isotope.LayoutMode = LayoutMode;
3528
3529  var proto = Isotope.prototype;
3530
3531  proto._create = function() {
3532    this.itemGUID = 0;
3533    // functions that sort items
3534    this._sorters = {};
3535    this._getSorters();
3536    // call super
3537    Outlayer.prototype._create.call( this );
3538
3539    // create layout modes
3540    this.modes = {};
3541    // start filteredItems with all items
3542    this.filteredItems = this.items;
3543    // keep of track of sortBys
3544    this.sortHistory = [ 'original-order' ];
3545    // create from registered layout modes
3546    for ( var name in LayoutMode.modes ) {
3547      this._initLayoutMode( name );
3548    }
3549  };
3550
3551  proto.reloadItems = function() {
3552    // reset item ID counter
3553    this.itemGUID = 0;
3554    // call super
3555    Outlayer.prototype.reloadItems.call( this );
3556  };
3557
3558  proto._itemize = function() {
3559    var items = Outlayer.prototype._itemize.apply( this, arguments );
3560    // assign ID for original-order
3561    for ( var i=0; i < items.length; i++ ) {
3562      var item = items[i];
3563      item.id = this.itemGUID++;
3564    }
3565    this._updateItemsSortData( items );
3566    return items;
3567  };
3568
3569
3570  // -------------------------- layout -------------------------- //
3571
3572  proto._initLayoutMode = function( name ) {
3573    var Mode = LayoutMode.modes[ name ];
3574    // set mode options
3575    // HACK extend initial options, back-fill in default options
3576    var initialOpts = this.options[ name ] || {};
3577    this.options[ name ] = Mode.options ?
3578      utils.extend( Mode.options, initialOpts ) : initialOpts;
3579    // init layout mode instance
3580    this.modes[ name ] = new Mode( this );
3581  };
3582
3583
3584  proto.layout = function() {
3585    // if first time doing layout, do all magic
3586    if ( !this._isLayoutInited && this._getOption('initLayout') ) {
3587      this.arrange();
3588      return;
3589    }
3590    this._layout();
3591  };
3592
3593  // private method to be used in layout() & magic()
3594  proto._layout = function() {
3595    // don't animate first layout
3596    var isInstant = this._getIsInstant();
3597    // layout flow
3598    this._resetLayout();
3599    this._manageStamps();
3600    this.layoutItems( this.filteredItems, isInstant );
3601
3602    // flag for initalized
3603    this._isLayoutInited = true;
3604  };
3605
3606  // filter + sort + layout
3607  proto.arrange = function( opts ) {
3608    // set any options pass
3609    this.option( opts );
3610    this._getIsInstant();
3611    // filter, sort, and layout
3612
3613    // filter
3614    var filtered = this._filter( this.items );
3615    this.filteredItems = filtered.matches;
3616
3617    this._bindArrangeComplete();
3618
3619    if ( this._isInstant ) {
3620      this._noTransition( this._hideReveal, [ filtered ] );
3621    } else {
3622      this._hideReveal( filtered );
3623    }
3624
3625    this._sort();
3626    this._layout();
3627  };
3628  // alias to _init for main plugin method
3629  proto._init = proto.arrange;
3630
3631  proto._hideReveal = function( filtered ) {
3632    this.reveal( filtered.needReveal );
3633    this.hide( filtered.needHide );
3634  };
3635
3636  // HACK
3637  // Don't animate/transition first layout
3638  // Or don't animate/transition other layouts
3639  proto._getIsInstant = function() {
3640    var isLayoutInstant = this._getOption('layoutInstant');
3641    var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
3642      !this._isLayoutInited;
3643    this._isInstant = isInstant;
3644    return isInstant;
3645  };
3646
3647  // listen for layoutComplete, hideComplete and revealComplete
3648  // to trigger arrangeComplete
3649  proto._bindArrangeComplete = function() {
3650    // listen for 3 events to trigger arrangeComplete
3651    var isLayoutComplete, isHideComplete, isRevealComplete;
3652    var _this = this;
3653    function arrangeParallelCallback() {
3654      if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
3655        _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
3656      }
3657    }
3658    this.once( 'layoutComplete', function() {
3659      isLayoutComplete = true;
3660      arrangeParallelCallback();
3661    });
3662    this.once( 'hideComplete', function() {
3663      isHideComplete = true;
3664      arrangeParallelCallback();
3665    });
3666    this.once( 'revealComplete', function() {
3667      isRevealComplete = true;
3668      arrangeParallelCallback();
3669    });
3670  };
3671
3672  // -------------------------- filter -------------------------- //
3673
3674  proto._filter = function( items ) {
3675    var filter = this.options.filter;
3676    filter = filter || '*';
3677    var matches = [];
3678    var hiddenMatched = [];
3679    var visibleUnmatched = [];
3680
3681    var test = this._getFilterTest( filter );
3682
3683    // test each item
3684    for ( var i=0; i < items.length; i++ ) {
3685      var item = items[i];
3686      if ( item.isIgnored ) {
3687        continue;
3688      }
3689      // add item to either matched or unmatched group
3690      var isMatched = test( item );
3691      // item.isFilterMatched = isMatched;
3692      // add to matches if its a match
3693      if ( isMatched ) {
3694        matches.push( item );
3695      }
3696      // add to additional group if item needs to be hidden or revealed
3697      if ( isMatched && item.isHidden ) {
3698        hiddenMatched.push( item );
3699      } else if ( !isMatched && !item.isHidden ) {
3700        visibleUnmatched.push( item );
3701      }
3702    }
3703
3704    // return collections of items to be manipulated
3705    return {
3706      matches: matches,
3707      needReveal: hiddenMatched,
3708      needHide: visibleUnmatched
3709    };
3710  };
3711
3712  // get a jQuery, function, or a matchesSelector test given the filter
3713  proto._getFilterTest = function( filter ) {
3714    if ( jQuery && this.options.isJQueryFiltering ) {
3715      // use jQuery
3716      return function( item ) {
3717        return jQuery( item.element ).is( filter );
3718      };
3719    }
3720    if ( typeof filter == 'function' ) {
3721      // use filter as function
3722      return function( item ) {
3723        return filter( item.element );
3724      };
3725    }
3726    // default, use filter as selector string
3727    return function( item ) {
3728      return matchesSelector( item.element, filter );
3729    };
3730  };
3731
3732  // -------------------------- sorting -------------------------- //
3733
3734  /**
3735   * @params {Array} elems
3736   * @public
3737   */
3738  proto.updateSortData = function( elems ) {
3739    // get items
3740    var items;
3741    if ( elems ) {
3742      elems = utils.makeArray( elems );
3743      items = this.getItems( elems );
3744    } else {
3745      // update all items if no elems provided
3746      items = this.items;
3747    }
3748
3749    this._getSorters();
3750    this._updateItemsSortData( items );
3751  };
3752
3753  proto._getSorters = function() {
3754    var getSortData = this.options.getSortData;
3755    for ( var key in getSortData ) {
3756      var sorter = getSortData[ key ];
3757      this._sorters[ key ] = mungeSorter( sorter );
3758    }
3759  };
3760
3761  /**
3762   * @params {Array} items - of Isotope.Items
3763   * @private
3764   */
3765  proto._updateItemsSortData = function( items ) {
3766    // do not update if no items
3767    var len = items && items.length;
3768
3769    for ( var i=0; len && i < len; i++ ) {
3770      var item = items[i];
3771      item.updateSortData();
3772    }
3773  };
3774
3775  // ----- munge sorter ----- //
3776
3777  // encapsulate this, as we just need mungeSorter
3778  // other functions in here are just for munging
3779  var mungeSorter = ( function() {
3780    // add a magic layer to sorters for convienent shorthands
3781    // `.foo-bar` will use the text of .foo-bar querySelector
3782    // `[foo-bar]` will use attribute
3783    // you can also add parser
3784    // `.foo-bar parseInt` will parse that as a number
3785    function mungeSorter( sorter ) {
3786      // if not a string, return function or whatever it is
3787      if ( typeof sorter != 'string' ) {
3788        return sorter;
3789      }
3790      // parse the sorter string
3791      var args = trim( sorter ).split(' ');
3792      var query = args[0];
3793      // check if query looks like [an-attribute]
3794      var attrMatch = query.match( /^\[(.+)\]$/ );
3795      var attr = attrMatch && attrMatch[1];
3796      var getValue = getValueGetter( attr, query );
3797      // use second argument as a parser
3798      var parser = Isotope.sortDataParsers[ args[1] ];
3799      // parse the value, if there was a parser
3800      sorter = parser ? function( elem ) {
3801        return elem && parser( getValue( elem ) );
3802      } :
3803      // otherwise just return value
3804      function( elem ) {
3805        return elem && getValue( elem );
3806      };
3807
3808      return sorter;
3809    }
3810
3811    // get an attribute getter, or get text of the querySelector
3812    function getValueGetter( attr, query ) {
3813      // if query looks like [foo-bar], get attribute
3814      if ( attr ) {
3815        return function getAttribute( elem ) {
3816          return elem.getAttribute( attr );
3817        };
3818      }
3819
3820      // otherwise, assume its a querySelector, and get its text
3821      return function getChildText( elem ) {
3822        var child = elem.querySelector( query );
3823        return child && child.textContent;
3824      };
3825    }
3826
3827    return mungeSorter;
3828  })();
3829
3830  // parsers used in getSortData shortcut strings
3831  Isotope.sortDataParsers = {
3832    'parseInt': function( val ) {
3833      return parseInt( val, 10 );
3834    },
3835    'parseFloat': function( val ) {
3836      return parseFloat( val );
3837    }
3838  };
3839
3840  // ----- sort method ----- //
3841
3842  // sort filteredItem order
3843  proto._sort = function() {
3844    if ( !this.options.sortBy ) {
3845      return;
3846    }
3847    // keep track of sortBy History
3848    var sortBys = utils.makeArray( this.options.sortBy );
3849    if ( !this._getIsSameSortBy( sortBys ) ) {
3850      // concat all sortBy and sortHistory, add to front, oldest goes in last
3851      this.sortHistory = sortBys.concat( this.sortHistory );
3852    }
3853    // sort magic
3854    var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending );
3855    this.filteredItems.sort( itemSorter );
3856  };
3857
3858  // check if sortBys is same as start of sortHistory
3859  proto._getIsSameSortBy = function( sortBys ) {
3860    for ( var i=0; i < sortBys.length; i++ ) {
3861      if ( sortBys[i] != this.sortHistory[i] ) {
3862        return false;
3863      }
3864    }
3865    return true;
3866  };
3867
3868  // returns a function used for sorting
3869  function getItemSorter( sortBys, sortAsc ) {
3870    return function sorter( itemA, itemB ) {
3871      // cycle through all sortKeys
3872      for ( var i = 0; i < sortBys.length; i++ ) {
3873        var sortBy = sortBys[i];
3874        var a = itemA.sortData[ sortBy ];
3875        var b = itemB.sortData[ sortBy ];
3876        if ( a > b || a < b ) {
3877          // if sortAsc is an object, use the value given the sortBy key
3878          var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
3879          var direction = isAscending ? 1 : -1;
3880          return ( a > b ? 1 : -1 ) * direction;
3881        }
3882      }
3883      return 0;
3884    };
3885  }
3886
3887  // -------------------------- methods -------------------------- //
3888
3889  // get layout mode
3890  proto._mode = function() {
3891    var layoutMode = this.options.layoutMode;
3892    var mode = this.modes[ layoutMode ];
3893    if ( !mode ) {
3894      // TODO console.error
3895      throw new Error( 'No layout mode: ' + layoutMode );
3896    }
3897    // HACK sync mode's options
3898    // any options set after init for layout mode need to be synced
3899    mode.options = this.options[ layoutMode ];
3900    return mode;
3901  };
3902
3903  proto._resetLayout = function() {
3904    // trigger original reset layout
3905    Outlayer.prototype._resetLayout.call( this );
3906    this._mode()._resetLayout();
3907  };
3908
3909  proto._getItemLayoutPosition = function( item  ) {
3910    return this._mode()._getItemLayoutPosition( item );
3911  };
3912
3913  proto._manageStamp = function( stamp ) {
3914    this._mode()._manageStamp( stamp );
3915  };
3916
3917  proto._getContainerSize = function() {
3918    return this._mode()._getContainerSize();
3919  };
3920
3921  proto.needsResizeLayout = function() {
3922    return this._mode().needsResizeLayout();
3923  };
3924
3925  // -------------------------- adding & removing -------------------------- //
3926
3927  // HEADS UP overwrites default Outlayer appended
3928  proto.appended = function( elems ) {
3929    var items = this.addItems( elems );
3930    if ( !items.length ) {
3931      return;
3932    }
3933    // filter, layout, reveal new items
3934    var filteredItems = this._filterRevealAdded( items );
3935    // add to filteredItems
3936    this.filteredItems = this.filteredItems.concat( filteredItems );
3937  };
3938
3939  // HEADS UP overwrites default Outlayer prepended
3940  proto.prepended = function( elems ) {
3941    var items = this._itemize( elems );
3942    if ( !items.length ) {
3943      return;
3944    }
3945    // start new layout
3946    this._resetLayout();
3947    this._manageStamps();
3948    // filter, layout, reveal new items
3949    var filteredItems = this._filterRevealAdded( items );
3950    // layout previous items
3951    this.layoutItems( this.filteredItems );
3952    // add to items and filteredItems
3953    this.filteredItems = filteredItems.concat( this.filteredItems );
3954    this.items = items.concat( this.items );
3955  };
3956
3957  proto._filterRevealAdded = function( items ) {
3958    var filtered = this._filter( items );
3959    this.hide( filtered.needHide );
3960    // reveal all new items
3961    this.reveal( filtered.matches );
3962    // layout new items, no transition
3963    this.layoutItems( filtered.matches, true );
3964    return filtered.matches;
3965  };
3966
3967  /**
3968   * Filter, sort, and layout newly-appended item elements
3969   * @param {Array or NodeList or Element} elems
3970   */
3971  proto.insert = function( elems ) {
3972    var items = this.addItems( elems );
3973    if ( !items.length ) {
3974      return;
3975    }
3976    // append item elements
3977    var i, item;
3978    var len = items.length;
3979    for ( i=0; i < len; i++ ) {
3980      item = items[i];
3981      this.element.appendChild( item.element );
3982    }
3983    // filter new stuff
3984    var filteredInsertItems = this._filter( items ).matches;
3985    // set flag
3986    for ( i=0; i < len; i++ ) {
3987      items[i].isLayoutInstant = true;
3988    }
3989    this.arrange();
3990    // reset flag
3991    for ( i=0; i < len; i++ ) {
3992      delete items[i].isLayoutInstant;
3993    }
3994    this.reveal( filteredInsertItems );
3995  };
3996
3997  var _remove = proto.remove;
3998  proto.remove = function( elems ) {
3999    elems = utils.makeArray( elems );
4000    var removeItems = this.getItems( elems );
4001    // do regular thing
4002    _remove.call( this, elems );
4003    // bail if no items to remove
4004    var len = removeItems && removeItems.length;
4005    // remove elems from filteredItems
4006    for ( var i=0; len && i < len; i++ ) {
4007      var item = removeItems[i];
4008      // remove item from collection
4009      utils.removeFrom( this.filteredItems, item );
4010    }
4011  };
4012
4013  proto.shuffle = function() {
4014    // update random sortData
4015    for ( var i=0; i < this.items.length; i++ ) {
4016      var item = this.items[i];
4017      item.sortData.random = Math.random();
4018    }
4019    this.options.sortBy = 'random';
4020    this._sort();
4021    this._layout();
4022  };
4023
4024  /**
4025   * trigger fn without transition
4026   * kind of hacky to have this in the first place
4027   * @param {Function} fn
4028   * @param {Array} args
4029   * @returns ret
4030   * @private
4031   */
4032  proto._noTransition = function( fn, args ) {
4033    // save transitionDuration before disabling
4034    var transitionDuration = this.options.transitionDuration;
4035    // disable transition
4036    this.options.transitionDuration = 0;
4037    // do it
4038    var returnValue = fn.apply( this, args );
4039    // re-enable transition for reveal
4040    this.options.transitionDuration = transitionDuration;
4041    return returnValue;
4042  };
4043
4044  // ----- helper methods ----- //
4045
4046  /**
4047   * getter method for getting filtered item elements
4048   * @returns {Array} elems - collection of item elements
4049   */
4050  proto.getFilteredItemElements = function() {
4051    return this.filteredItems.map( function( item ) {
4052      return item.element;
4053    });
4054  };
4055
4056  // -----  ----- //
4057
4058  return Isotope;
4059
4060}));
4061
4062
vendor: 31,440 bytes, lines 4063-5301
4063/*!
4064 * Packery layout mode PACKAGED v2.0.1
4065 * sub-classes Packery
4066 */
4067
4068/**
4069 * Rect
4070 * low-level utility class for basic geometry
4071 */
4072
4073( function( window, factory ) {
4074  // universal module definition
4075  /* jshint strict: false */ /* globals define, module */
4076  if ( typeof define == 'function' && define.amd ) {
4077    // AMD
4078    define( 'packery/js/rect',factory );
4079  } else if ( typeof module == 'object' && module.exports ) {
4080    // CommonJS
4081    module.exports = factory();
4082  } else {
4083    // browser global
4084    window.Packery = window.Packery || {};
4085    window.Packery.Rect = factory();
4086  }
4087
4088}( window, function factory() {
4089
4090
4091// -------------------------- Rect -------------------------- //
4092
4093function Rect( props ) {
4094  // extend properties from defaults
4095  for ( var prop in Rect.defaults ) {
4096    this[ prop ] = Rect.defaults[ prop ];
4097  }
4098
4099  for ( prop in props ) {
4100    this[ prop ] = props[ prop ];
4101  }
4102
4103}
4104
4105Rect.defaults = {
4106  x: 0,
4107  y: 0,
4108  width: 0,
4109  height: 0
4110};
4111
4112var proto = Rect.prototype;
4113
4114/**
4115 * Determines whether or not this rectangle wholly encloses another rectangle or point.
4116 * @param {Rect} rect
4117 * @returns {Boolean}
4118**/
4119proto.contains = function( rect ) {
4120  // points don't have width or height
4121  var otherWidth = rect.width || 0;
4122  var otherHeight = rect.height || 0;
4123  return this.x <= rect.x &&
4124    this.y <= rect.y &&
4125    this.x + this.width >= rect.x + otherWidth &&
4126    this.y + this.height >= rect.y + otherHeight;
4127};
4128
4129/**
4130 * Determines whether or not the rectangle intersects with another.
4131 * @param {Rect} rect
4132 * @returns {Boolean}
4133**/
4134proto.overlaps = function( rect ) {
4135  var thisRight = this.x + this.width;
4136  var thisBottom = this.y + this.height;
4137  var rectRight = rect.x + rect.width;
4138  var rectBottom = rect.y + rect.height;
4139
4140  // http://stackoverflow.com/a/306332
4141  return this.x < rectRight &&
4142    thisRight > rect.x &&
4143    this.y < rectBottom &&
4144    thisBottom > rect.y;
4145};
4146
4147/**
4148 * @param {Rect} rect - the overlapping rect
4149 * @returns {Array} freeRects - rects representing the area around the rect
4150**/
4151proto.getMaximalFreeRects = function( rect ) {
4152
4153  // if no intersection, return false
4154  if ( !this.overlaps( rect ) ) {
4155    return false;
4156  }
4157
4158  var freeRects = [];
4159  var freeRect;
4160
4161  var thisRight = this.x + this.width;
4162  var thisBottom = this.y + this.height;
4163  var rectRight = rect.x + rect.width;
4164  var rectBottom = rect.y + rect.height;
4165
4166  // top
4167  if ( this.y < rect.y ) {
4168    freeRect = new Rect({
4169      x: this.x,
4170      y: this.y,
4171      width: this.width,
4172      height: rect.y - this.y
4173    });
4174    freeRects.push( freeRect );
4175  }
4176
4177  // right
4178  if ( thisRight > rectRight ) {
4179    freeRect = new Rect({
4180      x: rectRight,
4181      y: this.y,
4182      width: thisRight - rectRight,
4183      height: this.height
4184    });
4185    freeRects.push( freeRect );
4186  }
4187
4188  // bottom
4189  if ( thisBottom > rectBottom ) {
4190    freeRect = new Rect({
4191      x: this.x,
4192      y: rectBottom,
4193      width: this.width,
4194      height: thisBottom - rectBottom
4195    });
4196    freeRects.push( freeRect );
4197  }
4198
4199  // left
4200  if ( this.x < rect.x ) {
4201    freeRect = new Rect({
4202      x: this.x,
4203      y: this.y,
4204      width: rect.x - this.x,
4205      height: this.height
4206    });
4207    freeRects.push( freeRect );
4208  }
4209
4210  return freeRects;
4211};
4212
4213proto.canFit = function( rect ) {
4214  return this.width >= rect.width && this.height >= rect.height;
4215};
4216
4217return Rect;
4218
4219}));
4220
4221/**
4222 * Packer
4223 * bin-packing algorithm
4224 */
4225
4226( function( window, factory ) {
4227  // universal module definition
4228  /* jshint strict: false */ /* globals define, module, require */
4229  if ( typeof define == 'function' && define.amd ) {
4230    // AMD
4231    define( 'packery/js/packer',[ './rect' ], factory );
4232  } else if ( typeof module == 'object' && module.exports ) {
4233    // CommonJS
4234    module.exports = factory(
4235      require('./rect')
4236    );
4237  } else {
4238    // browser global
4239    var Packery = window.Packery = window.Packery || {};
4240    Packery.Packer = factory( Packery.Rect );
4241  }
4242
4243}( window, function factory( Rect ) {
4244
4245
4246// -------------------------- Packer -------------------------- //
4247
4248/**
4249 * @param {Number} width
4250 * @param {Number} height
4251 * @param {String} sortDirection
4252 *   topLeft for vertical, leftTop for horizontal
4253 */
4254function Packer( width, height, sortDirection ) {
4255  this.width = width || 0;
4256  this.height = height || 0;
4257  this.sortDirection = sortDirection || 'downwardLeftToRight';
4258
4259  this.reset();
4260}
4261
4262var proto = Packer.prototype;
4263
4264proto.reset = function() {
4265  this.spaces = [];
4266
4267  var initialSpace = new Rect({
4268    x: 0,
4269    y: 0,
4270    width: this.width,
4271    height: this.height
4272  });
4273
4274  this.spaces.push( initialSpace );
4275  // set sorter
4276  this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
4277};
4278
4279// change x and y of rect to fit with in Packer's available spaces
4280proto.pack = function( rect ) {
4281  for ( var i=0; i < this.spaces.length; i++ ) {
4282    var space = this.spaces[i];
4283    if ( space.canFit( rect ) ) {
4284      this.placeInSpace( rect, space );
4285      break;
4286    }
4287  }
4288};
4289
4290proto.columnPack = function( rect ) {
4291  for ( var i=0; i < this.spaces.length; i++ ) {
4292    var space = this.spaces[i];
4293    var canFitInSpaceColumn = space.x <= rect.x &&
4294      space.x + space.width >= rect.x + rect.width &&
4295      space.height >= rect.height - 0.01; // fudge number for rounding error
4296    if ( canFitInSpaceColumn ) {
4297      rect.y = space.y;
4298      this.placed( rect );
4299      break;
4300    }
4301  }
4302};
4303
4304proto.rowPack = function( rect ) {
4305  for ( var i=0; i < this.spaces.length; i++ ) {
4306    var space = this.spaces[i];
4307    var canFitInSpaceRow = space.y <= rect.y &&
4308      space.y + space.height >= rect.y + rect.height &&
4309      space.width >= rect.width - 0.01; // fudge number for rounding error
4310    if ( canFitInSpaceRow ) {
4311      rect.x = space.x;
4312      this.placed( rect );
4313      break;
4314    }
4315  }
4316};
4317
4318proto.placeInSpace = function( rect, space ) {
4319  // place rect in space
4320  rect.x = space.x;
4321  rect.y = space.y;
4322
4323  this.placed( rect );
4324};
4325
4326// update spaces with placed rect
4327proto.placed = function( rect ) {
4328  // update spaces
4329  var revisedSpaces = [];
4330  for ( var i=0; i < this.spaces.length; i++ ) {
4331    var space = this.spaces[i];
4332    var newSpaces = space.getMaximalFreeRects( rect );
4333    // add either the original space or the new spaces to the revised spaces
4334    if ( newSpaces ) {
4335      revisedSpaces.push.apply( revisedSpaces, newSpaces );
4336    } else {
4337      revisedSpaces.push( space );
4338    }
4339  }
4340
4341  this.spaces = revisedSpaces;
4342
4343  this.mergeSortSpaces();
4344};
4345
4346proto.mergeSortSpaces = function() {
4347  // remove redundant spaces
4348  Packer.mergeRects( this.spaces );
4349  this.spaces.sort( this.sorter );
4350};
4351
4352// add a space back
4353proto.addSpace = function( rect ) {
4354  this.spaces.push( rect );
4355  this.mergeSortSpaces();
4356};
4357
4358// -------------------------- utility functions -------------------------- //
4359
4360/**
4361 * Remove redundant rectangle from array of rectangles
4362 * @param {Array} rects: an array of Rects
4363 * @returns {Array} rects: an array of Rects
4364**/
4365Packer.mergeRects = function( rects ) {
4366  var i = 0;
4367  var rect = rects[i];
4368
4369  rectLoop:
4370  while ( rect ) {
4371    var j = 0;
4372    var compareRect = rects[ i + j ];
4373
4374    while ( compareRect ) {
4375      if  ( compareRect == rect ) {
4376        j++; // next
4377      } else if ( compareRect.contains( rect ) ) {
4378        // remove rect
4379        rects.splice( i, 1 );
4380        rect = rects[i]; // set next rect
4381        continue rectLoop; // bail on compareLoop
4382      } else if ( rect.contains( compareRect ) ) {
4383        // remove compareRect
4384        rects.splice( i + j, 1 );
4385      } else {
4386        j++;
4387      }
4388      compareRect = rects[ i + j ]; // set next compareRect
4389    }
4390    i++;
4391    rect = rects[i];
4392  }
4393
4394  return rects;
4395};
4396
4397
4398// -------------------------- sorters -------------------------- //
4399
4400// functions for sorting rects in order
4401var sorters = {
4402  // top down, then left to right
4403  downwardLeftToRight: function( a, b ) {
4404    return a.y - b.y || a.x - b.x;
4405  },
4406  // left to right, then top down
4407  rightwardTopToBottom: function( a, b ) {
4408    return a.x - b.x || a.y - b.y;
4409  }
4410};
4411
4412
4413// --------------------------  -------------------------- //
4414
4415return Packer;
4416
4417}));
4418
4419/**
4420 * Packery Item Element
4421**/
4422
4423( function( window, factory ) {
4424  // universal module definition
4425  /* jshint strict: false */ /* globals define, module, require */
4426  if ( typeof define == 'function' && define.amd ) {
4427    // AMD
4428    define( 'packery/js/item',[
4429        'outlayer/outlayer',
4430        './rect'
4431      ],
4432      factory );
4433  } else if ( typeof module == 'object' && module.exports ) {
4434    // CommonJS
4435    module.exports = factory(
4436      require('outlayer'),
4437      require('./rect')
4438    );
4439  } else {
4440    // browser global
4441    window.Packery.Item = factory(
4442      window.Outlayer,
4443      window.Packery.Rect
4444    );
4445  }
4446
4447}( window, function factory( Outlayer, Rect ) {
4448
4449
4450// -------------------------- Item -------------------------- //
4451
4452var docElemStyle = document.documentElement.style;
4453
4454var transformProperty = typeof docElemStyle.transform == 'string' ?
4455  'transform' : 'WebkitTransform';
4456
4457// sub-class Item
4458var Item = function PackeryItem() {
4459  Outlayer.Item.apply( this, arguments );
4460};
4461
4462var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
4463
4464var __create = proto._create;
4465proto._create = function() {
4466  // call default _create logic
4467  __create.call( this );
4468  this.rect = new Rect();
4469};
4470
4471var _moveTo = proto.moveTo;
4472proto.moveTo = function( x, y ) {
4473  // don't shift 1px while dragging
4474  var dx = Math.abs( this.position.x - x );
4475  var dy = Math.abs( this.position.y - y );
4476
4477  var canHackGoTo = this.layout.dragItemCount && !this.isPlacing &&
4478    !this.isTransitioning && dx < 1 && dy < 1;
4479  if ( canHackGoTo ) {
4480    this.goTo( x, y );
4481    return;
4482  }
4483  _moveTo.apply( this, arguments );
4484};
4485
4486// -------------------------- placing -------------------------- //
4487
4488proto.enablePlacing = function() {
4489  this.removeTransitionStyles();
4490  // remove transform property from transition
4491  if ( this.isTransitioning && transformProperty ) {
4492    this.element.style[ transformProperty ] = 'none';
4493  }
4494  this.isTransitioning = false;
4495  this.getSize();
4496  this.layout._setRectSize( this.element, this.rect );
4497  this.isPlacing = true;
4498};
4499
4500proto.disablePlacing = function() {
4501  this.isPlacing = false;
4502};
4503
4504// -----  ----- //
4505
4506// remove element from DOM
4507proto.removeElem = function() {
4508  this.element.parentNode.removeChild( this.element );
4509  // add space back to packer
4510  this.layout.packer.addSpace( this.rect );
4511  this.emitEvent( 'remove', [ this ] );
4512};
4513
4514// ----- dropPlaceholder ----- //
4515
4516proto.showDropPlaceholder = function() {
4517  var dropPlaceholder = this.dropPlaceholder;
4518  if ( !dropPlaceholder ) {
4519    // create dropPlaceholder
4520    dropPlaceholder = this.dropPlaceholder = document.createElement('div');
4521    dropPlaceholder.className = 'packery-drop-placeholder';
4522    dropPlaceholder.style.position = 'absolute';
4523  }
4524
4525  dropPlaceholder.style.width = this.size.width + 'px';
4526  dropPlaceholder.style.height = this.size.height + 'px';
4527  this.positionDropPlaceholder();
4528  this.layout.element.appendChild( dropPlaceholder );
4529};
4530
4531proto.positionDropPlaceholder = function() {
4532  this.dropPlaceholder.style[ transformProperty ] = 'translate(' +
4533    this.rect.x + 'px, ' + this.rect.y + 'px)';
4534};
4535
4536proto.hideDropPlaceholder = function() {
4537  this.layout.element.removeChild( this.dropPlaceholder );
4538};
4539
4540// -----  ----- //
4541
4542return Item;
4543
4544}));
4545
4546/*!
4547 * Packery v2.0.0
4548 * Gapless, draggable grid layouts
4549 *
4550 * Licensed GPLv3 for open source use
4551 * or Packery Commercial License for commercial use
4552 *
4553 * http://packery.metafizzy.co
4554 * Copyright 2016 Metafizzy
4555 */
4556
4557( function( window, factory ) {
4558  // universal module definition
4559  /* jshint strict: false */ /* globals define, module, require */
4560  if ( typeof define == 'function' && define.amd ) {
4561    // AMD
4562    define( 'packery/js/packery',[
4563        'get-size/get-size',
4564        'outlayer/outlayer',
4565        './rect',
4566        './packer',
4567        './item'
4568      ],
4569      factory );
4570  } else if ( typeof module == 'object' && module.exports ) {
4571    // CommonJS
4572    module.exports = factory(
4573      require('get-size'),
4574      require('outlayer'),
4575      require('./rect'),
4576      require('./packer'),
4577      require('./item')
4578    );
4579  } else {
4580    // browser global
4581    window.Packery = factory(
4582      window.getSize,
4583      window.Outlayer,
4584      window.Packery.Rect,
4585      window.Packery.Packer,
4586      window.Packery.Item
4587    );
4588  }
4589
4590}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) {
4591
4592
4593// ----- Rect ----- //
4594
4595// allow for pixel rounding errors IE8-IE11 & Firefox; #227
4596Rect.prototype.canFit = function( rect ) {
4597  return this.width >= rect.width - 1 && this.height >= rect.height - 1;
4598};
4599
4600// -------------------------- Packery -------------------------- //
4601
4602// create an Outlayer layout class
4603var Packery = Outlayer.create('packery');
4604Packery.Item = Item;
4605
4606var proto = Packery.prototype;
4607
4608proto._create = function() {
4609  // call super
4610  Outlayer.prototype._create.call( this );
4611
4612  // initial properties
4613  this.packer = new Packer();
4614  // packer for drop targets
4615  this.shiftPacker = new Packer();
4616  this.isEnabled = true;
4617
4618  this.dragItemCount = 0;
4619
4620  // create drag handlers
4621  var _this = this;
4622  this.handleDraggabilly = {
4623    dragStart: function() {
4624      _this.itemDragStart( this.element );
4625    },
4626    dragMove: function() {
4627      _this.itemDragMove( this.element, this.position.x, this.position.y );
4628    },
4629    dragEnd: function() {
4630      _this.itemDragEnd( this.element );
4631    }
4632  };
4633
4634  this.handleUIDraggable = {
4635    start: function handleUIDraggableStart( event, ui ) {
4636      // HTML5 may trigger dragstart, dismiss HTML5 dragging
4637      if ( !ui ) {
4638        return;
4639      }
4640      _this.itemDragStart( event.currentTarget );
4641    },
4642    drag: function handleUIDraggableDrag( event, ui ) {
4643      if ( !ui ) {
4644        return;
4645      }
4646      _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
4647    },
4648    stop: function handleUIDraggableStop( event, ui ) {
4649      if ( !ui ) {
4650        return;
4651      }
4652      _this.itemDragEnd( event.currentTarget );
4653    }
4654  };
4655
4656};
4657
4658
4659// ----- init & layout ----- //
4660
4661/**
4662 * logic before any new layout
4663 */
4664proto._resetLayout = function() {
4665  this.getSize();
4666
4667  this._getMeasurements();
4668
4669  // reset packer
4670  var width, height, sortDirection;
4671  // packer settings, if horizontal or vertical
4672  if ( this._getOption('horizontal') ) {
4673    width = Infinity;
4674    height = this.size.innerHeight + this.gutter;
4675    sortDirection = 'rightwardTopToBottom';
4676  } else {
4677    width = this.size.innerWidth + this.gutter;
4678    height = Infinity;
4679    sortDirection = 'downwardLeftToRight';
4680  }
4681
4682  this.packer.width = this.shiftPacker.width = width;
4683  this.packer.height = this.shiftPacker.height = height;
4684  this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection;
4685
4686  this.packer.reset();
4687
4688  // layout
4689  this.maxY = 0;
4690  this.maxX = 0;
4691};
4692
4693/**
4694 * update columnWidth, rowHeight, & gutter
4695 * @private
4696 */
4697proto._getMeasurements = function() {
4698  this._getMeasurement( 'columnWidth', 'width' );
4699  this._getMeasurement( 'rowHeight', 'height' );
4700  this._getMeasurement( 'gutter', 'width' );
4701};
4702
4703proto._getItemLayoutPosition = function( item ) {
4704  this._setRectSize( item.element, item.rect );
4705  if ( this.isShifting || this.dragItemCount > 0 ) {
4706    var packMethod = this._getPackMethod();
4707    this.packer[ packMethod ]( item.rect );
4708  } else {
4709    this.packer.pack( item.rect );
4710  }
4711
4712  this._setMaxXY( item.rect );
4713  return item.rect;
4714};
4715
4716proto.shiftLayout = function() {
4717  this.isShifting = true;
4718  this.layout();
4719  delete this.isShifting;
4720};
4721
4722proto._getPackMethod = function() {
4723  return this._getOption('horizontal') ? 'rowPack' : 'columnPack';
4724};
4725
4726
4727/**
4728 * set max X and Y value, for size of container
4729 * @param {Packery.Rect} rect
4730 * @private
4731 */
4732proto._setMaxXY = function( rect ) {
4733  this.maxX = Math.max( rect.x + rect.width, this.maxX );
4734  this.maxY = Math.max( rect.y + rect.height, this.maxY );
4735};
4736
4737/**
4738 * set the width and height of a rect, applying columnWidth and rowHeight
4739 * @param {Element} elem
4740 * @param {Packery.Rect} rect
4741 */
4742proto._setRectSize = function( elem, rect ) {
4743  var size = getSize( elem );
4744  var w = size.outerWidth;
4745  var h = size.outerHeight;
4746  // size for columnWidth and rowHeight, if available
4747  // only check if size is non-zero, #177
4748  if ( w || h ) {
4749    w = this._applyGridGutter( w, this.columnWidth );
4750    h = this._applyGridGutter( h, this.rowHeight );
4751  }
4752  // rect must fit in packer
4753  rect.width = Math.min( w, this.packer.width );
4754  rect.height = Math.min( h, this.packer.height );
4755};
4756
4757/**
4758 * fits item to columnWidth/rowHeight and adds gutter
4759 * @param {Number} measurement - item width or height
4760 * @param {Number} gridSize - columnWidth or rowHeight
4761 * @returns measurement
4762 */
4763proto._applyGridGutter = function( measurement, gridSize ) {
4764  // just add gutter if no gridSize
4765  if ( !gridSize ) {
4766    return measurement + this.gutter;
4767  }
4768  gridSize += this.gutter;
4769  // fit item to columnWidth/rowHeight
4770  var remainder = measurement % gridSize;
4771  var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
4772  measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize;
4773  return measurement;
4774};
4775
4776proto._getContainerSize = function() {
4777  if ( this._getOption('horizontal') ) {
4778    return {
4779      width: this.maxX - this.gutter
4780    };
4781  } else {
4782    return {
4783      height: this.maxY - this.gutter
4784    };
4785  }
4786};
4787
4788
4789// -------------------------- stamp -------------------------- //
4790
4791/**
4792 * makes space for element
4793 * @param {Element} elem
4794 */
4795proto._manageStamp = function( elem ) {
4796
4797  var item = this.getItem( elem );
4798  var rect;
4799  if ( item && item.isPlacing ) {
4800    rect = item.rect;
4801  } else {
4802    var offset = this._getElementOffset( elem );
4803    rect = new Rect({
4804      x: this._getOption('originLeft') ? offset.left : offset.right,
4805      y: this._getOption('originTop') ? offset.top : offset.bottom
4806    });
4807  }
4808
4809  this._setRectSize( elem, rect );
4810  // save its space in the packer
4811  this.packer.placed( rect );
4812  this._setMaxXY( rect );
4813};
4814
4815// -------------------------- methods -------------------------- //
4816
4817function verticalSorter( a, b ) {
4818  return a.position.y - b.position.y || a.position.x - b.position.x;
4819}
4820
4821function horizontalSorter( a, b ) {
4822  return a.position.x - b.position.x || a.position.y - b.position.y;
4823}
4824
4825proto.sortItemsByPosition = function() {
4826  var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter;
4827  this.items.sort( sorter );
4828};
4829
4830/**
4831 * Fit item element in its current position
4832 * Packery will position elements around it
4833 * useful for expanding elements
4834 *
4835 * @param {Element} elem
4836 * @param {Number} x - horizontal destination position, optional
4837 * @param {Number} y - vertical destination position, optional
4838 */
4839proto.fit = function( elem, x, y ) {
4840  var item = this.getItem( elem );
4841  if ( !item ) {
4842    return;
4843  }
4844
4845  // stamp item to get it out of layout
4846  this.stamp( item.element );
4847  // set placing flag
4848  item.enablePlacing();
4849  this.updateShiftTargets( item );
4850  // fall back to current position for fitting
4851  x = x === undefined ? item.rect.x: x;
4852  y = y === undefined ? item.rect.y: y;
4853  // position it best at its destination
4854  this.shift( item, x, y );
4855  this._bindFitEvents( item );
4856  item.moveTo( item.rect.x, item.rect.y );
4857  // layout everything else
4858  this.shiftLayout();
4859  // return back to regularly scheduled programming
4860  this.unstamp( item.element );
4861  this.sortItemsByPosition();
4862  item.disablePlacing();
4863};
4864
4865/**
4866 * emit event when item is fit and other items are laid out
4867 * @param {Packery.Item} item
4868 * @private
4869 */
4870proto._bindFitEvents = function( item ) {
4871  var _this = this;
4872  var ticks = 0;
4873  function onLayout() {
4874    ticks++;
4875    if ( ticks != 2 ) {
4876      return;
4877    }
4878    _this.dispatchEvent( 'fitComplete', null, [ item ] );
4879  }
4880  // when item is laid out
4881  item.once( 'layout', onLayout );
4882  // when all items are laid out
4883  this.once( 'layoutComplete', onLayout );
4884};
4885
4886// -------------------------- resize -------------------------- //
4887
4888// debounced, layout on resize
4889proto.resize = function() {
4890  // don't trigger if size did not change
4891  // or if resize was unbound. See #285, outlayer#9
4892  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
4893    return;
4894  }
4895
4896  if ( this.options.shiftPercentResize ) {
4897    this.resizeShiftPercentLayout();
4898  } else {
4899    this.layout();
4900  }
4901};
4902
4903/**
4904 * check if layout is needed post layout
4905 * @returns Boolean
4906 */
4907proto.needsResizeLayout = function() {
4908  var size = getSize( this.element );
4909  var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth';
4910  return size[ innerSize ] != this.size[ innerSize ];
4911};
4912
4913proto.resizeShiftPercentLayout = function() {
4914  var items = this._getItemsForLayout( this.items );
4915
4916  var isHorizontal = this._getOption('horizontal');
4917  var coord = isHorizontal ? 'y' : 'x';
4918  var measure = isHorizontal ? 'height' : 'width';
4919  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
4920  var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth';
4921
4922  // proportional re-align items
4923  var previousSegment = this[ segmentName ];
4924  previousSegment = previousSegment && previousSegment + this.gutter;
4925
4926  if ( previousSegment ) {
4927    this._getMeasurements();
4928    var currentSegment = this[ segmentName ] + this.gutter;
4929    items.forEach( function( item ) {
4930      var seg = Math.round( item.rect[ coord ] / previousSegment );
4931      item.rect[ coord ] = seg * currentSegment;
4932    });
4933  } else {
4934    var currentSize = getSize( this.element )[ innerSize ] + this.gutter;
4935    var previousSize = this.packer[ measure ];
4936    items.forEach( function( item ) {
4937      item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize;
4938    });
4939  }
4940
4941  this.shiftLayout();
4942};
4943
4944// -------------------------- drag -------------------------- //
4945
4946/**
4947 * handle an item drag start event
4948 * @param {Element} elem
4949 */
4950proto.itemDragStart = function( elem ) {
4951  if ( !this.isEnabled ) {
4952    return;
4953  }
4954  this.stamp( elem );
4955  // this.ignore( elem );
4956  var item = this.getItem( elem );
4957  if ( !item ) {
4958    return;
4959  }
4960
4961  item.enablePlacing();
4962  item.showDropPlaceholder();
4963  this.dragItemCount++;
4964  this.updateShiftTargets( item );
4965};
4966
4967proto.updateShiftTargets = function( dropItem ) {
4968  this.shiftPacker.reset();
4969
4970  // pack stamps
4971  this._getBoundingRect();
4972  var isOriginLeft = this._getOption('originLeft');
4973  var isOriginTop = this._getOption('originTop');
4974  this.stamps.forEach( function( stamp ) {
4975    // ignore dragged item
4976    var item = this.getItem( stamp );
4977    if ( item && item.isPlacing ) {
4978      return;
4979    }
4980    var offset = this._getElementOffset( stamp );
4981    var rect = new Rect({
4982      x: isOriginLeft ? offset.left : offset.right,
4983      y: isOriginTop ? offset.top : offset.bottom
4984    });
4985    this._setRectSize( stamp, rect );
4986    // save its space in the packer
4987    this.shiftPacker.placed( rect );
4988  }, this );
4989
4990  // reset shiftTargets
4991  var isHorizontal = this._getOption('horizontal');
4992  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
4993  var measure = isHorizontal ? 'height' : 'width';
4994
4995  this.shiftTargetKeys = [];
4996  this.shiftTargets = [];
4997  var boundsSize;
4998  var segment = this[ segmentName ];
4999  segment = segment && segment + this.gutter;
5000
5001  if ( segment ) {
5002    var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment );
5003    var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment );
5004    boundsSize = ( segs - segmentSpan ) * segment;
5005    // add targets on top
5006    for ( var i=0; i < segs; i++ ) {
5007      this._addShiftTarget( i * segment, 0, boundsSize );
5008    }
5009  } else {
5010    boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ];
5011    this._addShiftTarget( 0, 0, boundsSize );
5012  }
5013
5014  // pack each item to measure where shiftTargets are
5015  var items = this._getItemsForLayout( this.items );
5016  var packMethod = this._getPackMethod();
5017  items.forEach( function( item ) {
5018    var rect = item.rect;
5019    this._setRectSize( item.element, rect );
5020    this.shiftPacker[ packMethod ]( rect );
5021
5022    // add top left corner
5023    this._addShiftTarget( rect.x, rect.y, boundsSize );
5024    // add bottom left / top right corner
5025    var cornerX = isHorizontal ? rect.x + rect.width : rect.x;
5026    var cornerY = isHorizontal ? rect.y : rect.y + rect.height;
5027    this._addShiftTarget( cornerX, cornerY, boundsSize );
5028
5029    if ( segment ) {
5030      // add targets for each column on bottom / row on right
5031      var segSpan = Math.round( rect[ measure ] / segment );
5032      for ( var i=1; i < segSpan; i++ ) {
5033        var segX = isHorizontal ? cornerX : rect.x + segment * i;
5034        var segY = isHorizontal ? rect.y + segment * i : cornerY;
5035        this._addShiftTarget( segX, segY, boundsSize );
5036      }
5037    }
5038  }, this );
5039
5040};
5041
5042proto._addShiftTarget = function( x, y, boundsSize ) {
5043  var checkCoord = this._getOption('horizontal') ? y : x;
5044  if ( checkCoord !== 0 && checkCoord > boundsSize ) {
5045    return;
5046  }
5047  // create string for a key, easier to keep track of what targets
5048  var key = x + ',' + y;
5049  var hasKey = this.shiftTargetKeys.indexOf( key ) != -1;
5050  if ( hasKey ) {
5051    return;
5052  }
5053  this.shiftTargetKeys.push( key );
5054  this.shiftTargets.push({ x: x, y: y });
5055};
5056
5057// -------------------------- drop -------------------------- //
5058
5059proto.shift = function( item, x, y ) {
5060  var shiftPosition;
5061  var minDistance = Infinity;
5062  var position = { x: x, y: y };
5063  this.shiftTargets.forEach( function( target ) {
5064    var distance = getDistance( target, position );
5065    if ( distance < minDistance ) {
5066      shiftPosition = target;
5067      minDistance = distance;
5068    }
5069  });
5070  item.rect.x = shiftPosition.x;
5071  item.rect.y = shiftPosition.y;
5072};
5073
5074function getDistance( a, b ) {
5075  var dx = b.x - a.x;
5076  var dy = b.y - a.y;
5077  return Math.sqrt( dx * dx + dy * dy );
5078}
5079
5080// -------------------------- drag move -------------------------- //
5081
5082var DRAG_THROTTLE_TIME = 120;
5083
5084/**
5085 * handle an item drag move event
5086 * @param {Element} elem
5087 * @param {Number} x - horizontal change in position
5088 * @param {Number} y - vertical change in position
5089 */
5090proto.itemDragMove = function( elem, x, y ) {
5091  var item = this.isEnabled && this.getItem( elem );
5092  if ( !item ) {
5093    return;
5094  }
5095
5096  x -= this.size.paddingLeft;
5097  y -= this.size.paddingTop;
5098
5099  var _this = this;
5100  function onDrag() {
5101    _this.shift( item, x, y );
5102    item.positionDropPlaceholder();
5103    _this.layout();
5104  }
5105
5106  // throttle
5107  var now = new Date();
5108  if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) {
5109    clearTimeout( this.dragTimeout );
5110    this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME );
5111  } else {
5112    onDrag();
5113    this._itemDragTime = now;
5114  }
5115};
5116
5117// -------------------------- drag end -------------------------- //
5118
5119/**
5120 * handle an item drag end event
5121 * @param {Element} elem
5122 */
5123proto.itemDragEnd = function( elem ) {
5124  var item = this.isEnabled && this.getItem( elem );
5125  if ( !item ) {
5126    return;
5127  }
5128
5129  clearTimeout( this.dragTimeout );
5130  item.element.classList.add('is-positioning-post-drag');
5131
5132  var completeCount = 0;
5133  var _this = this;
5134  function onDragEndLayoutComplete() {
5135    completeCount++;
5136    if ( completeCount != 2 ) {
5137      return;
5138    }
5139    // reset drag item
5140    item.element.classList.remove('is-positioning-post-drag');
5141    item.hideDropPlaceholder();
5142    _this.dispatchEvent( 'dragItemPositioned', null, [ item ] );
5143  }
5144
5145  item.once( 'layout', onDragEndLayoutComplete );
5146  this.once( 'layoutComplete', onDragEndLayoutComplete );
5147  item.moveTo( item.rect.x, item.rect.y );
5148  this.layout();
5149  this.dragItemCount = Math.max( 0, this.dragItemCount - 1 );
5150  this.sortItemsByPosition();
5151  item.disablePlacing();
5152  this.unstamp( item.element );
5153};
5154
5155/**
5156 * binds Draggabilly events
5157 * @param {Draggabilly} draggie
5158 */
5159proto.bindDraggabillyEvents = function( draggie ) {
5160  this._bindDraggabillyEvents( draggie, 'on' );
5161};
5162
5163proto.unbindDraggabillyEvents = function( draggie ) {
5164  this._bindDraggabillyEvents( draggie, 'off' );
5165};
5166
5167proto._bindDraggabillyEvents = function( draggie, method ) {
5168  var handlers = this.handleDraggabilly;
5169  draggie[ method ]( 'dragStart', handlers.dragStart );
5170  draggie[ method ]( 'dragMove', handlers.dragMove );
5171  draggie[ method ]( 'dragEnd', handlers.dragEnd );
5172};
5173
5174/**
5175 * binds jQuery UI Draggable events
5176 * @param {jQuery} $elems
5177 */
5178proto.bindUIDraggableEvents = function( $elems ) {
5179  this._bindUIDraggableEvents( $elems, 'on' );
5180};
5181
5182proto.unbindUIDraggableEvents = function( $elems ) {
5183  this._bindUIDraggableEvents( $elems, 'off' );
5184};
5185
5186proto._bindUIDraggableEvents = function( $elems, method ) {
5187  var handlers = this.handleUIDraggable;
5188  $elems
5189    [ method ]( 'dragstart', handlers.start )
5190    [ method ]( 'drag', handlers.drag )
5191    [ method ]( 'dragstop', handlers.stop );
5192};
5193
5194// ----- destroy ----- //
5195
5196var _destroy = proto.destroy;
5197proto.destroy = function() {
5198  _destroy.apply( this, arguments );
5199  // disable flag; prevent drag events from triggering. #72
5200  this.isEnabled = false;
5201};
5202
5203// -----  ----- //
5204
5205Packery.Rect = Rect;
5206Packery.Packer = Packer;
5207
5208return Packery;
5209
5210}));
5211
5212/*!
5213 * Packery layout mode v2.0.1
5214 * sub-classes Packery
5215 */
5216
5217/*jshint browser: true, strict: true, undef: true, unused: true */
5218
5219( function( window, factory ) {
5220  
5221  // universal module definition
5222  if ( typeof define == 'function' && define.amd ) {
5223    // AMD
5224    define( [
5225        'isotope-layout/js/layout-mode',
5226        'packery/js/packery'
5227      ],
5228      factory );
5229  } else if ( typeof module == 'object' && module.exports ) {
5230    // CommonJS
5231    module.exports = factory(
5232      require('isotope-layout/js/layout-mode'),
5233      require('packery')
5234    );
5235  } else {
5236    // browser global
5237    factory(
5238      window.Isotope.LayoutMode,
5239      window.Packery
5240    );
5241  }
5242
5243}( window, function factor( LayoutMode, Packery ) {
5244
5245
5246  // create an Outlayer layout class
5247  var PackeryMode = LayoutMode.create('packery');
5248  var proto = PackeryMode.prototype;
5249
5250  var keepModeMethods = {
5251    _getElementOffset: true,
5252    _getMeasurement: true
5253  };
5254
5255  // inherit Packery prototype
5256  for ( var method in Packery.prototype ) {
5257    // do not inherit mode methods
5258    if ( !keepModeMethods[ method ] ) {
5259      proto[ method ] = Packery.prototype[ method ];
5260    }
5261  }
5262
5263  // set packer in _resetLayout
5264  var _resetLayout = proto._resetLayout;
5265  proto._resetLayout = function() {
5266    this.packer = this.packer || new Packery.Packer();
5267    this.shiftPacker = this.shiftPacker || new Packery.Packer();
5268    _resetLayout.apply( this, arguments );
5269  };
5270
5271  var _getItemLayoutPosition = proto._getItemLayoutPosition;
5272  proto._getItemLayoutPosition = function( item ) {
5273    // set packery rect
5274    item.rect = item.rect || new Packery.Rect();
5275    return _getItemLayoutPosition.call( this, item );
5276  };
5277
5278  // needsResizeLayout for vertical or horizontal
5279  var _needsResizeLayout = proto.needsResizeLayout;
5280  proto.needsResizeLayout = function() {
5281    if ( this._getOption('horizontal') ) {
5282      return this.needsVerticalResizeLayout();
5283    } else {
5284      return _needsResizeLayout.call( this );
5285    }
5286  };
5287
5288  // point to mode options for horizontal
5289  var _getOption = proto._getOption;
5290  proto._getOption = function( option ) {
5291    if ( option == 'horizontal' ) {
5292      return this.options.isHorizontal !== undefined ?
5293        this.options.isHorizontal : this.options.horizontal;
5294    }
5295    return _getOption.apply( this.isotope, arguments );
5296  };
5297
5298  return PackeryMode;
5299
5300}));
5301
vendor: 9,043 bytes, lines 5302-5653
5302
5303/*!
5304 * Packery PACKAGED v2.1.2
5305 * Gapless, draggable grid layouts
5306 *
5307 * Licensed GPLv3 for open source use
5308 * or Packery Commercial License for commercial use
5309 *
5310 * http://packery.metafizzy.co
5311 * Copyright 2013-2018 Metafizzy
5312 */
5313
5314/**
5315 * Bridget makes jQuery widgets
5316 * v2.0.1
5317 * MIT license
5318 */
5319
5320/* jshint browser: true, strict: true, undef: true, unused: true */
5321
5322( function( window, factory ) {
5323  // universal module definition
5324  /*jshint strict: false */ /* globals define, module, require */
5325  if ( typeof define == 'function' && define.amd ) {
5326    // AMD
5327    define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
5328      return factory( window, jQuery );
5329    });
5330  } else if ( typeof module == 'object' && module.exports ) {
5331    // CommonJS
5332    module.exports = factory(
5333      window,
5334      require('jquery')
5335    );
5336  } else {
5337    // browser global
5338    window.jQueryBridget = factory(
5339      window,
5340      window.jQuery
5341    );
5342  }
5343
5344}( window, function factory( window, jQuery ) {
5345'use strict';
5346
5347// ----- utils ----- //
5348
5349var arraySlice = Array.prototype.slice;
5350
5351// helper function for logging errors
5352// $.error breaks jQuery chaining
5353var console = window.console;
5354var logError = typeof console == 'undefined' ? function() {} :
5355  function( message ) {
5356    console.error( message );
5357  };
5358
5359// ----- jQueryBridget ----- //
5360
5361function jQueryBridget( namespace, PluginClass, $ ) {
5362  $ = $ || jQuery || window.jQuery;
5363  if ( !$ ) {
5364    return;
5365  }
5366
5367  // add option method -> $().plugin('option', {...})
5368  if ( !PluginClass.prototype.option ) {
5369    // option setter
5370    PluginClass.prototype.option = function( opts ) {
5371      // bail out if not an object
5372      if ( !$.isPlainObject( opts ) ){
5373        return;
5374      }
5375      this.options = $.extend( true, this.options, opts );
5376    };
5377  }
5378
5379  // make jQuery plugin
5380  $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
5381    if ( typeof arg0 == 'string' ) {
5382      // method call $().plugin( 'methodName', { options } )
5383      // shift arguments by 1
5384      var args = arraySlice.call( arguments, 1 );
5385      return methodCall( this, arg0, args );
5386    }
5387    // just $().plugin({ options })
5388    plainCall( this, arg0 );
5389    return this;
5390  };
5391
5392  // $().plugin('methodName')
5393  function methodCall( $elems, methodName, args ) {
5394    var returnValue;
5395    var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
5396
5397    $elems.each( function( i, elem ) {
5398      // get instance
5399      var instance = $.data( elem, namespace );
5400      if ( !instance ) {
5401        logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
5402          pluginMethodStr );
5403        return;
5404      }
5405
5406      var method = instance[ methodName ];
5407      if ( !method || methodName.charAt(0) == '_' ) {
5408        logError( pluginMethodStr + ' is not a valid method' );
5409        return;
5410      }
5411
5412      // apply method, get return value
5413      var value = method.apply( instance, args );
5414      // set return value if value is returned, use only first value
5415      returnValue = returnValue === undefined ? value : returnValue;
5416    });
5417
5418    return returnValue !== undefined ? returnValue : $elems;
5419  }
5420
5421  function plainCall( $elems, options ) {
5422    $elems.each( function( i, elem ) {
5423      var instance = $.data( elem, namespace );
5424      if ( instance ) {
5425        // set options & init
5426        instance.option( options );
5427        instance._init();
5428      } else {
5429        // initialize new instance
5430        instance = new PluginClass( elem, options );
5431        $.data( elem, namespace, instance );
5432      }
5433    });
5434  }
5435
5436  updateJQuery( $ );
5437
5438}
5439
5440// ----- updateJQuery ----- //
5441
5442// set $.bridget for v1 backwards compatibility
5443function updateJQuery( $ ) {
5444  if ( !$ || ( $ && $.bridget ) ) {
5445    return;
5446  }
5447  $.bridget = jQueryBridget;
5448}
5449
5450updateJQuery( jQuery || window.jQuery );
5451
5452// -----  ----- //
5453
5454return jQueryBridget;
5455
5456}));
5457
5458/*!
5459 * getSize v2.0.3
5460 * measure size of elements
5461 * MIT license
5462 */
5463
5464/* jshint browser: true, strict: true, undef: true, unused: true */
5465/* globals console: false */
5466
5467( function( window, factory ) {
5468  /* jshint strict: false */ /* globals define, module */
5469  if ( typeof define == 'function' && define.amd ) {
5470    // AMD
5471    define( 'get-size/get-size',factory );
5472  } else if ( typeof module == 'object' && module.exports ) {
5473    // CommonJS
5474    module.exports = factory();
5475  } else {
5476    // browser global
5477    window.getSize = factory();
5478  }
5479
5480})( window, function factory() {
5481'use strict';
5482
5483// -------------------------- helpers -------------------------- //
5484
5485// get a number from a string, not a percentage
5486function getStyleSize( value ) {
5487  var num = parseFloat( value );
5488  // not a percent like '100%', and a number
5489  var isValid = value.indexOf('%') == -1 && !isNaN( num );
5490  return isValid && num;
5491}
5492
5493function noop() {}
5494
5495var logError = typeof console == 'undefined' ? noop :
5496  function( message ) {
5497    console.error( message );
5498  };
5499
5500// -------------------------- measurements -------------------------- //
5501
5502var measurements = [
5503  'paddingLeft',
5504  'paddingRight',
5505  'paddingTop',
5506  'paddingBottom',
5507  'marginLeft',
5508  'marginRight',
5509  'marginTop',
5510  'marginBottom',
5511  'borderLeftWidth',
5512  'borderRightWidth',
5513  'borderTopWidth',
5514  'borderBottomWidth'
5515];
5516
5517var measurementsLength = measurements.length;
5518
5519function getZeroSize() {
5520  var size = {
5521    width: 0,
5522    height: 0,
5523    innerWidth: 0,
5524    innerHeight: 0,
5525    outerWidth: 0,
5526    outerHeight: 0
5527  };
5528  for ( var i=0; i < measurementsLength; i++ ) {
5529    var measurement = measurements[i];
5530    size[ measurement ] = 0;
5531  }
5532  return size;
5533}
5534
5535// -------------------------- getStyle -------------------------- //
5536
5537/**
5538 * getStyle, get style of element, check for Firefox bug
5539 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
5540 */
5541function getStyle( elem ) {
5542  var style = getComputedStyle( elem );
5543  if ( !style ) {
5544    logError( 'Style returned ' + style +
5545      '. Are you running this code in a hidden iframe on Firefox? ' +
5546      'See https://bit.ly/getsizebug1' );
5547  }
5548  return style;
5549}
5550
5551// -------------------------- setup -------------------------- //
5552
5553var isSetup = false;
5554
5555var isBoxSizeOuter;
5556
5557/**
5558 * setup
5559 * check isBoxSizerOuter
5560 * do on first getSize() rather than on page load for Firefox bug
5561 */
5562function setup() {
5563  // setup once
5564  if ( isSetup ) {
5565    return;
5566  }
5567  isSetup = true;
5568
5569  // -------------------------- box sizing -------------------------- //
5570
5571  /**
5572   * Chrome & Safari measure the outer-width on style.width on border-box elems
5573   * IE11 & Firefox<29 measures the inner-width
5574   */
5575  var div = document.createElement('div');
5576  div.style.width = '200px';
5577  div.style.padding = '1px 2px 3px 4px';
5578  div.style.borderStyle = 'solid';
5579  div.style.borderWidth = '1px 2px 3px 4px';
5580  div.style.boxSizing = 'border-box';
5581
5582  var body = document.body || document.documentElement;
5583  body.appendChild( div );
5584  var style = getStyle( div );
5585  // round value for browser zoom. desandro/masonry#928
5586  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
5587  getSize.isBoxSizeOuter = isBoxSizeOuter;
5588
5589  body.removeChild( div );
5590}
5591
5592// -------------------------- getSize -------------------------- //
5593
5594function getSize( elem ) {
5595  setup();
5596
5597  // use querySeletor if elem is string
5598  if ( typeof elem == 'string' ) {
5599    elem = document.querySelector( elem );
5600  }
5601
5602  // do not proceed on non-objects
5603  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
5604    return;
5605  }
5606
5607  var style = getStyle( elem );
5608
5609  // if hidden, everything is 0
5610  if ( style.display == 'none' ) {
5611    return getZeroSize();
5612  }
5613
5614  var size = {};
5615  size.width = elem.offsetWidth;
5616  size.height = elem.offsetHeight;
5617
5618  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
5619
5620  // get all measurements
5621  for ( var i=0; i < measurementsLength; i++ ) {
5622    var measurement = measurements[i];
5623    var value = style[ measurement ];
5624    var num = parseFloat( value );
5625    // any 'auto', 'medium' value will be 0
5626    size[ measurement ] = !isNaN( num ) ? num : 0;
5627  }
5628
5629  var paddingWidth = size.paddingLeft + size.paddingRight;
5630  var paddingHeight = size.paddingTop + size.paddingBottom;
5631  var marginWidth = size.marginLeft + size.marginRight;
5632  var marginHeight = size.marginTop + size.marginBottom;
5633  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
5634  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
5635
5636  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
5637
5638  // overwrite width and height if we can get it from style
5639  var styleWidth = getStyleSize( style.width );
5640  if ( styleWidth !== false ) {
5641    size.width = styleWidth +
5642      // add padding and border unless it's already including it
5643      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
5644  }
5645
5646  var styleHeight = getStyleSize( style.height );
5647  if ( styleHeight !== false ) {
5648    size.height = styleHeight +
5649      // add padding and border unless it's already including it
5650      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
5651  }
5652
5653  size.innerWidth = size.width - ( paddingWidth + borderWidth );
vendor: 2,918 bytes, lines 5654-5777
5654  size.innerHeight = size.height - ( paddingHeight + borderHeight );
5655
5656  size.outerWidth = size.width + marginWidth;
5657  size.outerHeight = size.height + marginHeight;
5658
5659  return size;
5660}
5661
5662return getSize;
5663
5664});
5665
5666/**
5667 * EvEmitter v1.1.0
5668 * Lil' event emitter
5669 * MIT License
5670 */
5671
5672/* jshint unused: true, undef: true, strict: true */
5673
5674( function( global, factory ) {
5675  // universal module definition
5676  /* jshint strict: false */ /* globals define, module, window */
5677  if ( typeof define == 'function' && define.amd ) {
5678    // AMD - RequireJS
5679    define( 'ev-emitter/ev-emitter',factory );
5680  } else if ( typeof module == 'object' && module.exports ) {
5681    // CommonJS - Browserify, Webpack
5682    module.exports = factory();
5683  } else {
5684    // Browser globals
5685    global.EvEmitter = factory();
5686  }
5687
5688}( typeof window != 'undefined' ? window : this, function() {
5689
5690
5691
5692function EvEmitter() {}
5693
5694var proto = EvEmitter.prototype;
5695
5696proto.on = function( eventName, listener ) {
5697  if ( !eventName || !listener ) {
5698    return;
5699  }
5700  // set events hash
5701  var events = this._events = this._events || {};
5702  // set listeners array
5703  var listeners = events[ eventName ] = events[ eventName ] || [];
5704  // only add once
5705  if ( listeners.indexOf( listener ) == -1 ) {
5706    listeners.push( listener );
5707  }
5708
5709  return this;
5710};
5711
5712proto.once = function( eventName, listener ) {
5713  if ( !eventName || !listener ) {
5714    return;
5715  }
5716  // add event
5717  this.on( eventName, listener );
5718  // set once flag
5719  // set onceEvents hash
5720  var onceEvents = this._onceEvents = this._onceEvents || {};
5721  // set onceListeners object
5722  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
5723  // set flag
5724  onceListeners[ listener ] = true;
5725
5726  return this;
5727};
5728
5729proto.off = function( eventName, listener ) {
5730  var listeners = this._events && this._events[ eventName ];
5731  if ( !listeners || !listeners.length ) {
5732    return;
5733  }
5734  var index = listeners.indexOf( listener );
5735  if ( index != -1 ) {
5736    listeners.splice( index, 1 );
5737  }
5738
5739  return this;
5740};
5741
5742proto.emitEvent = function( eventName, args ) {
5743  var listeners = this._events && this._events[ eventName ];
5744  if ( !listeners || !listeners.length ) {
5745    return;
5746  }
5747  // copy over to avoid interference if .off() in listener
5748  listeners = listeners.slice(0);
5749  args = args || [];
5750  // once stuff
5751  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
5752
5753  for ( var i=0; i < listeners.length; i++ ) {
5754    var listener = listeners[i]
5755    var isOnce = onceListeners && onceListeners[ listener ];
5756    if ( isOnce ) {
5757      // remove listener
5758      // remove before trigger to prevent recursion
5759      this.off( eventName, listener );
5760      // unset once flag
5761      delete onceListeners[ listener ];
5762    }
5763    // trigger listener
5764    listener.apply( this, args );
5765  }
5766
5767  return this;
5768};
5769
5770proto.allOff = function() {
5771  delete this._events;
5772  delete this._onceEvents;
5773};
5774
5775return EvEmitter;
5776
5777})
vendor: 27,688 bytes, lines 5777-6873
5777);
5778
5779/**
5780 * matchesSelector v2.0.2
5781 * matchesSelector( element, '.selector' )
5782 * MIT license
5783 */
5784
5785/*jshint browser: true, strict: true, undef: true, unused: true */
5786
5787( function( window, factory ) {
5788  /*global define: false, module: false */
5789  'use strict';
5790  // universal module definition
5791  if ( typeof define == 'function' && define.amd ) {
5792    // AMD
5793    define( 'desandro-matches-selector/matches-selector',factory );
5794  } else if ( typeof module == 'object' && module.exports ) {
5795    // CommonJS
5796    module.exports = factory();
5797  } else {
5798    // browser global
5799    window.matchesSelector = factory();
5800  }
5801
5802}( window, function factory() {
5803  'use strict';
5804
5805  var matchesMethod = ( function() {
5806    var ElemProto = window.Element.prototype;
5807    // check for the standard method name first
5808    if ( ElemProto.matches ) {
5809      return 'matches';
5810    }
5811    // check un-prefixed
5812    if ( ElemProto.matchesSelector ) {
5813      return 'matchesSelector';
5814    }
5815    // check vendor prefixes
5816    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
5817
5818    for ( var i=0; i < prefixes.length; i++ ) {
5819      var prefix = prefixes[i];
5820      var method = prefix + 'MatchesSelector';
5821      if ( ElemProto[ method ] ) {
5822        return method;
5823      }
5824    }
5825  })();
5826
5827  return function matchesSelector( elem, selector ) {
5828    return elem[ matchesMethod ]( selector );
5829  };
5830
5831}));
5832
5833/**
5834 * Fizzy UI utils v2.0.7
5835 * MIT license
5836 */
5837
5838/*jshint browser: true, undef: true, unused: true, strict: true */
5839
5840( function( window, factory ) {
5841  // universal module definition
5842  /*jshint strict: false */ /*globals define, module, require */
5843
5844  if ( typeof define == 'function' && define.amd ) {
5845    // AMD
5846    define( 'fizzy-ui-utils/utils',[
5847      'desandro-matches-selector/matches-selector'
5848    ], function( matchesSelector ) {
5849      return factory( window, matchesSelector );
5850    });
5851  } else if ( typeof module == 'object' && module.exports ) {
5852    // CommonJS
5853    module.exports = factory(
5854      window,
5855      require('desandro-matches-selector')
5856    );
5857  } else {
5858    // browser global
5859    window.fizzyUIUtils = factory(
5860      window,
5861      window.matchesSelector
5862    );
5863  }
5864
5865}( window, function factory( window, matchesSelector ) {
5866
5867
5868
5869var utils = {};
5870
5871// ----- extend ----- //
5872
5873// extends objects
5874utils.extend = function( a, b ) {
5875  for ( var prop in b ) {
5876    a[ prop ] = b[ prop ];
5877  }
5878  return a;
5879};
5880
5881// ----- modulo ----- //
5882
5883utils.modulo = function( num, div ) {
5884  return ( ( num % div ) + div ) % div;
5885};
5886
5887// ----- makeArray ----- //
5888
5889var arraySlice = Array.prototype.slice;
5890
5891// turn element or nodeList into an array
5892utils.makeArray = function( obj ) {
5893  if ( Array.isArray( obj ) ) {
5894    // use object if already an array
5895    return obj;
5896  }
5897  // return empty array if undefined or null. #6
5898  if ( obj === null || obj === undefined ) {
5899    return [];
5900  }
5901
5902  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
5903  if ( isArrayLike ) {
5904    // convert nodeList to array
5905    return arraySlice.call( obj );
5906  }
5907
5908  // array of single index
5909  return [ obj ];
5910};
5911
5912// ----- removeFrom ----- //
5913
5914utils.removeFrom = function( ary, obj ) {
5915  var index = ary.indexOf( obj );
5916  if ( index != -1 ) {
5917    ary.splice( index, 1 );
5918  }
5919};
5920
5921// ----- getParent ----- //
5922
5923utils.getParent = function( elem, selector ) {
5924  while ( elem.parentNode && elem != document.body ) {
5925    elem = elem.parentNode;
5926    if ( matchesSelector( elem, selector ) ) {
5927      return elem;
5928    }
5929  }
5930};
5931
5932// ----- getQueryElement ----- //
5933
5934// use element as selector string
5935utils.getQueryElement = function( elem ) {
5936  if ( typeof elem == 'string' ) {
5937    return document.querySelector( elem );
5938  }
5939  return elem;
5940};
5941
5942// ----- handleEvent ----- //
5943
5944// enable .ontype to trigger from .addEventListener( elem, 'type' )
5945utils.handleEvent = function( event ) {
5946  var method = 'on' + event.type;
5947  if ( this[ method ] ) {
5948    this[ method ]( event );
5949  }
5950};
5951
5952// ----- filterFindElements ----- //
5953
5954utils.filterFindElements = function( elems, selector ) {
5955  // make array of elems
5956  elems = utils.makeArray( elems );
5957  var ffElems = [];
5958
5959  elems.forEach( function( elem ) {
5960    // check that elem is an actual element
5961    if ( !( elem instanceof HTMLElement ) ) {
5962      return;
5963    }
5964    // add elem if no selector
5965    if ( !selector ) {
5966      ffElems.push( elem );
5967      return;
5968    }
5969    // filter & find items if we have a selector
5970    // filter
5971    if ( matchesSelector( elem, selector ) ) {
5972      ffElems.push( elem );
5973    }
5974    // find children
5975    var childElems = elem.querySelectorAll( selector );
5976    // concat childElems to filterFound array
5977    for ( var i=0; i < childElems.length; i++ ) {
5978      ffElems.push( childElems[i] );
5979    }
5980  });
5981
5982  return ffElems;
5983};
5984
5985// ----- debounceMethod ----- //
5986
5987utils.debounceMethod = function( _class, methodName, threshold ) {
5988  threshold = threshold || 100;
5989  // original method
5990  var method = _class.prototype[ methodName ];
5991  var timeoutName = methodName + 'Timeout';
5992
5993  _class.prototype[ methodName ] = function() {
5994    var timeout = this[ timeoutName ];
5995    clearTimeout( timeout );
5996
5997    var args = arguments;
5998    var _this = this;
5999    this[ timeoutName ] = setTimeout( function() {
6000      method.apply( _this, args );
6001      delete _this[ timeoutName ];
6002    }, threshold );
6003  };
6004};
6005
6006// ----- docReady ----- //
6007
6008utils.docReady = function( callback ) {
6009  var readyState = document.readyState;
6010  if ( readyState == 'complete' || readyState == 'interactive' ) {
6011    // do async to allow for other scripts to run. metafizzy/flickity#441
6012    setTimeout( callback );
6013  } else {
6014    document.addEventListener( 'DOMContentLoaded', callback );
6015  }
6016};
6017
6018// ----- htmlInit ----- //
6019
6020// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
6021utils.toDashed = function( str ) {
6022  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
6023    return $1 + '-' + $2;
6024  }).toLowerCase();
6025};
6026
6027var console = window.console;
6028/**
6029 * allow user to initialize classes via [data-namespace] or .js-namespace class
6030 * htmlInit( Widget, 'widgetName' )
6031 * options are parsed from data-namespace-options
6032 */
6033utils.htmlInit = function( WidgetClass, namespace ) {
6034  utils.docReady( function() {
6035    var dashedNamespace = utils.toDashed( namespace );
6036    var dataAttr = 'data-' + dashedNamespace;
6037    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
6038    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
6039    var elems = utils.makeArray( dataAttrElems )
6040      .concat( utils.makeArray( jsDashElems ) );
6041    var dataOptionsAttr = dataAttr + '-options';
6042    var jQuery = window.jQuery;
6043
6044    elems.forEach( function( elem ) {
6045      var attr = elem.getAttribute( dataAttr ) ||
6046        elem.getAttribute( dataOptionsAttr );
6047      var options;
6048      try {
6049        options = attr && JSON.parse( attr );
6050      } catch ( error ) {
6051        // log error, do not initialize
6052        if ( console ) {
6053          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
6054          ': ' + error );
6055        }
6056        return;
6057      }
6058      // initialize
6059      var instance = new WidgetClass( elem, options );
6060      // make available via $().data('namespace')
6061      if ( jQuery ) {
6062        jQuery.data( elem, namespace, instance );
6063      }
6064    });
6065
6066  });
6067};
6068
6069// -----  ----- //
6070
6071return utils;
6072
6073}));
6074
6075/**
6076 * Outlayer Item
6077 */
6078
6079( function( window, factory ) {
6080  // universal module definition
6081  /* jshint strict: false */ /* globals define, module, require */
6082  if ( typeof define == 'function' && define.amd ) {
6083    // AMD - RequireJS
6084    define( 'outlayer/item',[
6085        'ev-emitter/ev-emitter',
6086        'get-size/get-size'
6087      ],
6088      factory
6089    );
6090  } else if ( typeof module == 'object' && module.exports ) {
6091    // CommonJS - Browserify, Webpack
6092    module.exports = factory(
6093      require('ev-emitter'),
6094      require('get-size')
6095    );
6096  } else {
6097    // browser global
6098    window.Outlayer = {};
6099    window.Outlayer.Item = factory(
6100      window.EvEmitter,
6101      window.getSize
6102    );
6103  }
6104
6105}( window, function factory( EvEmitter, getSize ) {
6106'use strict';
6107
6108// ----- helpers ----- //
6109
6110function isEmptyObj( obj ) {
6111  for ( var prop in obj ) {
6112    return false;
6113  }
6114  prop = null;
6115  return true;
6116}
6117
6118// -------------------------- CSS3 support -------------------------- //
6119
6120
6121var docElemStyle = document.documentElement.style;
6122
6123var transitionProperty = typeof docElemStyle.transition == 'string' ?
6124  'transition' : 'WebkitTransition';
6125var transformProperty = typeof docElemStyle.transform == 'string' ?
6126  'transform' : 'WebkitTransform';
6127
6128var transitionEndEvent = {
6129  WebkitTransition: 'webkitTransitionEnd',
6130  transition: 'transitionend'
6131}[ transitionProperty ];
6132
6133// cache all vendor properties that could have vendor prefix
6134var vendorProperties = {
6135  transform: transformProperty,
6136  transition: transitionProperty,
6137  transitionDuration: transitionProperty + 'Duration',
6138  transitionProperty: transitionProperty + 'Property',
6139  transitionDelay: transitionProperty + 'Delay'
6140};
6141
6142// -------------------------- Item -------------------------- //
6143
6144function Item( element, layout ) {
6145  if ( !element ) {
6146    return;
6147  }
6148
6149  this.element = element;
6150  // parent layout class, i.e. Masonry, Isotope, or Packery
6151  this.layout = layout;
6152  this.position = {
6153    x: 0,
6154    y: 0
6155  };
6156
6157  this._create();
6158}
6159
6160// inherit EvEmitter
6161var proto = Item.prototype = Object.create( EvEmitter.prototype );
6162proto.constructor = Item;
6163
6164proto._create = function() {
6165  // transition objects
6166  this._transn = {
6167    ingProperties: {},
6168    clean: {},
6169    onEnd: {}
6170  };
6171
6172  this.css({
6173    position: 'absolute'
6174  });
6175};
6176
6177// trigger specified handler for event type
6178proto.handleEvent = function( event ) {
6179  var method = 'on' + event.type;
6180  if ( this[ method ] ) {
6181    this[ method ]( event );
6182  }
6183};
6184
6185proto.getSize = function() {
6186  this.size = getSize( this.element );
6187};
6188
6189/**
6190 * apply CSS styles to element
6191 * @param {Object} style
6192 */
6193proto.css = function( style ) {
6194  var elemStyle = this.element.style;
6195
6196  for ( var prop in style ) {
6197    // use vendor property if available
6198    var supportedProp = vendorProperties[ prop ] || prop;
6199    elemStyle[ supportedProp ] = style[ prop ];
6200  }
6201};
6202
6203 // measure position, and sets it
6204proto.getPosition = function() {
6205  var style = getComputedStyle( this.element );
6206  var isOriginLeft = this.layout._getOption('originLeft');
6207  var isOriginTop = this.layout._getOption('originTop');
6208  var xValue = style[ isOriginLeft ? 'left' : 'right' ];
6209  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
6210  var x = parseFloat( xValue );
6211  var y = parseFloat( yValue );
6212  // convert percent to pixels
6213  var layoutSize = this.layout.size;
6214  if ( xValue.indexOf('%') != -1 ) {
6215    x = ( x / 100 ) * layoutSize.width;
6216  }
6217  if ( yValue.indexOf('%') != -1 ) {
6218    y = ( y / 100 ) * layoutSize.height;
6219  }
6220  // clean up 'auto' or other non-integer values
6221  x = isNaN( x ) ? 0 : x;
6222  y = isNaN( y ) ? 0 : y;
6223  // remove padding from measurement
6224  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
6225  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
6226
6227  this.position.x = x;
6228  this.position.y = y;
6229};
6230
6231// set settled position, apply padding
6232proto.layoutPosition = function() {
6233  var layoutSize = this.layout.size;
6234  var style = {};
6235  var isOriginLeft = this.layout._getOption('originLeft');
6236  var isOriginTop = this.layout._getOption('originTop');
6237
6238  // x
6239  var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
6240  var xProperty = isOriginLeft ? 'left' : 'right';
6241  var xResetProperty = isOriginLeft ? 'right' : 'left';
6242
6243  var x = this.position.x + layoutSize[ xPadding ];
6244  // set in percentage or pixels
6245  style[ xProperty ] = this.getXValue( x );
6246  // reset other property
6247  style[ xResetProperty ] = '';
6248
6249  // y
6250  var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
6251  var yProperty = isOriginTop ? 'top' : 'bottom';
6252  var yResetProperty = isOriginTop ? 'bottom' : 'top';
6253
6254  var y = this.position.y + layoutSize[ yPadding ];
6255  // set in percentage or pixels
6256  style[ yProperty ] = this.getYValue( y );
6257  // reset other property
6258  style[ yResetProperty ] = '';
6259
6260  this.css( style );
6261  this.emitEvent( 'layout', [ this ] );
6262};
6263
6264proto.getXValue = function( x ) {
6265  var isHorizontal = this.layout._getOption('horizontal');
6266  return this.layout.options.percentPosition && !isHorizontal ?
6267    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
6268};
6269
6270proto.getYValue = function( y ) {
6271  var isHorizontal = this.layout._getOption('horizontal');
6272  return this.layout.options.percentPosition && isHorizontal ?
6273    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
6274};
6275
6276proto._transitionTo = function( x, y ) {
6277  this.getPosition();
6278  // get current x & y from top/left
6279  var curX = this.position.x;
6280  var curY = this.position.y;
6281
6282  var didNotMove = x == this.position.x && y == this.position.y;
6283
6284  // save end position
6285  this.setPosition( x, y );
6286
6287  // if did not move and not transitioning, just go to layout
6288  if ( didNotMove && !this.isTransitioning ) {
6289    this.layoutPosition();
6290    return;
6291  }
6292
6293  var transX = x - curX;
6294  var transY = y - curY;
6295  var transitionStyle = {};
6296  transitionStyle.transform = this.getTranslate( transX, transY );
6297
6298  this.transition({
6299    to: transitionStyle,
6300    onTransitionEnd: {
6301      transform: this.layoutPosition
6302    },
6303    isCleaning: true
6304  });
6305};
6306
6307proto.getTranslate = function( x, y ) {
6308  // flip cooridinates if origin on right or bottom
6309  var isOriginLeft = this.layout._getOption('originLeft');
6310  var isOriginTop = this.layout._getOption('originTop');
6311  x = isOriginLeft ? x : -x;
6312  y = isOriginTop ? y : -y;
6313  return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
6314};
6315
6316// non transition + transform support
6317proto.goTo = function( x, y ) {
6318  this.setPosition( x, y );
6319  this.layoutPosition();
6320};
6321
6322proto.moveTo = proto._transitionTo;
6323
6324proto.setPosition = function( x, y ) {
6325  this.position.x = parseFloat( x );
6326  this.position.y = parseFloat( y );
6327};
6328
6329// ----- transition ----- //
6330
6331/**
6332 * @param {Object} style - CSS
6333 * @param {Function} onTransitionEnd
6334 */
6335
6336// non transition, just trigger callback
6337proto._nonTransition = function( args ) {
6338  this.css( args.to );
6339  if ( args.isCleaning ) {
6340    this._removeStyles( args.to );
6341  }
6342  for ( var prop in args.onTransitionEnd ) {
6343    args.onTransitionEnd[ prop ].call( this );
6344  }
6345};
6346
6347/**
6348 * proper transition
6349 * @param {Object} args - arguments
6350 *   @param {Object} to - style to transition to
6351 *   @param {Object} from - style to start transition from
6352 *   @param {Boolean} isCleaning - removes transition styles after transition
6353 *   @param {Function} onTransitionEnd - callback
6354 */
6355proto.transition = function( args ) {
6356  // redirect to nonTransition if no transition duration
6357  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
6358    this._nonTransition( args );
6359    return;
6360  }
6361
6362  var _transition = this._transn;
6363  // keep track of onTransitionEnd callback by css property
6364  for ( var prop in args.onTransitionEnd ) {
6365    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
6366  }
6367  // keep track of properties that are transitioning
6368  for ( prop in args.to ) {
6369    _transition.ingProperties[ prop ] = true;
6370    // keep track of properties to clean up when transition is done
6371    if ( args.isCleaning ) {
6372      _transition.clean[ prop ] = true;
6373    }
6374  }
6375
6376  // set from styles
6377  if ( args.from ) {
6378    this.css( args.from );
6379    // force redraw. http://blog.alexmaccaw.com/css-transitions
6380    var h = this.element.offsetHeight;
6381    // hack for JSHint to hush about unused var
6382    h = null;
6383  }
6384  // enable transition
6385  this.enableTransition( args.to );
6386  // set styles that are transitioning
6387  this.css( args.to );
6388
6389  this.isTransitioning = true;
6390
6391};
6392
6393// dash before all cap letters, including first for
6394// WebkitTransform => -webkit-transform
6395function toDashedAll( str ) {
6396  return str.replace( /([A-Z])/g, function( $1 ) {
6397    return '-' + $1.toLowerCase();
6398  });
6399}
6400
6401var transitionProps = 'opacity,' + toDashedAll( transformProperty );
6402
6403proto.enableTransition = function(/* style */) {
6404  // HACK changing transitionProperty during a transition
6405  // will cause transition to jump
6406  if ( this.isTransitioning ) {
6407    return;
6408  }
6409
6410  // make `transition: foo, bar, baz` from style object
6411  // HACK un-comment this when enableTransition can work
6412  // while a transition is happening
6413  // var transitionValues = [];
6414  // for ( var prop in style ) {
6415  //   // dash-ify camelCased properties like WebkitTransition
6416  //   prop = vendorProperties[ prop ] || prop;
6417  //   transitionValues.push( toDashedAll( prop ) );
6418  // }
6419  // munge number to millisecond, to match stagger
6420  var duration = this.layout.options.transitionDuration;
6421  duration = typeof duration == 'number' ? duration + 'ms' : duration;
6422  // enable transition styles
6423  this.css({
6424    transitionProperty: transitionProps,
6425    transitionDuration: duration,
6426    transitionDelay: this.staggerDelay || 0
6427  });
6428  // listen for transition end event
6429  this.element.addEventListener( transitionEndEvent, this, false );
6430};
6431
6432// ----- events ----- //
6433
6434proto.onwebkitTransitionEnd = function( event ) {
6435  this.ontransitionend( event );
6436};
6437
6438proto.onotransitionend = function( event ) {
6439  this.ontransitionend( event );
6440};
6441
6442// properties that I munge to make my life easier
6443var dashedVendorProperties = {
6444  '-webkit-transform': 'transform'
6445};
6446
6447proto.ontransitionend = function( event ) {
6448  // disregard bubbled events from children
6449  if ( event.target !== this.element ) {
6450    return;
6451  }
6452  var _transition = this._transn;
6453  // get property name of transitioned property, convert to prefix-free
6454  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
6455
6456  // remove property that has completed transitioning
6457  delete _transition.ingProperties[ propertyName ];
6458  // check if any properties are still transitioning
6459  if ( isEmptyObj( _transition.ingProperties ) ) {
6460    // all properties have completed transitioning
6461    this.disableTransition();
6462  }
6463  // clean style
6464  if ( propertyName in _transition.clean ) {
6465    // clean up style
6466    this.element.style[ event.propertyName ] = '';
6467    delete _transition.clean[ propertyName ];
6468  }
6469  // trigger onTransitionEnd callback
6470  if ( propertyName in _transition.onEnd ) {
6471    var onTransitionEnd = _transition.onEnd[ propertyName ];
6472    onTransitionEnd.call( this );
6473    delete _transition.onEnd[ propertyName ];
6474  }
6475
6476  this.emitEvent( 'transitionEnd', [ this ] );
6477};
6478
6479proto.disableTransition = function() {
6480  this.removeTransitionStyles();
6481  this.element.removeEventListener( transitionEndEvent, this, false );
6482  this.isTransitioning = false;
6483};
6484
6485/**
6486 * removes style property from element
6487 * @param {Object} style
6488**/
6489proto._removeStyles = function( style ) {
6490  // clean up transition styles
6491  var cleanStyle = {};
6492  for ( var prop in style ) {
6493    cleanStyle[ prop ] = '';
6494  }
6495  this.css( cleanStyle );
6496};
6497
6498var cleanTransitionStyle = {
6499  transitionProperty: '',
6500  transitionDuration: '',
6501  transitionDelay: ''
6502};
6503
6504proto.removeTransitionStyles = function() {
6505  // remove transition
6506  this.css( cleanTransitionStyle );
6507};
6508
6509// ----- stagger ----- //
6510
6511proto.stagger = function( delay ) {
6512  delay = isNaN( delay ) ? 0 : delay;
6513  this.staggerDelay = delay + 'ms';
6514};
6515
6516// ----- show/hide/remove ----- //
6517
6518// remove element from DOM
6519proto.removeElem = function() {
6520  this.element.parentNode.removeChild( this.element );
6521  // remove display: none
6522  this.css({ display: '' });
6523  this.emitEvent( 'remove', [ this ] );
6524};
6525
6526proto.remove = function() {
6527  // just remove element if no transition support or no transition
6528  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
6529    this.removeElem();
6530    return;
6531  }
6532
6533  // start transition
6534  this.once( 'transitionEnd', function() {
6535    this.removeElem();
6536  });
6537  this.hide();
6538};
6539
6540proto.reveal = function() {
6541  delete this.isHidden;
6542  // remove display: none
6543  this.css({ display: '' });
6544
6545  var options = this.layout.options;
6546
6547  var onTransitionEnd = {};
6548  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
6549  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
6550
6551  this.transition({
6552    from: options.hiddenStyle,
6553    to: options.visibleStyle,
6554    isCleaning: true,
6555    onTransitionEnd: onTransitionEnd
6556  });
6557};
6558
6559proto.onRevealTransitionEnd = function() {
6560  // check if still visible
6561  // during transition, item may have been hidden
6562  if ( !this.isHidden ) {
6563    this.emitEvent('reveal');
6564  }
6565};
6566
6567/**
6568 * get style property use for hide/reveal transition end
6569 * @param {String} styleProperty - hiddenStyle/visibleStyle
6570 * @returns {String}
6571 */
6572proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
6573  var optionStyle = this.layout.options[ styleProperty ];
6574  // use opacity
6575  if ( optionStyle.opacity ) {
6576    return 'opacity';
6577  }
6578  // get first property
6579  for ( var prop in optionStyle ) {
6580    return prop;
6581  }
6582};
6583
6584proto.hide = function() {
6585  // set flag
6586  this.isHidden = true;
6587  // remove display: none
6588  this.css({ display: '' });
6589
6590  var options = this.layout.options;
6591
6592  var onTransitionEnd = {};
6593  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
6594  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
6595
6596  this.transition({
6597    from: options.visibleStyle,
6598    to: options.hiddenStyle,
6599    // keep hidden stuff hidden
6600    isCleaning: true,
6601    onTransitionEnd: onTransitionEnd
6602  });
6603};
6604
6605proto.onHideTransitionEnd = function() {
6606  // check if still hidden
6607  // during transition, item may have been un-hidden
6608  if ( this.isHidden ) {
6609    this.css({ display: 'none' });
6610    this.emitEvent('hide');
6611  }
6612};
6613
6614proto.destroy = function() {
6615  this.css({
6616    position: '',
6617    left: '',
6618    right: '',
6619    top: '',
6620    bottom: '',
6621    transition: '',
6622    transform: ''
6623  });
6624};
6625
6626return Item;
6627
6628}));
6629
6630/*!
6631 * Outlayer v2.1.1
6632 * the brains and guts of a layout library
6633 * MIT license
6634 */
6635
6636( function( window, factory ) {
6637  'use strict';
6638  // universal module definition
6639  /* jshint strict: false */ /* globals define, module, require */
6640  if ( typeof define == 'function' && define.amd ) {
6641    // AMD - RequireJS
6642    define( 'outlayer/outlayer',[
6643        'ev-emitter/ev-emitter',
6644        'get-size/get-size',
6645        'fizzy-ui-utils/utils',
6646        './item'
6647      ],
6648      function( EvEmitter, getSize, utils, Item ) {
6649        return factory( window, EvEmitter, getSize, utils, Item);
6650      }
6651    );
6652  } else if ( typeof module == 'object' && module.exports ) {
6653    // CommonJS - Browserify, Webpack
6654    module.exports = factory(
6655      window,
6656      require('ev-emitter'),
6657      require('get-size'),
6658      require('fizzy-ui-utils'),
6659      require('./item')
6660    );
6661  } else {
6662    // browser global
6663    window.Outlayer = factory(
6664      window,
6665      window.EvEmitter,
6666      window.getSize,
6667      window.fizzyUIUtils,
6668      window.Outlayer.Item
6669    );
6670  }
6671
6672}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
6673'use strict';
6674
6675// ----- vars ----- //
6676
6677var console = window.console;
6678var jQuery = window.jQuery;
6679var noop = function() {};
6680
6681// -------------------------- Outlayer -------------------------- //
6682
6683// globally unique identifiers
6684var GUID = 0;
6685// internal store of all Outlayer intances
6686var instances = {};
6687
6688
6689/**
6690 * @param {Element, String} element
6691 * @param {Object} options
6692 * @constructor
6693 */
6694function Outlayer( element, options ) {
6695  var queryElement = utils.getQueryElement( element );
6696  if ( !queryElement ) {
6697    if ( console ) {
6698      console.error( 'Bad element for ' + this.constructor.namespace +
6699        ': ' + ( queryElement || element ) );
6700    }
6701    return;
6702  }
6703  this.element = queryElement;
6704  // add jQuery
6705  if ( jQuery ) {
6706    this.$element = jQuery( this.element );
6707  }
6708
6709  // options
6710  this.options = utils.extend( {}, this.constructor.defaults );
6711  this.option( options );
6712
6713  // add id for Outlayer.getFromElement
6714  var id = ++GUID;
6715  this.element.outlayerGUID = id; // expando
6716  instances[ id ] = this; // associate via id
6717
6718  // kick it off
6719  this._create();
6720
6721  var isInitLayout = this._getOption('initLayout');
6722  if ( isInitLayout ) {
6723    this.layout();
6724  }
6725}
6726
6727// settings are for internal use only
6728Outlayer.namespace = 'outlayer';
6729Outlayer.Item = Item;
6730
6731// default options
6732Outlayer.defaults = {
6733  containerStyle: {
6734    position: 'relative'
6735  },
6736  initLayout: true,
6737  originLeft: true,
6738  originTop: true,
6739  resize: true,
6740  resizeContainer: true,
6741  // item options
6742  transitionDuration: '0.4s',
6743  hiddenStyle: {
6744    opacity: 0,
6745    transform: 'scale(0.001)'
6746  },
6747  visibleStyle: {
6748    opacity: 1,
6749    transform: 'scale(1)'
6750  }
6751};
6752
6753var proto = Outlayer.prototype;
6754// inherit EvEmitter
6755utils.extend( proto, EvEmitter.prototype );
6756
6757/**
6758 * set options
6759 * @param {Object} opts
6760 */
6761proto.option = function( opts ) {
6762  utils.extend( this.options, opts );
6763};
6764
6765/**
6766 * get backwards compatible option value, check old name
6767 */
6768proto._getOption = function( option ) {
6769  var oldOption = this.constructor.compatOptions[ option ];
6770  return oldOption && this.options[ oldOption ] !== undefined ?
6771    this.options[ oldOption ] : this.options[ option ];
6772};
6773
6774Outlayer.compatOptions = {
6775  // currentName: oldName
6776  initLayout: 'isInitLayout',
6777  horizontal: 'isHorizontal',
6778  layoutInstant: 'isLayoutInstant',
6779  originLeft: 'isOriginLeft',
6780  originTop: 'isOriginTop',
6781  resize: 'isResizeBound',
6782  resizeContainer: 'isResizingContainer'
6783};
6784
6785proto._create = function() {
6786  // get items from children
6787  this.reloadItems();
6788  // elements that affect layout, but are not laid out
6789  this.stamps = [];
6790  this.stamp( this.options.stamp );
6791  // set container style
6792  utils.extend( this.element.style, this.options.containerStyle );
6793
6794  // bind resize method
6795  var canBindResize = this._getOption('resize');
6796  if ( canBindResize ) {
6797    this.bindResize();
6798  }
6799};
6800
6801// goes through all children again and gets bricks in proper order
6802proto.reloadItems = function() {
6803  // collection of item elements
6804  this.items = this._itemize( this.element.children );
6805};
6806
6807
6808/**
6809 * turn elements into Outlayer.Items to be used in layout
6810 * @param {Array or NodeList or HTMLElement} elems
6811 * @returns {Array} items - collection of new Outlayer Items
6812 */
6813proto._itemize = function( elems ) {
6814
6815  var itemElems = this._filterFindItemElements( elems );
6816  var Item = this.constructor.Item;
6817
6818  // create new Outlayer Items for collection
6819  var items = [];
6820  for ( var i=0; i < itemElems.length; i++ ) {
6821    var elem = itemElems[i];
6822    var item = new Item( elem, this );
6823    items.push( item );
6824  }
6825
6826  return items;
6827};
6828
6829/**
6830 * get item elements to be used in layout
6831 * @param {Array or NodeList or HTMLElement} elems
6832 * @returns {Array} items - item elements
6833 */
6834proto._filterFindItemElements = function( elems ) {
6835  return utils.filterFindElements( elems, this.options.itemSelector );
6836};
6837
6838/**
6839 * getter method for getting item elements
6840 * @returns {Array} elems - collection of item elements
6841 */
6842proto.getItemElements = function() {
6843  return this.items.map( function( item ) {
6844    return item.element;
6845  });
6846};
6847
6848// ----- init & layout ----- //
6849
6850/**
6851 * lays out all items
6852 */
6853proto.layout = function() {
6854  this._resetLayout();
6855  this._manageStamps();
6856
6857  // don't animate first layout
6858  var layoutInstant = this._getOption('layoutInstant');
6859  var isInstant = layoutInstant !== undefined ?
6860    layoutInstant : !this._isLayoutInited;
6861  this.layoutItems( this.items, isInstant );
6862
6863  // flag for initalized
6864  this._isLayoutInited = true;
6865};
6866
6867// _init is alias for layout
6868proto._init = proto.layout;
6869
6870/**
6871 * logic before any new layout
6872 */
6873proto._resetLayout = function() {
vendor: 45,660 bytes, lines 6874-8723
6874  this.getSize();
6875};
6876
6877
6878proto.getSize = function() {
6879  this.size = getSize( this.element );
6880};
6881
6882/**
6883 * get measurement from option, for columnWidth, rowHeight, gutter
6884 * if option is String -> get element from selector string, & get size of element
6885 * if option is Element -> get size of element
6886 * else use option as a number
6887 *
6888 * @param {String} measurement
6889 * @param {String} size - width or height
6890 * @private
6891 */
6892proto._getMeasurement = function( measurement, size ) {
6893  var option = this.options[ measurement ];
6894  var elem;
6895  if ( !option ) {
6896    // default to 0
6897    this[ measurement ] = 0;
6898  } else {
6899    // use option as an element
6900    if ( typeof option == 'string' ) {
6901      elem = this.element.querySelector( option );
6902    } else if ( option instanceof HTMLElement ) {
6903      elem = option;
6904    }
6905    // use size of element, if element
6906    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
6907  }
6908};
6909
6910/**
6911 * layout a collection of item elements
6912 * @api public
6913 */
6914proto.layoutItems = function( items, isInstant ) {
6915  items = this._getItemsForLayout( items );
6916
6917  this._layoutItems( items, isInstant );
6918
6919  this._postLayout();
6920};
6921
6922/**
6923 * get the items to be laid out
6924 * you may want to skip over some items
6925 * @param {Array} items
6926 * @returns {Array} items
6927 */
6928proto._getItemsForLayout = function( items ) {
6929  return items.filter( function( item ) {
6930    return !item.isIgnored;
6931  });
6932};
6933
6934/**
6935 * layout items
6936 * @param {Array} items
6937 * @param {Boolean} isInstant
6938 */
6939proto._layoutItems = function( items, isInstant ) {
6940  this._emitCompleteOnItems( 'layout', items );
6941
6942  if ( !items || !items.length ) {
6943    // no items, emit event with empty array
6944    return;
6945  }
6946
6947  var queue = [];
6948
6949  items.forEach( function( item ) {
6950    // get x/y object from method
6951    var position = this._getItemLayoutPosition( item );
6952    // enqueue
6953    position.item = item;
6954    position.isInstant = isInstant || item.isLayoutInstant;
6955    queue.push( position );
6956  }, this );
6957
6958  this._processLayoutQueue( queue );
6959};
6960
6961/**
6962 * get item layout position
6963 * @param {Outlayer.Item} item
6964 * @returns {Object} x and y position
6965 */
6966proto._getItemLayoutPosition = function( /* item */ ) {
6967  return {
6968    x: 0,
6969    y: 0
6970  };
6971};
6972
6973/**
6974 * iterate over array and position each item
6975 * Reason being - separating this logic prevents 'layout invalidation'
6976 * thx @paul_irish
6977 * @param {Array} queue
6978 */
6979proto._processLayoutQueue = function( queue ) {
6980  this.updateStagger();
6981  queue.forEach( function( obj, i ) {
6982    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
6983  }, this );
6984};
6985
6986// set stagger from option in milliseconds number
6987proto.updateStagger = function() {
6988  var stagger = this.options.stagger;
6989  if ( stagger === null || stagger === undefined ) {
6990    this.stagger = 0;
6991    return;
6992  }
6993  this.stagger = getMilliseconds( stagger );
6994  return this.stagger;
6995};
6996
6997/**
6998 * Sets position of item in DOM
6999 * @param {Outlayer.Item} item
7000 * @param {Number} x - horizontal position
7001 * @param {Number} y - vertical position
7002 * @param {Boolean} isInstant - disables transitions
7003 */
7004proto._positionItem = function( item, x, y, isInstant, i ) {
7005  if ( isInstant ) {
7006    // if not transition, just set CSS
7007    item.goTo( x, y );
7008  } else {
7009    item.stagger( i * this.stagger );
7010    item.moveTo( x, y );
7011  }
7012};
7013
7014/**
7015 * Any logic you want to do after each layout,
7016 * i.e. size the container
7017 */
7018proto._postLayout = function() {
7019  this.resizeContainer();
7020};
7021
7022proto.resizeContainer = function() {
7023  var isResizingContainer = this._getOption('resizeContainer');
7024  if ( !isResizingContainer ) {
7025    return;
7026  }
7027  var size = this._getContainerSize();
7028  if ( size ) {
7029    this._setContainerMeasure( size.width, true );
7030    this._setContainerMeasure( size.height, false );
7031  }
7032};
7033
7034/**
7035 * Sets width or height of container if returned
7036 * @returns {Object} size
7037 *   @param {Number} width
7038 *   @param {Number} height
7039 */
7040proto._getContainerSize = noop;
7041
7042/**
7043 * @param {Number} measure - size of width or height
7044 * @param {Boolean} isWidth
7045 */
7046proto._setContainerMeasure = function( measure, isWidth ) {
7047  if ( measure === undefined ) {
7048    return;
7049  }
7050
7051  var elemSize = this.size;
7052  // add padding and border width if border box
7053  if ( elemSize.isBorderBox ) {
7054    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
7055      elemSize.borderLeftWidth + elemSize.borderRightWidth :
7056      elemSize.paddingBottom + elemSize.paddingTop +
7057      elemSize.borderTopWidth + elemSize.borderBottomWidth;
7058  }
7059
7060  measure = Math.max( measure, 0 );
7061  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
7062};
7063
7064/**
7065 * emit eventComplete on a collection of items events
7066 * @param {String} eventName
7067 * @param {Array} items - Outlayer.Items
7068 */
7069proto._emitCompleteOnItems = function( eventName, items ) {
7070  var _this = this;
7071  function onComplete() {
7072    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
7073  }
7074
7075  var count = items.length;
7076  if ( !items || !count ) {
7077    onComplete();
7078    return;
7079  }
7080
7081  var doneCount = 0;
7082  function tick() {
7083    doneCount++;
7084    if ( doneCount == count ) {
7085      onComplete();
7086    }
7087  }
7088
7089  // bind callback
7090  items.forEach( function( item ) {
7091    item.once( eventName, tick );
7092  });
7093};
7094
7095/**
7096 * emits events via EvEmitter and jQuery events
7097 * @param {String} type - name of event
7098 * @param {Event} event - original event
7099 * @param {Array} args - extra arguments
7100 */
7101proto.dispatchEvent = function( type, event, args ) {
7102  // add original event to arguments
7103  var emitArgs = event ? [ event ].concat( args ) : args;
7104  this.emitEvent( type, emitArgs );
7105
7106  if ( jQuery ) {
7107    // set this.$element
7108    this.$element = this.$element || jQuery( this.element );
7109    if ( event ) {
7110      // create jQuery event
7111      var $event = jQuery.Event( event );
7112      $event.type = type;
7113      this.$element.trigger( $event, args );
7114    } else {
7115      // just trigger with type if no event available
7116      this.$element.trigger( type, args );
7117    }
7118  }
7119};
7120
7121// -------------------------- ignore & stamps -------------------------- //
7122
7123
7124/**
7125 * keep item in collection, but do not lay it out
7126 * ignored items do not get skipped in layout
7127 * @param {Element} elem
7128 */
7129proto.ignore = function( elem ) {
7130  var item = this.getItem( elem );
7131  if ( item ) {
7132    item.isIgnored = true;
7133  }
7134};
7135
7136/**
7137 * return item to layout collection
7138 * @param {Element} elem
7139 */
7140proto.unignore = function( elem ) {
7141  var item = this.getItem( elem );
7142  if ( item ) {
7143    delete item.isIgnored;
7144  }
7145};
7146
7147/**
7148 * adds elements to stamps
7149 * @param {NodeList, Array, Element, or String} elems
7150 */
7151proto.stamp = function( elems ) {
7152  elems = this._find( elems );
7153  if ( !elems ) {
7154    return;
7155  }
7156
7157  this.stamps = this.stamps.concat( elems );
7158  // ignore
7159  elems.forEach( this.ignore, this );
7160};
7161
7162/**
7163 * removes elements to stamps
7164 * @param {NodeList, Array, or Element} elems
7165 */
7166proto.unstamp = function( elems ) {
7167  elems = this._find( elems );
7168  if ( !elems ){
7169    return;
7170  }
7171
7172  elems.forEach( function( elem ) {
7173    // filter out removed stamp elements
7174    utils.removeFrom( this.stamps, elem );
7175    this.unignore( elem );
7176  }, this );
7177};
7178
7179/**
7180 * finds child elements
7181 * @param {NodeList, Array, Element, or String} elems
7182 * @returns {Array} elems
7183 */
7184proto._find = function( elems ) {
7185  if ( !elems ) {
7186    return;
7187  }
7188  // if string, use argument as selector string
7189  if ( typeof elems == 'string' ) {
7190    elems = this.element.querySelectorAll( elems );
7191  }
7192  elems = utils.makeArray( elems );
7193  return elems;
7194};
7195
7196proto._manageStamps = function() {
7197  if ( !this.stamps || !this.stamps.length ) {
7198    return;
7199  }
7200
7201  this._getBoundingRect();
7202
7203  this.stamps.forEach( this._manageStamp, this );
7204};
7205
7206// update boundingLeft / Top
7207proto._getBoundingRect = function() {
7208  // get bounding rect for container element
7209  var boundingRect = this.element.getBoundingClientRect();
7210  var size = this.size;
7211  this._boundingRect = {
7212    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
7213    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
7214    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
7215    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
7216  };
7217};
7218
7219/**
7220 * @param {Element} stamp
7221**/
7222proto._manageStamp = noop;
7223
7224/**
7225 * get x/y position of element relative to container element
7226 * @param {Element} elem
7227 * @returns {Object} offset - has left, top, right, bottom
7228 */
7229proto._getElementOffset = function( elem ) {
7230  var boundingRect = elem.getBoundingClientRect();
7231  var thisRect = this._boundingRect;
7232  var size = getSize( elem );
7233  var offset = {
7234    left: boundingRect.left - thisRect.left - size.marginLeft,
7235    top: boundingRect.top - thisRect.top - size.marginTop,
7236    right: thisRect.right - boundingRect.right - size.marginRight,
7237    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
7238  };
7239  return offset;
7240};
7241
7242// -------------------------- resize -------------------------- //
7243
7244// enable event handlers for listeners
7245// i.e. resize -> onresize
7246proto.handleEvent = utils.handleEvent;
7247
7248/**
7249 * Bind layout to window resizing
7250 */
7251proto.bindResize = function() {
7252  window.addEventListener( 'resize', this );
7253  this.isResizeBound = true;
7254};
7255
7256/**
7257 * Unbind layout to window resizing
7258 */
7259proto.unbindResize = function() {
7260  window.removeEventListener( 'resize', this );
7261  this.isResizeBound = false;
7262};
7263
7264proto.onresize = function() {
7265  this.resize();
7266};
7267
7268utils.debounceMethod( Outlayer, 'onresize', 100 );
7269
7270proto.resize = function() {
7271  // don't trigger if size did not change
7272  // or if resize was unbound. See #9
7273  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
7274    return;
7275  }
7276
7277  this.layout();
7278};
7279
7280/**
7281 * check if layout is needed post layout
7282 * @returns Boolean
7283 */
7284proto.needsResizeLayout = function() {
7285  var size = getSize( this.element );
7286  // check that this.size and size are there
7287  // IE8 triggers resize on body size change, so they might not be
7288  var hasSizes = this.size && size;
7289  return hasSizes && size.innerWidth !== this.size.innerWidth;
7290};
7291
7292// -------------------------- methods -------------------------- //
7293
7294/**
7295 * add items to Outlayer instance
7296 * @param {Array or NodeList or Element} elems
7297 * @returns {Array} items - Outlayer.Items
7298**/
7299proto.addItems = function( elems ) {
7300  var items = this._itemize( elems );
7301  // add items to collection
7302  if ( items.length ) {
7303    this.items = this.items.concat( items );
7304  }
7305  return items;
7306};
7307
7308/**
7309 * Layout newly-appended item elements
7310 * @param {Array or NodeList or Element} elems
7311 */
7312proto.appended = function( elems ) {
7313  var items = this.addItems( elems );
7314  if ( !items.length ) {
7315    return;
7316  }
7317  // layout and reveal just the new items
7318  this.layoutItems( items, true );
7319  this.reveal( items );
7320};
7321
7322/**
7323 * Layout prepended elements
7324 * @param {Array or NodeList or Element} elems
7325 */
7326proto.prepended = function( elems ) {
7327  var items = this._itemize( elems );
7328  if ( !items.length ) {
7329    return;
7330  }
7331  // add items to beginning of collection
7332  var previousItems = this.items.slice(0);
7333  this.items = items.concat( previousItems );
7334  // start new layout
7335  this._resetLayout();
7336  this._manageStamps();
7337  // layout new stuff without transition
7338  this.layoutItems( items, true );
7339  this.reveal( items );
7340  // layout previous items
7341  this.layoutItems( previousItems );
7342};
7343
7344/**
7345 * reveal a collection of items
7346 * @param {Array of Outlayer.Items} items
7347 */
7348proto.reveal = function( items ) {
7349  this._emitCompleteOnItems( 'reveal', items );
7350  if ( !items || !items.length ) {
7351    return;
7352  }
7353  var stagger = this.updateStagger();
7354  items.forEach( function( item, i ) {
7355    item.stagger( i * stagger );
7356    item.reveal();
7357  });
7358};
7359
7360/**
7361 * hide a collection of items
7362 * @param {Array of Outlayer.Items} items
7363 */
7364proto.hide = function( items ) {
7365  this._emitCompleteOnItems( 'hide', items );
7366  if ( !items || !items.length ) {
7367    return;
7368  }
7369  var stagger = this.updateStagger();
7370  items.forEach( function( item, i ) {
7371    item.stagger( i * stagger );
7372    item.hide();
7373  });
7374};
7375
7376/**
7377 * reveal item elements
7378 * @param {Array}, {Element}, {NodeList} items
7379 */
7380proto.revealItemElements = function( elems ) {
7381  var items = this.getItems( elems );
7382  this.reveal( items );
7383};
7384
7385/**
7386 * hide item elements
7387 * @param {Array}, {Element}, {NodeList} items
7388 */
7389proto.hideItemElements = function( elems ) {
7390  var items = this.getItems( elems );
7391  this.hide( items );
7392};
7393
7394/**
7395 * get Outlayer.Item, given an Element
7396 * @param {Element} elem
7397 * @param {Function} callback
7398 * @returns {Outlayer.Item} item
7399 */
7400proto.getItem = function( elem ) {
7401  // loop through items to get the one that matches
7402  for ( var i=0; i < this.items.length; i++ ) {
7403    var item = this.items[i];
7404    if ( item.element == elem ) {
7405      // return item
7406      return item;
7407    }
7408  }
7409};
7410
7411/**
7412 * get collection of Outlayer.Items, given Elements
7413 * @param {Array} elems
7414 * @returns {Array} items - Outlayer.Items
7415 */
7416proto.getItems = function( elems ) {
7417  elems = utils.makeArray( elems );
7418  var items = [];
7419  elems.forEach( function( elem ) {
7420    var item = this.getItem( elem );
7421    if ( item ) {
7422      items.push( item );
7423    }
7424  }, this );
7425
7426  return items;
7427};
7428
7429/**
7430 * remove element(s) from instance and DOM
7431 * @param {Array or NodeList or Element} elems
7432 */
7433proto.remove = function( elems ) {
7434  var removeItems = this.getItems( elems );
7435
7436  this._emitCompleteOnItems( 'remove', removeItems );
7437
7438  // bail if no items to remove
7439  if ( !removeItems || !removeItems.length ) {
7440    return;
7441  }
7442
7443  removeItems.forEach( function( item ) {
7444    item.remove();
7445    // remove item from collection
7446    utils.removeFrom( this.items, item );
7447  }, this );
7448};
7449
7450// ----- destroy ----- //
7451
7452// remove and disable Outlayer instance
7453proto.destroy = function() {
7454  // clean up dynamic styles
7455  var style = this.element.style;
7456  style.height = '';
7457  style.position = '';
7458  style.width = '';
7459  // destroy items
7460  this.items.forEach( function( item ) {
7461    item.destroy();
7462  });
7463
7464  this.unbindResize();
7465
7466  var id = this.element.outlayerGUID;
7467  delete instances[ id ]; // remove reference to instance by id
7468  delete this.element.outlayerGUID;
7469  // remove data for jQuery
7470  if ( jQuery ) {
7471    jQuery.removeData( this.element, this.constructor.namespace );
7472  }
7473
7474};
7475
7476// -------------------------- data -------------------------- //
7477
7478/**
7479 * get Outlayer instance from element
7480 * @param {Element} elem
7481 * @returns {Outlayer}
7482 */
7483Outlayer.data = function( elem ) {
7484  elem = utils.getQueryElement( elem );
7485  var id = elem && elem.outlayerGUID;
7486  return id && instances[ id ];
7487};
7488
7489
7490// -------------------------- create Outlayer class -------------------------- //
7491
7492/**
7493 * create a layout class
7494 * @param {String} namespace
7495 */
7496Outlayer.create = function( namespace, options ) {
7497  // sub-class Outlayer
7498  var Layout = subclass( Outlayer );
7499  // apply new options and compatOptions
7500  Layout.defaults = utils.extend( {}, Outlayer.defaults );
7501  utils.extend( Layout.defaults, options );
7502  Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );
7503
7504  Layout.namespace = namespace;
7505
7506  Layout.data = Outlayer.data;
7507
7508  // sub-class Item
7509  Layout.Item = subclass( Item );
7510
7511  // -------------------------- declarative -------------------------- //
7512
7513  utils.htmlInit( Layout, namespace );
7514
7515  // -------------------------- jQuery bridge -------------------------- //
7516
7517  // make into jQuery plugin
7518  if ( jQuery && jQuery.bridget ) {
7519    jQuery.bridget( namespace, Layout );
7520  }
7521
7522  return Layout;
7523};
7524
7525function subclass( Parent ) {
7526  function SubClass() {
7527    Parent.apply( this, arguments );
7528  }
7529
7530  SubClass.prototype = Object.create( Parent.prototype );
7531  SubClass.prototype.constructor = SubClass;
7532
7533  return SubClass;
7534}
7535
7536// ----- helpers ----- //
7537
7538// how many milliseconds are in each unit
7539var msUnits = {
7540  ms: 1,
7541  s: 1000
7542};
7543
7544// munge time-like parameter into millisecond number
7545// '0.4s' -> 40
7546function getMilliseconds( time ) {
7547  if ( typeof time == 'number' ) {
7548    return time;
7549  }
7550  var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
7551  var num = matches && matches[1];
7552  var unit = matches && matches[2];
7553  if ( !num.length ) {
7554    return 0;
7555  }
7556  num = parseFloat( num );
7557  var mult = msUnits[ unit ] || 1;
7558  return num * mult;
7559}
7560
7561// ----- fin ----- //
7562
7563// back in global
7564Outlayer.Item = Item;
7565
7566return Outlayer;
7567
7568}));
7569
7570/**
7571 * Rect
7572 * low-level utility class for basic geometry
7573 */
7574
7575( function( window, factory ) {
7576  // universal module definition
7577  /* jshint strict: false */ /* globals define, module */
7578  if ( typeof define == 'function' && define.amd ) {
7579    // AMD
7580    define( 'packery/js/rect',factory );
7581  } else if ( typeof module == 'object' && module.exports ) {
7582    // CommonJS
7583    module.exports = factory();
7584  } else {
7585    // browser global
7586    window.Packery = window.Packery || {};
7587    window.Packery.Rect = factory();
7588  }
7589
7590}( window, function factory() {
7591'use strict';
7592
7593// -------------------------- Rect -------------------------- //
7594
7595function Rect( props ) {
7596  // extend properties from defaults
7597  for ( var prop in Rect.defaults ) {
7598    this[ prop ] = Rect.defaults[ prop ];
7599  }
7600
7601  for ( prop in props ) {
7602    this[ prop ] = props[ prop ];
7603  }
7604
7605}
7606
7607Rect.defaults = {
7608  x: 0,
7609  y: 0,
7610  width: 0,
7611  height: 0
7612};
7613
7614var proto = Rect.prototype;
7615
7616/**
7617 * Determines whether or not this rectangle wholly encloses another rectangle or point.
7618 * @param {Rect} rect
7619 * @returns {Boolean}
7620**/
7621proto.contains = function( rect ) {
7622  // points don't have width or height
7623  var otherWidth = rect.width || 0;
7624  var otherHeight = rect.height || 0;
7625  return this.x <= rect.x &&
7626    this.y <= rect.y &&
7627    this.x + this.width >= rect.x + otherWidth &&
7628    this.y + this.height >= rect.y + otherHeight;
7629};
7630
7631/**
7632 * Determines whether or not the rectangle intersects with another.
7633 * @param {Rect} rect
7634 * @returns {Boolean}
7635**/
7636proto.overlaps = function( rect ) {
7637  var thisRight = this.x + this.width;
7638  var thisBottom = this.y + this.height;
7639  var rectRight = rect.x + rect.width;
7640  var rectBottom = rect.y + rect.height;
7641
7642  // http://stackoverflow.com/a/306332
7643  return this.x < rectRight &&
7644    thisRight > rect.x &&
7645    this.y < rectBottom &&
7646    thisBottom > rect.y;
7647};
7648
7649/**
7650 * @param {Rect} rect - the overlapping rect
7651 * @returns {Array} freeRects - rects representing the area around the rect
7652**/
7653proto.getMaximalFreeRects = function( rect ) {
7654
7655  // if no intersection, return false
7656  if ( !this.overlaps( rect ) ) {
7657    return false;
7658  }
7659
7660  var freeRects = [];
7661  var freeRect;
7662
7663  var thisRight = this.x + this.width;
7664  var thisBottom = this.y + this.height;
7665  var rectRight = rect.x + rect.width;
7666  var rectBottom = rect.y + rect.height;
7667
7668  // top
7669  if ( this.y < rect.y ) {
7670    freeRect = new Rect({
7671      x: this.x,
7672      y: this.y,
7673      width: this.width,
7674      height: rect.y - this.y
7675    });
7676    freeRects.push( freeRect );
7677  }
7678
7679  // right
7680  if ( thisRight > rectRight ) {
7681    freeRect = new Rect({
7682      x: rectRight,
7683      y: this.y,
7684      width: thisRight - rectRight,
7685      height: this.height
7686    });
7687    freeRects.push( freeRect );
7688  }
7689
7690  // bottom
7691  if ( thisBottom > rectBottom ) {
7692    freeRect = new Rect({
7693      x: this.x,
7694      y: rectBottom,
7695      width: this.width,
7696      height: thisBottom - rectBottom
7697    });
7698    freeRects.push( freeRect );
7699  }
7700
7701  // left
7702  if ( this.x < rect.x ) {
7703    freeRect = new Rect({
7704      x: this.x,
7705      y: this.y,
7706      width: rect.x - this.x,
7707      height: this.height
7708    });
7709    freeRects.push( freeRect );
7710  }
7711
7712  return freeRects;
7713};
7714
7715proto.canFit = function( rect ) {
7716  return this.width >= rect.width && this.height >= rect.height;
7717};
7718
7719return Rect;
7720
7721}));
7722
7723/**
7724 * Packer
7725 * bin-packing algorithm
7726 */
7727
7728( function( window, factory ) {
7729  // universal module definition
7730  /* jshint strict: false */ /* globals define, module, require */
7731  if ( typeof define == 'function' && define.amd ) {
7732    // AMD
7733    define( 'packery/js/packer',[ './rect' ], factory );
7734  } else if ( typeof module == 'object' && module.exports ) {
7735    // CommonJS
7736    module.exports = factory(
7737      require('./rect')
7738    );
7739  } else {
7740    // browser global
7741    var Packery = window.Packery = window.Packery || {};
7742    Packery.Packer = factory( Packery.Rect );
7743  }
7744
7745}( window, function factory( Rect ) {
7746'use strict';
7747
7748// -------------------------- Packer -------------------------- //
7749
7750/**
7751 * @param {Number} width
7752 * @param {Number} height
7753 * @param {String} sortDirection
7754 *   topLeft for vertical, leftTop for horizontal
7755 */
7756function Packer( width, height, sortDirection ) {
7757  this.width = width || 0;
7758  this.height = height || 0;
7759  this.sortDirection = sortDirection || 'downwardLeftToRight';
7760
7761  this.reset();
7762}
7763
7764var proto = Packer.prototype;
7765
7766proto.reset = function() {
7767  this.spaces = [];
7768
7769  var initialSpace = new Rect({
7770    x: 0,
7771    y: 0,
7772    width: this.width,
7773    height: this.height
7774  });
7775
7776  this.spaces.push( initialSpace );
7777  // set sorter
7778  this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
7779};
7780
7781// change x and y of rect to fit with in Packer's available spaces
7782proto.pack = function( rect ) {
7783  for ( var i=0; i < this.spaces.length; i++ ) {
7784    var space = this.spaces[i];
7785    if ( space.canFit( rect ) ) {
7786      this.placeInSpace( rect, space );
7787      break;
7788    }
7789  }
7790};
7791
7792proto.columnPack = function( rect ) {
7793  for ( var i=0; i < this.spaces.length; i++ ) {
7794    var space = this.spaces[i];
7795    var canFitInSpaceColumn = space.x <= rect.x &&
7796      space.x + space.width >= rect.x + rect.width &&
7797      space.height >= rect.height - 0.01; // fudge number for rounding error
7798    if ( canFitInSpaceColumn ) {
7799      rect.y = space.y;
7800      this.placed( rect );
7801      break;
7802    }
7803  }
7804};
7805
7806proto.rowPack = function( rect ) {
7807  for ( var i=0; i < this.spaces.length; i++ ) {
7808    var space = this.spaces[i];
7809    var canFitInSpaceRow = space.y <= rect.y &&
7810      space.y + space.height >= rect.y + rect.height &&
7811      space.width >= rect.width - 0.01; // fudge number for rounding error
7812    if ( canFitInSpaceRow ) {
7813      rect.x = space.x;
7814      this.placed( rect );
7815      break;
7816    }
7817  }
7818};
7819
7820proto.placeInSpace = function( rect, space ) {
7821  // place rect in space
7822  rect.x = space.x;
7823  rect.y = space.y;
7824
7825  this.placed( rect );
7826};
7827
7828// update spaces with placed rect
7829proto.placed = function( rect ) {
7830  // update spaces
7831  var revisedSpaces = [];
7832  for ( var i=0; i < this.spaces.length; i++ ) {
7833    var space = this.spaces[i];
7834    var newSpaces = space.getMaximalFreeRects( rect );
7835    // add either the original space or the new spaces to the revised spaces
7836    if ( newSpaces ) {
7837      revisedSpaces.push.apply( revisedSpaces, newSpaces );
7838    } else {
7839      revisedSpaces.push( space );
7840    }
7841  }
7842
7843  this.spaces = revisedSpaces;
7844
7845  this.mergeSortSpaces();
7846};
7847
7848proto.mergeSortSpaces = function() {
7849  // remove redundant spaces
7850  Packer.mergeRects( this.spaces );
7851  this.spaces.sort( this.sorter );
7852};
7853
7854// add a space back
7855proto.addSpace = function( rect ) {
7856  this.spaces.push( rect );
7857  this.mergeSortSpaces();
7858};
7859
7860// -------------------------- utility functions -------------------------- //
7861
7862/**
7863 * Remove redundant rectangle from array of rectangles
7864 * @param {Array} rects: an array of Rects
7865 * @returns {Array} rects: an array of Rects
7866**/
7867Packer.mergeRects = function( rects ) {
7868  var i = 0;
7869  var rect = rects[i];
7870
7871  rectLoop:
7872  while ( rect ) {
7873    var j = 0;
7874    var compareRect = rects[ i + j ];
7875
7876    while ( compareRect ) {
7877      if  ( compareRect == rect ) {
7878        j++; // next
7879      } else if ( compareRect.contains( rect ) ) {
7880        // remove rect
7881        rects.splice( i, 1 );
7882        rect = rects[i]; // set next rect
7883        continue rectLoop; // bail on compareLoop
7884      } else if ( rect.contains( compareRect ) ) {
7885        // remove compareRect
7886        rects.splice( i + j, 1 );
7887      } else {
7888        j++;
7889      }
7890      compareRect = rects[ i + j ]; // set next compareRect
7891    }
7892    i++;
7893    rect = rects[i];
7894  }
7895
7896  return rects;
7897};
7898
7899
7900// -------------------------- sorters -------------------------- //
7901
7902// functions for sorting rects in order
7903var sorters = {
7904  // top down, then left to right
7905  downwardLeftToRight: function( a, b ) {
7906    return a.y - b.y || a.x - b.x;
7907  },
7908  // left to right, then top down
7909  rightwardTopToBottom: function( a, b ) {
7910    return a.x - b.x || a.y - b.y;
7911  }
7912};
7913
7914
7915// --------------------------  -------------------------- //
7916
7917return Packer;
7918
7919}));
7920
7921/**
7922 * Packery Item Element
7923**/
7924
7925( function( window, factory ) {
7926  // universal module definition
7927  /* jshint strict: false */ /* globals define, module, require */
7928  if ( typeof define == 'function' && define.amd ) {
7929    // AMD
7930    define( 'packery/js/item',[
7931        'outlayer/outlayer',
7932        './rect'
7933      ],
7934      factory );
7935  } else if ( typeof module == 'object' && module.exports ) {
7936    // CommonJS
7937    module.exports = factory(
7938      require('outlayer'),
7939      require('./rect')
7940    );
7941  } else {
7942    // browser global
7943    window.Packery.Item = factory(
7944      window.Outlayer,
7945      window.Packery.Rect
7946    );
7947  }
7948
7949}( window, function factory( Outlayer, Rect ) {
7950'use strict';
7951
7952// -------------------------- Item -------------------------- //
7953
7954var docElemStyle = document.documentElement.style;
7955
7956var transformProperty = typeof docElemStyle.transform == 'string' ?
7957  'transform' : 'WebkitTransform';
7958
7959// sub-class Item
7960var Item = function PackeryItem() {
7961  Outlayer.Item.apply( this, arguments );
7962};
7963
7964var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
7965
7966var __create = proto._create;
7967proto._create = function() {
7968  // call default _create logic
7969  __create.call( this );
7970  this.rect = new Rect();
7971};
7972
7973var _moveTo = proto.moveTo;
7974proto.moveTo = function( x, y ) {
7975  // don't shift 1px while dragging
7976  var dx = Math.abs( this.position.x - x );
7977  var dy = Math.abs( this.position.y - y );
7978
7979  var canHackGoTo = this.layout.dragItemCount && !this.isPlacing &&
7980    !this.isTransitioning && dx < 1 && dy < 1;
7981  if ( canHackGoTo ) {
7982    this.goTo( x, y );
7983    return;
7984  }
7985  _moveTo.apply( this, arguments );
7986};
7987
7988// -------------------------- placing -------------------------- //
7989
7990proto.enablePlacing = function() {
7991  this.removeTransitionStyles();
7992  // remove transform property from transition
7993  if ( this.isTransitioning && transformProperty ) {
7994    this.element.style[ transformProperty ] = 'none';
7995  }
7996  this.isTransitioning = false;
7997  this.getSize();
7998  this.layout._setRectSize( this.element, this.rect );
7999  this.isPlacing = true;
8000};
8001
8002proto.disablePlacing = function() {
8003  this.isPlacing = false;
8004};
8005
8006// -----  ----- //
8007
8008// remove element from DOM
8009proto.removeElem = function() {
8010  var parent = this.element.parentNode;
8011  if ( parent ) {
8012    parent.removeChild( this.element );
8013  }
8014  // add space back to packer
8015  this.layout.packer.addSpace( this.rect );
8016  this.emitEvent( 'remove', [ this ] );
8017};
8018
8019// ----- dropPlaceholder ----- //
8020
8021proto.showDropPlaceholder = function() {
8022  var dropPlaceholder = this.dropPlaceholder;
8023  if ( !dropPlaceholder ) {
8024    // create dropPlaceholder
8025    dropPlaceholder = this.dropPlaceholder = document.createElement('div');
8026    dropPlaceholder.className = 'packery-drop-placeholder';
8027    dropPlaceholder.style.position = 'absolute';
8028  }
8029
8030  dropPlaceholder.style.width = this.size.width + 'px';
8031  dropPlaceholder.style.height = this.size.height + 'px';
8032  this.positionDropPlaceholder();
8033  this.layout.element.appendChild( dropPlaceholder );
8034};
8035
8036proto.positionDropPlaceholder = function() {
8037  this.dropPlaceholder.style[ transformProperty ] = 'translate(' +
8038    this.rect.x + 'px, ' + this.rect.y + 'px)';
8039};
8040
8041proto.hideDropPlaceholder = function() {
8042  // only remove once, #333
8043  var parent = this.dropPlaceholder.parentNode;
8044  if ( parent ) {
8045    parent.removeChild( this.dropPlaceholder );
8046  }
8047};
8048
8049// -----  ----- //
8050
8051return Item;
8052
8053}));
8054
8055/*!
8056 * Packery v2.1.2
8057 * Gapless, draggable grid layouts
8058 *
8059 * Licensed GPLv3 for open source use
8060 * or Packery Commercial License for commercial use
8061 *
8062 * http://packery.metafizzy.co
8063 * Copyright 2013-2018 Metafizzy
8064 */
8065
8066( function( window, factory ) {
8067  // universal module definition
8068  /* jshint strict: false */ /* globals define, module, require */
8069  if ( typeof define == 'function' && define.amd ) {
8070    // AMD
8071    define( [
8072        'get-size/get-size',
8073        'outlayer/outlayer',
8074        'packery/js/rect',
8075        'packery/js/packer',
8076        'packery/js/item'
8077      ],
8078      factory );
8079  } else if ( typeof module == 'object' && module.exports ) {
8080    // CommonJS
8081    module.exports = factory(
8082      require('get-size'),
8083      require('outlayer'),
8084      require('./rect'),
8085      require('./packer'),
8086      require('./item')
8087    );
8088  } else {
8089    // browser global
8090    window.Packery = factory(
8091      window.getSize,
8092      window.Outlayer,
8093      window.Packery.Rect,
8094      window.Packery.Packer,
8095      window.Packery.Item
8096    );
8097  }
8098
8099}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) {
8100'use strict';
8101
8102// ----- Rect ----- //
8103
8104// allow for pixel rounding errors IE8-IE11 & Firefox; #227
8105Rect.prototype.canFit = function( rect ) {
8106  return this.width >= rect.width - 1 && this.height >= rect.height - 1;
8107};
8108
8109// -------------------------- Packery -------------------------- //
8110
8111// create an Outlayer layout class
8112var Packery = Outlayer.create('packery');
8113Packery.Item = Item;
8114
8115var proto = Packery.prototype;
8116
8117proto._create = function() {
8118  // call super
8119  Outlayer.prototype._create.call( this );
8120
8121  // initial properties
8122  this.packer = new Packer();
8123  // packer for drop targets
8124  this.shiftPacker = new Packer();
8125  this.isEnabled = true;
8126
8127  this.dragItemCount = 0;
8128
8129  // create drag handlers
8130  var _this = this;
8131  this.handleDraggabilly = {
8132    dragStart: function() {
8133      _this.itemDragStart( this.element );
8134    },
8135    dragMove: function() {
8136      _this.itemDragMove( this.element, this.position.x, this.position.y );
8137    },
8138    dragEnd: function() {
8139      _this.itemDragEnd( this.element );
8140    }
8141  };
8142
8143  this.handleUIDraggable = {
8144    start: function handleUIDraggableStart( event, ui ) {
8145      // HTML5 may trigger dragstart, dismiss HTML5 dragging
8146      if ( !ui ) {
8147        return;
8148      }
8149      _this.itemDragStart( event.currentTarget );
8150    },
8151    drag: function handleUIDraggableDrag( event, ui ) {
8152      if ( !ui ) {
8153        return;
8154      }
8155      _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
8156    },
8157    stop: function handleUIDraggableStop( event, ui ) {
8158      if ( !ui ) {
8159        return;
8160      }
8161      _this.itemDragEnd( event.currentTarget );
8162    }
8163  };
8164
8165};
8166
8167
8168// ----- init & layout ----- //
8169
8170/**
8171 * logic before any new layout
8172 */
8173proto._resetLayout = function() {
8174  this.getSize();
8175
8176  this._getMeasurements();
8177
8178  // reset packer
8179  var width, height, sortDirection;
8180  // packer settings, if horizontal or vertical
8181  if ( this._getOption('horizontal') ) {
8182    width = Infinity;
8183    height = this.size.innerHeight + this.gutter;
8184    sortDirection = 'rightwardTopToBottom';
8185  } else {
8186    width = this.size.innerWidth + this.gutter;
8187    height = Infinity;
8188    sortDirection = 'downwardLeftToRight';
8189  }
8190
8191  this.packer.width = this.shiftPacker.width = width;
8192  this.packer.height = this.shiftPacker.height = height;
8193  this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection;
8194
8195  this.packer.reset();
8196
8197  // layout
8198  this.maxY = 0;
8199  this.maxX = 0;
8200};
8201
8202/**
8203 * update columnWidth, rowHeight, & gutter
8204 * @private
8205 */
8206proto._getMeasurements = function() {
8207  this._getMeasurement( 'columnWidth', 'width' );
8208  this._getMeasurement( 'rowHeight', 'height' );
8209  this._getMeasurement( 'gutter', 'width' );
8210};
8211
8212proto._getItemLayoutPosition = function( item ) {
8213  this._setRectSize( item.element, item.rect );
8214  if ( this.isShifting || this.dragItemCount > 0 ) {
8215    var packMethod = this._getPackMethod();
8216    this.packer[ packMethod ]( item.rect );
8217  } else {
8218    this.packer.pack( item.rect );
8219  }
8220
8221  this._setMaxXY( item.rect );
8222  return item.rect;
8223};
8224
8225proto.shiftLayout = function() {
8226  this.isShifting = true;
8227  this.layout();
8228  delete this.isShifting;
8229};
8230
8231proto._getPackMethod = function() {
8232  return this._getOption('horizontal') ? 'rowPack' : 'columnPack';
8233};
8234
8235
8236/**
8237 * set max X and Y value, for size of container
8238 * @param {Packery.Rect} rect
8239 * @private
8240 */
8241proto._setMaxXY = function( rect ) {
8242  this.maxX = Math.max( rect.x + rect.width, this.maxX );
8243  this.maxY = Math.max( rect.y + rect.height, this.maxY );
8244};
8245
8246/**
8247 * set the width and height of a rect, applying columnWidth and rowHeight
8248 * @param {Element} elem
8249 * @param {Packery.Rect} rect
8250 */
8251proto._setRectSize = function( elem, rect ) {
8252  var size = getSize( elem );
8253  var w = size.outerWidth;
8254  var h = size.outerHeight;
8255  // size for columnWidth and rowHeight, if available
8256  // only check if size is non-zero, #177
8257  if ( w || h ) {
8258    w = this._applyGridGutter( w, this.columnWidth );
8259    h = this._applyGridGutter( h, this.rowHeight );
8260  }
8261  // rect must fit in packer
8262  rect.width = Math.min( w, this.packer.width );
8263  rect.height = Math.min( h, this.packer.height );
8264};
8265
8266/**
8267 * fits item to columnWidth/rowHeight and adds gutter
8268 * @param {Number} measurement - item width or height
8269 * @param {Number} gridSize - columnWidth or rowHeight
8270 * @returns measurement
8271 */
8272proto._applyGridGutter = function( measurement, gridSize ) {
8273  // just add gutter if no gridSize
8274  if ( !gridSize ) {
8275    return measurement + this.gutter;
8276  }
8277  gridSize += this.gutter;
8278  // fit item to columnWidth/rowHeight
8279  var remainder = measurement % gridSize;
8280  var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
8281  measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize;
8282  return measurement;
8283};
8284
8285proto._getContainerSize = function() {
8286  if ( this._getOption('horizontal') ) {
8287    return {
8288      width: this.maxX - this.gutter
8289    };
8290  } else {
8291    return {
8292      height: this.maxY - this.gutter
8293    };
8294  }
8295};
8296
8297
8298// -------------------------- stamp -------------------------- //
8299
8300/**
8301 * makes space for element
8302 * @param {Element} elem
8303 */
8304proto._manageStamp = function( elem ) {
8305
8306  var item = this.getItem( elem );
8307  var rect;
8308  if ( item && item.isPlacing ) {
8309    rect = item.rect;
8310  } else {
8311    var offset = this._getElementOffset( elem );
8312    rect = new Rect({
8313      x: this._getOption('originLeft') ? offset.left : offset.right,
8314      y: this._getOption('originTop') ? offset.top : offset.bottom
8315    });
8316  }
8317
8318  this._setRectSize( elem, rect );
8319  // save its space in the packer
8320  this.packer.placed( rect );
8321  this._setMaxXY( rect );
8322};
8323
8324// -------------------------- methods -------------------------- //
8325
8326function verticalSorter( a, b ) {
8327  return a.position.y - b.position.y || a.position.x - b.position.x;
8328}
8329
8330function horizontalSorter( a, b ) {
8331  return a.position.x - b.position.x || a.position.y - b.position.y;
8332}
8333
8334proto.sortItemsByPosition = function() {
8335  var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter;
8336  this.items.sort( sorter );
8337};
8338
8339/**
8340 * Fit item element in its current position
8341 * Packery will position elements around it
8342 * useful for expanding elements
8343 *
8344 * @param {Element} elem
8345 * @param {Number} x - horizontal destination position, optional
8346 * @param {Number} y - vertical destination position, optional
8347 */
8348proto.fit = function( elem, x, y ) {
8349  var item = this.getItem( elem );
8350  if ( !item ) {
8351    return;
8352  }
8353
8354  // stamp item to get it out of layout
8355  this.stamp( item.element );
8356  // set placing flag
8357  item.enablePlacing();
8358  this.updateShiftTargets( item );
8359  // fall back to current position for fitting
8360  x = x === undefined ? item.rect.x: x;
8361  y = y === undefined ? item.rect.y: y;
8362  // position it best at its destination
8363  this.shift( item, x, y );
8364  this._bindFitEvents( item );
8365  item.moveTo( item.rect.x, item.rect.y );
8366  // layout everything else
8367  this.shiftLayout();
8368  // return back to regularly scheduled programming
8369  this.unstamp( item.element );
8370  this.sortItemsByPosition();
8371  item.disablePlacing();
8372};
8373
8374/**
8375 * emit event when item is fit and other items are laid out
8376 * @param {Packery.Item} item
8377 * @private
8378 */
8379proto._bindFitEvents = function( item ) {
8380  var _this = this;
8381  var ticks = 0;
8382  function onLayout() {
8383    ticks++;
8384    if ( ticks != 2 ) {
8385      return;
8386    }
8387    _this.dispatchEvent( 'fitComplete', null, [ item ] );
8388  }
8389  // when item is laid out
8390  item.once( 'layout', onLayout );
8391  // when all items are laid out
8392  this.once( 'layoutComplete', onLayout );
8393};
8394
8395// -------------------------- resize -------------------------- //
8396
8397// debounced, layout on resize
8398proto.resize = function() {
8399  // don't trigger if size did not change
8400  // or if resize was unbound. See #285, outlayer#9
8401  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
8402    return;
8403  }
8404
8405  if ( this.options.shiftPercentResize ) {
8406    this.resizeShiftPercentLayout();
8407  } else {
8408    this.layout();
8409  }
8410};
8411
8412/**
8413 * check if layout is needed post layout
8414 * @returns Boolean
8415 */
8416proto.needsResizeLayout = function() {
8417  var size = getSize( this.element );
8418  var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth';
8419  return size[ innerSize ] != this.size[ innerSize ];
8420};
8421
8422proto.resizeShiftPercentLayout = function() {
8423  var items = this._getItemsForLayout( this.items );
8424
8425  var isHorizontal = this._getOption('horizontal');
8426  var coord = isHorizontal ? 'y' : 'x';
8427  var measure = isHorizontal ? 'height' : 'width';
8428  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
8429  var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth';
8430
8431  // proportional re-align items
8432  var previousSegment = this[ segmentName ];
8433  previousSegment = previousSegment && previousSegment + this.gutter;
8434
8435  if ( previousSegment ) {
8436    this._getMeasurements();
8437    var currentSegment = this[ segmentName ] + this.gutter;
8438    items.forEach( function( item ) {
8439      var seg = Math.round( item.rect[ coord ] / previousSegment );
8440      item.rect[ coord ] = seg * currentSegment;
8441    });
8442  } else {
8443    var currentSize = getSize( this.element )[ innerSize ] + this.gutter;
8444    var previousSize = this.packer[ measure ];
8445    items.forEach( function( item ) {
8446      item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize;
8447    });
8448  }
8449
8450  this.shiftLayout();
8451};
8452
8453// -------------------------- drag -------------------------- //
8454
8455/**
8456 * handle an item drag start event
8457 * @param {Element} elem
8458 */
8459proto.itemDragStart = function( elem ) {
8460  if ( !this.isEnabled ) {
8461    return;
8462  }
8463  this.stamp( elem );
8464  // this.ignore( elem );
8465  var item = this.getItem( elem );
8466  if ( !item ) {
8467    return;
8468  }
8469
8470  item.enablePlacing();
8471  item.showDropPlaceholder();
8472  this.dragItemCount++;
8473  this.updateShiftTargets( item );
8474};
8475
8476proto.updateShiftTargets = function( dropItem ) {
8477  this.shiftPacker.reset();
8478
8479  // pack stamps
8480  this._getBoundingRect();
8481  var isOriginLeft = this._getOption('originLeft');
8482  var isOriginTop = this._getOption('originTop');
8483  this.stamps.forEach( function( stamp ) {
8484    // ignore dragged item
8485    var item = this.getItem( stamp );
8486    if ( item && item.isPlacing ) {
8487      return;
8488    }
8489    var offset = this._getElementOffset( stamp );
8490    var rect = new Rect({
8491      x: isOriginLeft ? offset.left : offset.right,
8492      y: isOriginTop ? offset.top : offset.bottom
8493    });
8494    this._setRectSize( stamp, rect );
8495    // save its space in the packer
8496    this.shiftPacker.placed( rect );
8497  }, this );
8498
8499  // reset shiftTargets
8500  var isHorizontal = this._getOption('horizontal');
8501  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
8502  var measure = isHorizontal ? 'height' : 'width';
8503
8504  this.shiftTargetKeys = [];
8505  this.shiftTargets = [];
8506  var boundsSize;
8507  var segment = this[ segmentName ];
8508  segment = segment && segment + this.gutter;
8509
8510  if ( segment ) {
8511    var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment );
8512    var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment );
8513    boundsSize = ( segs - segmentSpan ) * segment;
8514    // add targets on top
8515    for ( var i=0; i < segs; i++ ) {
8516      var initialX = isHorizontal ? 0 : i * segment;
8517      var initialY = isHorizontal ? i * segment : 0;
8518      this._addShiftTarget( initialX, initialY, boundsSize );
8519    }
8520  } else {
8521    boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ];
8522    this._addShiftTarget( 0, 0, boundsSize );
8523  }
8524
8525  // pack each item to measure where shiftTargets are
8526  var items = this._getItemsForLayout( this.items );
8527  var packMethod = this._getPackMethod();
8528  items.forEach( function( item ) {
8529    var rect = item.rect;
8530    this._setRectSize( item.element, rect );
8531    this.shiftPacker[ packMethod ]( rect );
8532
8533    // add top left corner
8534    this._addShiftTarget( rect.x, rect.y, boundsSize );
8535    // add bottom left / top right corner
8536    var cornerX = isHorizontal ? rect.x + rect.width : rect.x;
8537    var cornerY = isHorizontal ? rect.y : rect.y + rect.height;
8538    this._addShiftTarget( cornerX, cornerY, boundsSize );
8539
8540    if ( segment ) {
8541      // add targets for each column on bottom / row on right
8542      var segSpan = Math.round( rect[ measure ] / segment );
8543      for ( var i=1; i < segSpan; i++ ) {
8544        var segX = isHorizontal ? cornerX : rect.x + segment * i;
8545        var segY = isHorizontal ? rect.y + segment * i : cornerY;
8546        this._addShiftTarget( segX, segY, boundsSize );
8547      }
8548    }
8549  }, this );
8550
8551};
8552
8553proto._addShiftTarget = function( x, y, boundsSize ) {
8554  var checkCoord = this._getOption('horizontal') ? y : x;
8555  if ( checkCoord !== 0 && checkCoord > boundsSize ) {
8556    return;
8557  }
8558  // create string for a key, easier to keep track of what targets
8559  var key = x + ',' + y;
8560  var hasKey = this.shiftTargetKeys.indexOf( key ) != -1;
8561  if ( hasKey ) {
8562    return;
8563  }
8564  this.shiftTargetKeys.push( key );
8565  this.shiftTargets.push({ x: x, y: y });
8566};
8567
8568// -------------------------- drop -------------------------- //
8569
8570proto.shift = function( item, x, y ) {
8571  var shiftPosition;
8572  var minDistance = Infinity;
8573  var position = { x: x, y: y };
8574  this.shiftTargets.forEach( function( target ) {
8575    var distance = getDistance( target, position );
8576    if ( distance < minDistance ) {
8577      shiftPosition = target;
8578      minDistance = distance;
8579    }
8580  });
8581  item.rect.x = shiftPosition.x;
8582  item.rect.y = shiftPosition.y;
8583};
8584
8585function getDistance( a, b ) {
8586  var dx = b.x - a.x;
8587  var dy = b.y - a.y;
8588  return Math.sqrt( dx * dx + dy * dy );
8589}
8590
8591// -------------------------- drag move -------------------------- //
8592
8593var DRAG_THROTTLE_TIME = 120;
8594
8595/**
8596 * handle an item drag move event
8597 * @param {Element} elem
8598 * @param {Number} x - horizontal change in position
8599 * @param {Number} y - vertical change in position
8600 */
8601proto.itemDragMove = function( elem, x, y ) {
8602  var item = this.isEnabled && this.getItem( elem );
8603  if ( !item ) {
8604    return;
8605  }
8606
8607  x -= this.size.paddingLeft;
8608  y -= this.size.paddingTop;
8609
8610  var _this = this;
8611  function onDrag() {
8612    _this.shift( item, x, y );
8613    item.positionDropPlaceholder();
8614    _this.layout();
8615  }
8616
8617  // throttle
8618  var now = new Date();
8619  var isThrottled = this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME;
8620  if ( isThrottled ) {
8621    clearTimeout( this.dragTimeout );
8622    this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME );
8623  } else {
8624    onDrag();
8625    this._itemDragTime = now;
8626  }
8627};
8628
8629// -------------------------- drag end -------------------------- //
8630
8631/**
8632 * handle an item drag end event
8633 * @param {Element} elem
8634 */
8635proto.itemDragEnd = function( elem ) {
8636  var item = this.isEnabled && this.getItem( elem );
8637  if ( !item ) {
8638    return;
8639  }
8640
8641  clearTimeout( this.dragTimeout );
8642  item.element.classList.add('is-positioning-post-drag');
8643
8644  var completeCount = 0;
8645  var _this = this;
8646  function onDragEndLayoutComplete() {
8647    completeCount++;
8648    if ( completeCount != 2 ) {
8649      return;
8650    }
8651    // reset drag item
8652    item.element.classList.remove('is-positioning-post-drag');
8653    item.hideDropPlaceholder();
8654    _this.dispatchEvent( 'dragItemPositioned', null, [ item ] );
8655  }
8656
8657  item.once( 'layout', onDragEndLayoutComplete );
8658  this.once( 'layoutComplete', onDragEndLayoutComplete );
8659  item.moveTo( item.rect.x, item.rect.y );
8660  this.layout();
8661  this.dragItemCount = Math.max( 0, this.dragItemCount - 1 );
8662  this.sortItemsByPosition();
8663  item.disablePlacing();
8664  this.unstamp( item.element );
8665};
8666
8667/**
8668 * binds Draggabilly events
8669 * @param {Draggabilly} draggie
8670 */
8671proto.bindDraggabillyEvents = function( draggie ) {
8672  this._bindDraggabillyEvents( draggie, 'on' );
8673};
8674
8675proto.unbindDraggabillyEvents = function( draggie ) {
8676  this._bindDraggabillyEvents( draggie, 'off' );
8677};
8678
8679proto._bindDraggabillyEvents = function( draggie, method ) {
8680  var handlers = this.handleDraggabilly;
8681  draggie[ method ]( 'dragStart', handlers.dragStart );
8682  draggie[ method ]( 'dragMove', handlers.dragMove );
8683  draggie[ method ]( 'dragEnd', handlers.dragEnd );
8684};
8685
8686/**
8687 * binds jQuery UI Draggable events
8688 * @param {jQuery} $elems
8689 */
8690proto.bindUIDraggableEvents = function( $elems ) {
8691  this._bindUIDraggableEvents( $elems, 'on' );
8692};
8693
8694proto.unbindUIDraggableEvents = function( $elems ) {
8695  this._bindUIDraggableEvents( $elems, 'off' );
8696};
8697
8698proto._bindUIDraggableEvents = function( $elems, method ) {
8699  var handlers = this.handleUIDraggable;
8700  $elems
8701    [ method ]( 'dragstart', handlers.start )
8702    [ method ]( 'drag', handlers.drag )
8703    [ method ]( 'dragstop', handlers.stop );
8704};
8705
8706// ----- destroy ----- //
8707
8708var _destroy = proto.destroy;
8709proto.destroy = function() {
8710  _destroy.apply( this, arguments );
8711  // disable flag; prevent drag events from triggering. #72
8712  this.isEnabled = false;
8713};
8714
8715// -----  ----- //
8716
8717Packery.Rect = Rect;
8718Packery.Packer = Packer;
8719
8720return Packery;
8721
8722}));
8723
8724
8725/*!
8726Waypoints - 4.0.0
8727Copyright © 2011-2015 Caleb Troughton
8728Licensed under the MIT license.
8729https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
8730*/
8731(function() {
8732  'use strict'
8733
8734  var keyCounter = 0
8735  var allWaypoints = {}
8736
8737  /* http://imakewebthings.com/waypoints/api/waypoint */
8738  function Waypoint(options) {
8739    if (!options) {
8740      throw new Error('No options passed to Waypoint constructor')
8741    }
8742    if (!options.element) {
8743      throw new Error('No element option passed to Waypoint constructor')
8744    }
8745    if (!options.handler) {
8746      throw new Error('No handler option passed to Waypoint constructor')
8747    }
8748
8749    this.key = 'waypoint-' + keyCounter
8750    this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
8751    this.element = this.options.element
8752    this.adapter = new Waypoint.Adapter(this.element)
8753    this.callback = options.handler
8754    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
8755    this.enabled = this.options.enabled
8756    this.triggerPoint = null
8757    this.group = Waypoint.Group.findOrCreate({
8758      name: this.options.group,
8759      axis: this.axis
8760    })
8761    this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
8762
8763    if (Waypoint.offsetAliases[this.options.offset]) {
8764      this.options.offset = Waypoint.offsetAliases[this.options.offset]
8765    }
8766    this.group.add(this)
8767    this.context.add(this)
8768    allWaypoints[this.key] = this
8769    keyCounter += 1
8770  }
8771
8772  /* Private */
8773  Waypoint.prototype.queueTrigger = function(direction) {
8774    this.group.queueTrigger(this, direction)
8775  }
8776
8777  /* Private */
8778  Waypoint.prototype.trigger = function(args) {
8779    if (!this.enabled) {
8780      return
8781    }
8782    if (this.callback) {
8783      this.callback.apply(this, args)
8784    }
8785  }
8786
8787  /* Public */
8788  /* http://imakewebthings.com/waypoints/api/destroy */
8789  Waypoint.prototype.destroy = function() {
8790    this.context.remove(this)
8791    this.group.remove(this)
8792    delete allWaypoints[this.key]
8793  }
8794
8795  /* Public */
8796  /* http://imakewebthings.com/waypoints/api/disable */
8797  Waypoint.prototype.disable = function() {
8798    this.enabled = false
8799    return this
8800  }
8801
8802  /* Public */
8803  /* http://imakewebthings.com/waypoints/api/enable */
8804  Waypoint.prototype.enable = function() {
8805    this.context.refresh()
8806    this.enabled = true
8807    return this
8808  }
8809
8810  /* Public */
8811  /* http://imakewebthings.com/waypoints/api/next */
8812  Waypoint.prototype.next = function() {
8813    return this.group.next(this)
8814  }
8815
8816  /* Public */
8817  /* http://imakewebthings.com/waypoints/api/previous */
8818  Waypoint.prototype.previous = function() {
8819    return this.group.previous(this)
8820  }
8821
8822  /* Private */
8823  Waypoint.invokeAll = function(method) {
8824    var allWaypointsArray = []
8825    for (var waypointKey in allWaypoints) {
8826      allWaypointsArray.push(allWaypoints[waypointKey])
8827    }
8828    for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
8829      allWaypointsArray[i][method]()
8830    }
8831  }
8832
8833  /* Public */
8834  /* http://imakewebthings.com/waypoints/api/destroy-all */
8835  Waypoint.destroyAll = function() {
8836    Waypoint.invokeAll('destroy')
8837  }
8838
8839  /* Public */
8840  /* http://imakewebthings.com/waypoints/api/disable-all */
8841  Waypoint.disableAll = function() {
8842    Waypoint.invokeAll('disable')
8843  }
8844
8845  /* Public */
8846  /* http://imakewebthings.com/waypoints/api/enable-all */
8847  Waypoint.enableAll = function() {
8848    Waypoint.invokeAll('enable')
8849  }
8850
8851  /* Public */
8852  /* http://imakewebthings.com/waypoints/api/refresh-all */
8853  Waypoint.refreshAll = function() {
8854    Waypoint.Context.refreshAll()
8855  }
8856
8857  /* Public */
8858  /* http://imakewebthings.com/waypoints/api/viewport-height */
8859  Waypoint.viewportHeight = function() {
8860    return window.innerHeight || document.documentElement.clientHeight
8861  }
8862
8863  /* Public */
8864  /* http://imakewebthings.com/waypoints/api/viewport-width */
8865  Waypoint.viewportWidth = function() {
8866    return document.documentElement.clientWidth
8867  }
8868
8869  Waypoint.adapters = []
8870
8871  Waypoint.defaults = {
8872    context: window,
8873    continuous: true,
8874    enabled: true,
8875    group: 'default',
8876    horizontal: false,
8877    offset: 0
8878  }
8879
8880  Waypoint.offsetAliases = {
8881    'bottom-in-view': function() {
8882      return this.context.innerHeight() - this.adapter.outerHeight()
8883    },
8884    'right-in-view': function() {
8885      return this.context.innerWidth() - this.adapter.outerWidth()
8886    }
8887  }
8888
8889  window.Waypoint = Waypoint
8890}())
8891;(function() {
8892  'use strict'
8893
8894  function requestAnimationFrameShim(callback) {
8895    window.setTimeout(callback, 1000 / 60)
8896  }
8897
8898  var keyCounter = 0
8899  var contexts = {}
8900  var Waypoint = window.Waypoint
8901  var oldWindowLoad = window.onload
8902
8903  /* http://imakewebthings.com/waypoints/api/context */
8904  function Context(element) {
8905    this.element = element
8906    this.Adapter = Waypoint.Adapter
8907    this.adapter = new this.Adapter(element)
8908    this.key = 'waypoint-context-' + keyCounter
8909    this.didScroll = false
8910    this.didResize = false
8911    this.oldScroll = {
8912      x: this.adapter.scrollLeft(),
8913      y: this.adapter.scrollTop()
8914    }
8915    this.waypoints = {
8916      vertical: {},
8917      horizontal: {}
8918    }
8919
8920    element.waypointContextKey = this.key
8921    contexts[element.waypointContextKey] = this
8922    keyCounter += 1
8923
8924    this.createThrottledScrollHandler()
8925    this.createThrottledResizeHandler()
8926  }
8927
8928  /* Private */
8929  Context.prototype.add = function(waypoint) {
8930    var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
8931    this.waypoints[axis][waypoint.key] = waypoint
8932    this.refresh()
8933  }
8934
8935  /* Private */
8936  Context.prototype.checkEmpty = function() {
8937    var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
8938    var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
8939    if (horizontalEmpty && verticalEmpty) {
8940      this.adapter.off('.waypoints')
8941      delete contexts[this.key]
8942    }
8943  }
8944
8945  /* Private */
8946  Context.prototype.createThrottledResizeHandler = function() {
8947    var self = this
8948
8949    function resizeHandler() {
8950      self.handleResize()
8951      self.didResize = false
8952    }
8953
8954    this.adapter.on('resize.waypoints', function() {
8955      if (!self.didResize) {
8956        self.didResize = true
8957        Waypoint.requestAnimationFrame(resizeHandler)
8958      }
8959    })
8960  }
8961
8962  /* Private */
8963  Context.prototype.createThrottledScrollHandler = function() {
8964    var self = this
8965    function scrollHandler() {
8966      self.handleScroll()
8967      self.didScroll = false
8968    }
8969
8970    this.adapter.on('scroll.waypoints', function() {
8971      if (!self.didScroll || Waypoint.isTouch) {
8972        self.didScroll = true
8973        Waypoint.requestAnimationFrame(scrollHandler)
8974      }
8975    })
8976  }
8977
8978  /* Private */
8979  Context.prototype.handleResize = function() {
8980    Waypoint.Context.refreshAll()
8981  }
8982
8983  /* Private */
8984  Context.prototype.handleScroll = function() {
8985    var triggeredGroups = {}
8986    var axes = {
8987      horizontal: {
8988        newScroll: this.adapter.scrollLeft(),
8989        oldScroll: this.oldScroll.x,
8990        forward: 'right',
8991        backward: 'left'
8992      },
8993      vertical: {
8994        newScroll: this.adapter.scrollTop(),
8995        oldScroll: this.oldScroll.y,
8996        forward: 'down',
8997        backward: 'up'
8998      }
8999    }
9000
9001    for (var axisKey in axes) {
9002      var axis = axes[axisKey]
9003      var isForward = axis.newScroll > axis.oldScroll
9004      var direction = isForward ? axis.forward : axis.backward
9005
9006      for (var waypointKey in this.waypoints[axisKey]) {
9007        var waypoint = this.waypoints[axisKey][waypointKey]
9008        var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
9009        var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
9010        var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
9011        var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
9012        if (crossedForward || crossedBackward) {
9013          waypoint.queueTrigger(direction)
9014          triggeredGroups[waypoint.group.id] = waypoint.group
9015        }
9016      }
9017    }
9018
9019    for (var groupKey in triggeredGroups) {
9020      triggeredGroups[groupKey].flushTriggers()
9021    }
9022
9023    this.oldScroll = {
9024      x: axes.horizontal.newScroll,
9025      y: axes.vertical.newScroll
9026    }
9027  }
9028
9029  /* Private */
9030  Context.prototype.innerHeight = function() {
9031    /*eslint-disable eqeqeq */
9032    if (this.element == this.element.window) {
9033      return Waypoint.viewportHeight()
9034    }
9035    /*eslint-enable eqeqeq */
9036    return this.adapter.innerHeight()
9037  }
9038
9039  /* Private */
9040  Context.prototype.remove = function(waypoint) {
9041    delete this.waypoints[waypoint.axis][waypoint.key]
9042    this.checkEmpty()
9043  }
9044
9045  /* Private */
9046  Context.prototype.innerWidth = function() {
9047    /*eslint-disable eqeqeq */
9048    if (this.element == this.element.window) {
9049      return Waypoint.viewportWidth()
9050    }
9051    /*eslint-enable eqeqeq */
9052    return this.adapter.innerWidth()
9053  }
9054
9055  /* Public */
9056  /* http://imakewebthings.com/waypoints/api/context-destroy */
9057  Context.prototype.destroy = function() {
9058    var allWaypoints = []
9059    for (var axis in this.waypoints) {
9060      for (var waypointKey in this.waypoints[axis]) {
9061        allWaypoints.push(this.waypoints[axis][waypointKey])
9062      }
9063    }
9064    for (var i = 0, end = allWaypoints.length; i < end; i++) {
9065      allWaypoints[i].destroy()
9066    }
9067  }
9068
9069  /* Public */
9070  /* http://imakewebthings.com/waypoints/api/context-refresh */
9071  Context.prototype.refresh = function() {
9072    /*eslint-disable eqeqeq */
9073    var isWindow = this.element == this.element.window
9074    /*eslint-enable eqeqeq */
9075    var contextOffset = isWindow ? undefined : this.adapter.offset()
9076    var triggeredGroups = {}
9077    var axes
9078
9079    this.handleScroll()
9080    axes = {
9081      horizontal: {
9082        contextOffset: isWindow ? 0 : contextOffset.left,
9083        contextScroll: isWindow ? 0 : this.oldScroll.x,
9084        contextDimension: this.innerWidth(),
9085        oldScroll: this.oldScroll.x,
9086        forward: 'right',
9087        backward: 'left',
9088        offsetProp: 'left'
9089      },
9090      vertical: {
9091        contextOffset: isWindow ? 0 : contextOffset.top,
9092        contextScroll: isWindow ? 0 : this.oldScroll.y,
9093        contextDimension: this.innerHeight(),
9094        oldScroll: this.oldScroll.y,
9095        forward: 'down',
9096        backward: 'up',
9097        offsetProp: 'top'
9098      }
9099    }
9100
9101    for (var axisKey in axes) {
9102      var axis = axes[axisKey]
9103      for (var waypointKey in this.waypoints[axisKey]) {
9104        var waypoint = this.waypoints[axisKey][waypointKey]
9105        var adjustment = waypoint.options.offset
9106        var oldTriggerPoint = waypoint.triggerPoint
9107        var elementOffset = 0
9108        var freshWaypoint = oldTriggerPoint == null
9109        var contextModifier, wasBeforeScroll, nowAfterScroll
9110        var triggeredBackward, triggeredForward
9111
9112        if (waypoint.element !== waypoint.element.window) {
9113          elementOffset = waypoint.adapter.offset()[axis.offsetProp]
9114        }
9115
9116        if (typeof adjustment === 'function') {
9117          adjustment = adjustment.apply(waypoint)
9118        }
9119        else if (typeof adjustment === 'string') {
9120          adjustment = parseFloat(adjustment)
9121          if (waypoint.options.offset.indexOf('%') > - 1) {
9122            adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
9123          }
9124        }
9125
9126        contextModifier = axis.contextScroll - axis.contextOffset
9127        waypoint.triggerPoint = elementOffset + contextModifier - adjustment
9128        wasBeforeScroll = oldTriggerPoint < axis.oldScroll
9129        nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
9130        triggeredBackward = wasBeforeScroll && nowAfterScroll
9131        triggeredForward = !wasBeforeScroll && !nowAfterScroll
9132
9133        if (!freshWaypoint && triggeredBackward) {
9134          waypoint.queueTrigger(axis.backward)
9135          triggeredGroups[waypoint.group.id] = waypoint.group
9136        }
9137        else if (!freshWaypoint && triggeredForward) {
9138          waypoint.queueTrigger(axis.forward)
9139          triggeredGroups[waypoint.group.id] = waypoint.group
9140        }
9141        else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
9142          waypoint.queueTrigger(axis.forward)
9143          triggeredGroups[waypoint.group.id] = waypoint.group
9144        }
9145      }
9146    }
9147
9148    Waypoint.requestAnimationFrame(function() {
9149      for (var groupKey in triggeredGroups) {
9150        triggeredGroups[groupKey].flushTriggers()
9151      }
9152    })
9153
9154    return this
9155  }
9156
9157  /* Private */
9158  Context.findOrCreateByElement = function(element) {
9159    return Context.findByElement(element) || new Context(element)
9160  }
9161
9162  /* Private */
9163  Context.refreshAll = function() {
9164    for (var contextId in contexts) {
9165      contexts[contextId].refresh()
9166    }
9167  }
9168
9169  /* Public */
9170  /* http://imakewebthings.com/waypoints/api/context-find-by-element */
9171  Context.findByElement = function(element) {
9172    return contexts[element.waypointContextKey]
9173  }
9174
9175  window.onload = function() {
9176    if (oldWindowLoad) {
9177      oldWindowLoad()
9178    }
9179    Context.refreshAll()
9180  }
9181
9182  Waypoint.requestAnimationFrame = function(callback) {
9183    var requestFn = window.requestAnimationFrame ||
9184      window.mozRequestAnimationFrame ||
9185      window.webkitRequestAnimationFrame ||
9186      requestAnimationFrameShim
9187    requestFn.call(window, callback)
9188  }
9189  Waypoint.Context = Context
9190}())
9191;(function() {
9192  'use strict'
9193
9194  function byTriggerPoint(a, b) {
9195    return a.triggerPoint - b.triggerPoint
9196  }
9197
9198  function byReverseTriggerPoint(a, b) {
9199    return b.triggerPoint - a.triggerPoint
9200  }
9201
9202  var groups = {
9203    vertical: {},
9204    horizontal: {}
9205  }
9206  var Waypoint = window.Waypoint
9207
9208  /* http://imakewebthings.com/waypoints/api/group */
9209  function Group(options) {
9210    this.name = options.name
9211    this.axis = options.axis
9212    this.id = this.name + '-' + this.axis
9213    this.waypoints = []
9214    this.clearTriggerQueues()
9215    groups[this.axis][this.name] = this
9216  }
9217
9218  /* Private */
9219  Group.prototype.add = function(waypoint) {
9220    this.waypoints.push(waypoint)
9221  }
9222
9223  /* Private */
9224  Group.prototype.clearTriggerQueues = function() {
9225    this.triggerQueues = {
9226      up: [],
9227      down: [],
9228      left: [],
9229      right: []
9230    }
9231  }
9232
9233  /* Private */
9234  Group.prototype.flushTriggers = function() {
9235    for (var direction in this.triggerQueues) {
9236      var waypoints = this.triggerQueues[direction]
9237      var reverse = direction === 'up' || direction === 'left'
9238      waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
9239      for (var i = 0, end = waypoints.length; i < end; i += 1) {
9240        var waypoint = waypoints[i]
9241        if (waypoint.options.continuous || i === waypoints.length - 1) {
9242          waypoint.trigger([direction])
9243        }
9244      }
9245    }
9246    this.clearTriggerQueues()
9247  }
9248
9249  /* Private */
9250  Group.prototype.next = function(waypoint) {
9251    this.waypoints.sort(byTriggerPoint)
9252    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
9253    var isLast = index === this.waypoints.length - 1
9254    return isLast ? null : this.waypoints[index + 1]
9255  }
9256
9257  /* Private */
9258  Group.prototype.previous = function(waypoint) {
9259    this.waypoints.sort(byTriggerPoint)
9260    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
9261    return index ? this.waypoints[index - 1] : null
9262  }
9263
9264  /* Private */
9265  Group.prototype.queueTrigger = function(waypoint, direction) {
9266    this.triggerQueues[direction].push(waypoint)
9267  }
9268
9269  /* Private */
9270  Group.prototype.remove = function(waypoint) {
9271    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
9272    if (index > -1) {
9273      this.waypoints.splice(index, 1)
9274    }
9275  }
9276
9277  /* Public */
9278  /* http://imakewebthings.com/waypoints/api/first */
9279  Group.prototype.first = function() {
9280    return this.waypoints[0]
9281  }
9282
9283  /* Public */
9284  /* http://imakewebthings.com/waypoints/api/last */
9285  Group.prototype.last = function() {
9286    return this.waypoints[this.waypoints.length - 1]
9287  }
9288
9289  /* Private */
9290  Group.findOrCreate = function(options) {
9291    return groups[options.axis][options.name] || new Group(options)
9292  }
9293
9294  Waypoint.Group = Group
9295}())
9296;(function() {
9297  'use strict'
9298
9299  var $ = window.jQuery
9300  var Waypoint = window.Waypoint
9301
9302  function JQueryAdapter(element) {
9303    this.$element = $(element)
9304  }
9305
9306  $.each([
9307    'innerHeight',
9308    'innerWidth',
9309    'off',
9310    'offset',
9311    'on',
9312    'outerHeight',
9313    'outerWidth',
9314    'scrollLeft',
9315    'scrollTop'
9316  ], function(i, method) {
9317    JQueryAdapter.prototype[method] = function() {
9318      var args = Array.prototype.slice.call(arguments)
9319      return this.$element[method].apply(this.$element, args)
9320    }
9321  })
9322
9323  $.each([
9324    'extend',
9325    'inArray',
9326    'isEmptyObject'
9327  ], function(i, method) {
9328    JQueryAdapter[method] = $[method]
9329  })
9330
9331  Waypoint.adapters.push({
9332    name: 'jquery',
9333    Adapter: JQueryAdapter
9334  })
9335  Waypoint.Adapter = JQueryAdapter
9336}())
9337;(function() {
9338  'use strict'
9339
9340  var Waypoint = window.Waypoint
9341
9342  function createExtension(framework) {
9343    return function() {
9344      var waypoints = []
9345      var overrides = arguments[0]
9346
9347      if (framework.isFunction(arguments[0])) {
9348        overrides = framework.extend({}, arguments[1])
9349        overrides.handler = arguments[0]
9350      }
9351
9352      this.each(function() {
9353        var options = framework.extend({}, overrides, {
9354          element: this
9355        })
9356        if (typeof options.context === 'string') {
9357          options.context = framework(this).closest(options.context)[0]
9358        }
9359        waypoints.push(new Waypoint(options))
9360      })
9361
9362      return waypoints
9363    }
9364  }
9365
9366  if (window.jQuery) {
9367    window.jQuery.fn.waypoint = createExtension(window.jQuery)
9368  }
9369  if (window.Zepto) {
9370    window.Zepto.fn.waypoint = createExtension(window.Zepto)
9371  }
9372}())
9373;
9374/*!
9375Waypoints Inview Shortcut - 4.0.0
9376Copyright © 2011-2015 Caleb Troughton
9377Licensed under the MIT license.
9378https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
9379*/
9380(function() {
9381  'use strict'
9382
9383  function noop() {}
9384
9385  var Waypoint = window.Waypoint
9386
9387  /* http://imakewebthings.com/waypoints/shortcuts/inview */
9388  function Inview(options) {
9389    this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
9390    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
9391    this.waypoints = []
9392    this.element = this.options.element
9393    this.createWaypoints()
9394  }
9395
9396  /* Private */
9397  Inview.prototype.createWaypoints = function() {
9398    var configs = {
9399      vertical: [{
9400        down: 'enter',
9401        up: 'exited',
9402        offset: '100%'
9403      }, {
9404        down: 'entered',
9405        up: 'exit',
9406        offset: 'bottom-in-view'
9407      }, {
9408        down: 'exit',
9409        up: 'entered',
9410        offset: 0
9411      }, {
9412        down: 'exited',
9413        up: 'enter',
9414        offset: function() {
9415          return -this.adapter.outerHeight()
9416        }
9417      }],
9418      horizontal: [{
9419        right: 'enter',
9420        left: 'exited',
9421        offset: '100%'
9422      }, {
9423        right: 'entered',
9424        left: 'exit',
9425        offset: 'right-in-view'
9426      }, {
9427        right: 'exit',
9428        left: 'entered',
9429        offset: 0
9430      }, {
9431        right: 'exited',
9432        left: 'enter',
9433        offset: function() {
9434          return -this.adapter.outerWidth()
9435        }
9436      }]
9437    }
9438
9439    for (var i = 0, end = configs[this.axis].length; i < end; i++) {
9440      var config = configs[this.axis][i]
9441      this.createWaypoint(config)
9442    }
9443  }
9444
9445  /* Private */
9446  Inview.prototype.createWaypoint = function(config) {
9447    var self = this
9448    this.waypoints.push(new Waypoint({
9449      context: this.options.context,
9450      element: this.options.element,
9451      enabled: this.options.enabled,
9452      handler: (function(config) {
9453        return function(direction) {
9454          self.options[config[direction]].call(self, direction)
9455        }
9456      }(config)),
9457      offset: config.offset,
9458      horizontal: this.options.horizontal
9459    }))
9460  }
9461
9462  /* Public */
9463  Inview.prototype.destroy = function() {
9464    for (var i = 0, end = this.waypoints.length; i < end; i++) {
9465      this.waypoints[i].destroy()
9466    }
9467    this.waypoints = []
9468  }
9469
9470  Inview.prototype.disable = function() {
9471    for (var i = 0, end = this.waypoints.length; i < end; i++) {
9472      this.waypoints[i].disable()
9473    }
9474  }
9475
9476  Inview.prototype.enable = function() {
9477    for (var i = 0, end = this.waypoints.length; i < end; i++) {
9478      this.waypoints[i].enable()
9479    }
9480  }
9481
9482  Inview.defaults = {
9483    context: window,
9484    enabled: true,
9485    enter: noop,
9486    entered: noop,
9487    exit: noop,
9488    exited: noop
9489  }
9490
9491  Waypoint.Inview = Inview
9492}())
9493;
9494/**
9495 * Swiper 3.4.2
9496 * Most modern mobile touch slider and framework with hardware accelerated transitions
9497 * 
9498 * http://www.idangero.us/swiper/
9499 * 
9500 * Copyright 2017, Vladimir Kharlampidi
9501 * The iDangero.us
9502 * http://www.idangero.us/
9503 * 
9504 * Licensed under MIT
9505 * 
9506 * Released on: March 10, 2017
9507 */
9508(function () {
9509    'use strict';
9510    var $;
9511
9512    /*===========================
9513    Swiper
9514    ===========================*/
9515    var Swiper = function (container, params) {
9516        if (!(this instanceof Swiper)) return new Swiper(container, params);
9517    
9518
9519        var defaults = {
9520            direction: 'horizontal',
9521            touchEventsTarget: 'container',
9522            initialSlide: 0,
9523            speed: 300,
9524            // autoplay
9525            autoplay: false,
9526            autoplayDisableOnInteraction: true,
9527            autoplayStopOnLast: false,
9528            // To support iOS's swipe-to-go-back gesture (when being used in-app, with UIWebView).
9529            iOSEdgeSwipeDetection: false,
9530            iOSEdgeSwipeThreshold: 20,
9531            // Free mode
9532            freeMode: false,
9533            freeModeMomentum: true,
9534            freeModeMomentumRatio: 1,
9535            freeModeMomentumBounce: true,
9536            freeModeMomentumBounceRatio: 1,
9537            freeModeMomentumVelocityRatio: 1,
9538            freeModeSticky: false,
9539            freeModeMinimumVelocity: 0.02,
9540            // Autoheight
9541            autoHeight: false,
9542            // Set wrapper width
9543            setWrapperSize: false,
9544            // Virtual Translate
9545            virtualTranslate: false,
9546            // Effects
9547            effect: 'slide', // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
9548            coverflow: {
9549                rotate: 50,
9550                stretch: 0,
9551                depth: 100,
9552                modifier: 1,
9553                slideShadows : true
9554            },
9555            flip: {
9556                slideShadows : true,
9557                limitRotation: true
9558            },
9559            cube: {
9560                slideShadows: true,
9561                shadow: true,
9562                shadowOffset: 20,
9563                shadowScale: 0.94
9564            },
9565            fade: {
9566                crossFade: false
9567            },
9568            // Parallax
9569            parallax: false,
9570            // Zoom
9571            zoom: false,
9572            zoomMax: 3,
9573            zoomMin: 1,
9574            zoomToggle: true,
9575            // Scrollbar
9576            scrollbar: null,
9577            scrollbarHide: true,
9578            scrollbarDraggable: false,
9579            scrollbarSnapOnRelease: false,
9580            // Keyboard Mousewheel
9581            keyboardControl: false,
9582            mousewheelControl: false,
9583            mousewheelReleaseOnEdges: false,
9584            mousewheelInvert: false,
9585            mousewheelForceToAxis: false,
9586            mousewheelSensitivity: 1,
9587            mousewheelEventsTarged: 'container',
9588            // Hash Navigation
9589            hashnav: false,
9590            hashnavWatchState: false,
9591            // History
9592            history: false,
9593            // Commong Nav State
9594            replaceState: false,
9595            // Breakpoints
9596            breakpoints: undefined,
9597            // Slides grid
9598            spaceBetween: 0,
9599            slidesPerView: 1,
9600            slidesPerColumn: 1,
9601            slidesPerColumnFill: 'column',
9602            slidesPerGroup: 1,
9603            centeredSlides: false,
9604            slidesOffsetBefore: 0, // in px
9605            slidesOffsetAfter: 0, // in px
9606            // Round length
9607            roundLengths: false,
9608            // Touches
9609            touchRatio: 1,
9610            touchAngle: 45,
9611            simulateTouch: true,
9612            shortSwipes: true,
9613            longSwipes: true,
9614            longSwipesRatio: 0.5,
9615            longSwipesMs: 300,
9616            followFinger: true,
9617            onlyExternal: false,
9618            threshold: 0,
9619            touchMoveStopPropagation: true,
9620            touchReleaseOnEdges: false,
9621            // Unique Navigation Elements
9622            uniqueNavElements: true,
9623            // Pagination
9624            pagination: null,
9625            paginationElement: 'span',
9626            paginationClickable: false,
9627            paginationHide: false,
9628            paginationBulletRender: null,
9629            paginationProgressRender: null,
9630            paginationFractionRender: null,
9631            paginationCustomRender: null,
9632            paginationType: 'bullets', // 'bullets' or 'progress' or 'fraction' or 'custom'
9633            // Resistance
9634            resistance: true,
9635            resistanceRatio: 0.85,
9636            // Next/prev buttons
9637            nextButton: null,
9638            prevButton: null,
9639            // Progress
9640            watchSlidesProgress: false,
9641            watchSlidesVisibility: false,
9642            // Cursor
9643            grabCursor: false,
9644            // Clicks
9645            preventClicks: true,
9646            preventClicksPropagation: true,
9647            slideToClickedSlide: false,
9648            // Lazy Loading
9649            lazyLoading: false,
9650            lazyLoadingInPrevNext: false,
9651            lazyLoadingInPrevNextAmount: 1,
9652            lazyLoadingOnTransitionStart: false,
9653            // Images
9654            preloadImages: true,
9655            updateOnImagesReady: true,
9656            // loop
9657            loop: false,
9658            loopAdditionalSlides: 0,
9659            loopedSlides: null,
9660            // Control
9661            control: undefined,
9662            controlInverse: false,
9663            controlBy: 'slide', //or 'container'
9664            normalizeSlideIndex: true,
9665            // Swiping/no swiping
9666            allowSwipeToPrev: true,
9667            allowSwipeToNext: true,
9668            swipeHandler: null, //'.swipe-handler',
9669            noSwiping: true,
9670            noSwipingClass: 'swiper-no-swiping',
9671            // Passive Listeners
9672            passiveListeners: true,
9673            // NS
9674            containerModifierClass: 'swiper-container-', // NEW
9675            slideClass: 'swiper-slide',
9676            slideActiveClass: 'swiper-slide-active',
9677            slideDuplicateActiveClass: 'swiper-slide-duplicate-active',
9678            slideVisibleClass: 'swiper-slide-visible',
9679            slideDuplicateClass: 'swiper-slide-duplicate',
9680            slideNextClass: 'swiper-slide-next',
9681            slideDuplicateNextClass: 'swiper-slide-duplicate-next',
9682            slidePrevClass: 'swiper-slide-prev',
9683            slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',
9684            wrapperClass: 'swiper-wrapper',
9685            bulletClass: 'swiper-pagination-bullet',
9686            bulletActiveClass: 'swiper-pagination-bullet-active',
9687            buttonDisabledClass: 'swiper-button-disabled',
9688            paginationCurrentClass: 'swiper-pagination-current',
9689            paginationTotalClass: 'swiper-pagination-total',
9690            paginationHiddenClass: 'swiper-pagination-hidden',
9691            paginationProgressbarClass: 'swiper-pagination-progressbar',
9692            paginationClickableClass: 'swiper-pagination-clickable', // NEW
9693            paginationModifierClass: 'swiper-pagination-', // NEW
9694            lazyLoadingClass: 'swiper-lazy',
9695            lazyStatusLoadingClass: 'swiper-lazy-loading',
9696            lazyStatusLoadedClass: 'swiper-lazy-loaded',
9697            lazyPreloaderClass: 'swiper-lazy-preloader',
9698            notificationClass: 'swiper-notification',
9699            preloaderClass: 'preloader',
9700            zoomContainerClass: 'swiper-zoom-container',
9701        
9702            // Observer
9703            observer: false,
9704            observeParents: false,
9705            // Accessibility
9706            a11y: false,
9707            prevSlideMessage: 'Previous slide',
9708            nextSlideMessage: 'Next slide',
9709            firstSlideMessage: 'This is the first slide',
9710            lastSlideMessage: 'This is the last slide',
9711            paginationBulletMessage: 'Go to slide {{index}}',
9712            // Callbacks
9713            runCallbacksOnInit: true
9714            /*
9715            Callbacks:
9716            onInit: function (swiper)
9717            onDestroy: function (swiper)
9718            onBeforeResize: function (swiper)
9719            onAfterResize: function (swiper)
9720            onClick: function (swiper, e)
9721            onTap: function (swiper, e)
9722            onDoubleTap: function (swiper, e)
9723            onSliderMove: function (swiper, e)
9724            onSlideChangeStart: function (swiper)
9725            onSlideChangeEnd: function (swiper)
9726            onTransitionStart: function (swiper)
9727            onTransitionEnd: function (swiper)
9728            onImagesReady: function (swiper)
9729            onProgress: function (swiper, progress)
9730            onTouchStart: function (swiper, e)
9731            onTouchMove: function (swiper, e)
9732            onTouchMoveOpposite: function (swiper, e)
9733            onTouchEnd: function (swiper, e)
9734            onReachBeginning: function (swiper)
9735            onReachEnd: function (swiper)
9736            onSetTransition: function (swiper, duration)
9737            onSetTranslate: function (swiper, translate)
9738            onAutoplayStart: function (swiper)
9739            onAutoplayStop: function (swiper),
9740            onLazyImageLoad: function (swiper, slide, image)
9741            onLazyImageReady: function (swiper, slide, image)
9742            onKeyPress: function (swiper, keyCode)
9743            */
9744        
9745        };
9746        var initialVirtualTranslate = params && params.virtualTranslate;
9747        
9748        params = params || {};
9749        var originalParams = {};
9750        for (var param in params) {
9751            if (typeof params[param] === 'object' && params[param] !== null && !(params[param].nodeType || params[param] === window || params[param] === document || (typeof Dom7 !== 'undefined' && params[param] instanceof Dom7) || (typeof jQuery !== 'undefined' && params[param] instanceof jQuery))) {
9752                originalParams[param] = {};
9753                for (var deepParam in params[param]) {
9754                    originalParams[param][deepParam] = params[param][deepParam];
9755                }
9756            }
9757            else {
9758                originalParams[param] = params[param];
9759            }
9760        }
9761        for (var def in defaults) {
9762            if (typeof params[def] === 'undefined') {
9763                params[def] = defaults[def];
9764            }
9765            else if (typeof params[def] === 'object') {
9766                for (var deepDef in defaults[def]) {
9767                    if (typeof params[def][deepDef] === 'undefined') {
9768                        params[def][deepDef] = defaults[def][deepDef];
9769                    }
9770                }
9771            }
9772        }
9773        
9774        // Swiper
9775        var s = this;
9776        
9777        // Params
9778        s.params = params;
9779        s.originalParams = originalParams;
9780        
9781        // Classname
9782        s.classNames = [];
9783        /*=========================
9784          Dom Library and plugins
9785          ===========================*/
9786        if (typeof $ !== 'undefined' && typeof Dom7 !== 'undefined'){
9787            $ = Dom7;
9788        }
9789        if (typeof $ === 'undefined') {
9790            if (typeof Dom7 === 'undefined') {
9791                $ = window.Dom7 || window.Zepto || window.jQuery;
9792            }
9793            else {
9794                $ = Dom7;
9795            }
9796            if (!$) return;
9797        }
9798        // Export it to Swiper instance
9799        s.$ = $;
9800        
9801        /*=========================
9802          Breakpoints
9803          ===========================*/
9804        s.currentBreakpoint = undefined;
9805        s.getActiveBreakpoint = function () {
9806            //Get breakpoint for window width
9807            if (!s.params.breakpoints) return false;
9808            var breakpoint = false;
9809            var points = [], point;
9810            for ( point in s.params.breakpoints ) {
9811                if (s.params.breakpoints.hasOwnProperty(point)) {
9812                    points.push(point);
9813                }
9814            }
9815            points.sort(function (a, b) {
9816                return parseInt(a, 10) > parseInt(b, 10);
9817            });
9818            for (var i = 0; i < points.length; i++) {
9819                point = points[i];
9820                if (point >= window.innerWidth && !breakpoint) {
9821                    breakpoint = point;
9822                }
9823            }
9824            return breakpoint || 'max';
9825        };
9826        s.setBreakpoint = function () {
9827            //Set breakpoint for window width and update parameters
9828            var breakpoint = s.getActiveBreakpoint();
9829            if (breakpoint && s.currentBreakpoint !== breakpoint) {
9830                var breakPointsParams = breakpoint in s.params.breakpoints ? s.params.breakpoints[breakpoint] : s.originalParams;
9831                var needsReLoop = s.params.loop && (breakPointsParams.slidesPerView !== s.params.slidesPerView);
9832                for ( var param in breakPointsParams ) {
9833                    s.params[param] = breakPointsParams[param];
9834                }
9835                s.currentBreakpoint = breakpoint;
9836                if(needsReLoop && s.destroyLoop) {
9837                    s.reLoop(true);
9838                }
9839            }
9840        };
9841        // Set breakpoint on load
9842        if (s.params.breakpoints) {
9843            s.setBreakpoint();
9844        }
9845        
9846        /*=========================
9847          Preparation - Define Container, Wrapper and Pagination
9848          ===========================*/
9849        s.container = $(container);
9850        if (s.container.length === 0) return;
9851        if (s.container.length > 1) {
9852            var swipers = [];
9853            s.container.each(function () {
9854                var container = this;
9855                swipers.push(new Swiper(this, params));
9856            });
9857            return swipers;
9858        }
9859        
9860        // Save instance in container HTML Element and in data
9861        s.container[0].swiper = s;
9862        s.container.data('swiper', s);
9863        
9864        s.classNames.push(s.params.containerModifierClass + s.params.direction);
9865        
9866        if (s.params.freeMode) {
9867            s.classNames.push(s.params.containerModifierClass + 'free-mode');
9868        }
9869        if (!s.support.flexbox) {
9870            s.classNames.push(s.params.containerModifierClass + 'no-flexbox');
9871            s.params.slidesPerColumn = 1;
9872        }
9873        if (s.params.autoHeight) {
9874            s.classNames.push(s.params.containerModifierClass + 'autoheight');
9875        }
9876        // Enable slides progress when required
9877        if (s.params.parallax || s.params.watchSlidesVisibility) {
9878            s.params.watchSlidesProgress = true;
9879        }
9880        // Max resistance when touchReleaseOnEdges
9881        if (s.params.touchReleaseOnEdges) {
9882            s.params.resistanceRatio = 0;
9883        }
9884        // Coverflow / 3D
9885        if (['cube', 'coverflow', 'flip'].indexOf(s.params.effect) >= 0) {
9886            if (s.support.transforms3d) {
9887                s.params.watchSlidesProgress = true;
9888                s.classNames.push(s.params.containerModifierClass + '3d');
9889            }
9890            else {
9891                s.params.effect = 'slide';
9892            }
9893        }
9894        if (s.params.effect !== 'slide') {
9895            s.classNames.push(s.params.containerModifierClass + s.params.effect);
9896        }
9897        if (s.params.effect === 'cube') {
9898            s.params.resistanceRatio = 0;
9899            s.params.slidesPerView = 1;
9900            s.params.slidesPerColumn = 1;
9901            s.params.slidesPerGroup = 1;
9902            s.params.centeredSlides = false;
9903            s.params.spaceBetween = 0;
9904            s.params.virtualTranslate = true;
9905        }
9906        if (s.params.effect === 'fade' || s.params.effect === 'flip') {
9907            s.params.slidesPerView = 1;
9908            s.params.slidesPerColumn = 1;
9909            s.params.slidesPerGroup = 1;
9910            s.params.watchSlidesProgress = true;
9911            s.params.spaceBetween = 0;
9912            if (typeof initialVirtualTranslate === 'undefined') {
9913                s.params.virtualTranslate = true;
9914            }
9915        }
9916        
9917        // Grab Cursor
9918        if (s.params.grabCursor && s.support.touch) {
9919            s.params.grabCursor = false;
9920        }
9921        
9922        // Wrapper
9923        s.wrapper = s.container.children('.' + s.params.wrapperClass);
9924        
9925        // Pagination
9926        if (s.params.pagination) {
9927            s.paginationContainer = $(s.params.pagination);
9928            if (s.params.uniqueNavElements && typeof s.params.pagination === 'string' && s.paginationContainer.length > 1 && s.container.find(s.params.pagination).length === 1) {
9929                s.paginationContainer = s.container.find(s.params.pagination);
9930            }
9931        
9932            if (s.params.paginationType === 'bullets' && s.params.paginationClickable) {
9933                s.paginationContainer.addClass(s.params.paginationModifierClass + 'clickable');
9934            }
9935            else {
9936                s.params.paginationClickable = false;
9937            }
9938            s.paginationContainer.addClass(s.params.paginationModifierClass + s.params.paginationType);
9939        }
9940        // Next/Prev Buttons
9941        if (s.params.nextButton || s.params.prevButton) {
9942            if (s.params.nextButton) {
9943                s.nextButton = $(s.params.nextButton);
9944                if (s.params.uniqueNavElements && typeof s.params.nextButton === 'string' && s.nextButton.length > 1 && s.container.find(s.params.nextButton).length === 1) {
9945                    s.nextButton = s.container.find(s.params.nextButton);
9946                }
9947            }
9948            if (s.params.prevButton) {
9949                s.prevButton = $(s.params.prevButton);
9950                if (s.params.uniqueNavElements && typeof s.params.prevButton === 'string' && s.prevButton.length > 1 && s.container.find(s.params.prevButton).length === 1) {
9951                    s.prevButton = s.container.find(s.params.prevButton);
9952                }
9953            }
9954        }
9955        
9956        // Is Horizontal
9957        s.isHorizontal = function () {
9958            return s.params.direction === 'horizontal';
9959        };
9960        // s.isH = isH;
9961        
9962        // RTL
9963        s.rtl = s.isHorizontal() && (s.container[0].dir.toLowerCase() === 'rtl' || s.container.css('direction') === 'rtl');
9964        if (s.rtl) {
9965            s.classNames.push(s.params.containerModifierClass + 'rtl');
9966        }
9967        
9968        // Wrong RTL support
9969        if (s.rtl) {
9970            s.wrongRTL = s.wrapper.css('display') === '-webkit-box';
9971        }
9972        
9973        // Columns
9974        if (s.params.slidesPerColumn > 1) {
9975            s.classNames.push(s.params.containerModifierClass + 'multirow');
9976        }
9977        
9978        // Check for Android
9979        if (s.device.android) {
9980            s.classNames.push(s.params.containerModifierClass + 'android');
9981        }
9982        
9983        // Add classes
9984        s.container.addClass(s.classNames.join(' '));
9985        
9986        // Translate
9987        s.translate = 0;
9988        
9989        // Progress
9990        s.progress = 0;
9991        
9992        // Velocity
9993        s.velocity = 0;
9994        
9995        /*=========================
9996          Locks, unlocks
9997          ===========================*/
9998        s.lockSwipeToNext = function () {
9999            s.params.allowSwipeToNext = false;
10000            if (s.params.allowSwipeToPrev === false && s.params.grabCursor) {
10001                s.unsetGrabCursor();
10002            }
10003        };
10004        s.lockSwipeToPrev = function () {
10005            s.params.allowSwipeToPrev = false;
10006            if (s.params.allowSwipeToNext === false && s.params.grabCursor) {
10007                s.unsetGrabCursor();
10008            }
10009        };
10010        s.lockSwipes = function () {
10011            s.params.allowSwipeToNext = s.params.allowSwipeToPrev = false;
10012            if (s.params.grabCursor) s.unsetGrabCursor();
10013        };
10014        s.unlockSwipeToNext = function () {
10015            s.params.allowSwipeToNext = true;
10016            if (s.params.allowSwipeToPrev === true && s.params.grabCursor) {
10017                s.setGrabCursor();
10018            }
10019        };
10020        s.unlockSwipeToPrev = function () {
10021            s.params.allowSwipeToPrev = true;
10022            if (s.params.allowSwipeToNext === true && s.params.grabCursor) {
10023                s.setGrabCursor();
10024            }
10025        };
10026        s.unlockSwipes = function () {
10027            s.params.allowSwipeToNext = s.params.allowSwipeToPrev = true;
10028            if (s.params.grabCursor) s.setGrabCursor();
10029        };
10030        
10031        /*=========================
10032          Round helper
10033          ===========================*/
10034        function round(a) {
10035            return Math.floor(a);
10036        }
10037        /*=========================
10038          Set grab cursor
10039          ===========================*/
10040        s.setGrabCursor = function(moving) {
10041            s.container[0].style.cursor = 'move';
10042            s.container[0].style.cursor = moving ? '-webkit-grabbing' : '-webkit-grab';
10043            s.container[0].style.cursor = moving ? '-moz-grabbin' : '-moz-grab';
10044            s.container[0].style.cursor = moving ? 'grabbing': 'grab';
10045        };
10046        s.unsetGrabCursor = function () {
10047            s.container[0].style.cursor = '';
10048        };
10049        if (s.params.grabCursor) {
10050            s.setGrabCursor();
10051        }
10052        /*=========================
10053          Update on Images Ready
10054          ===========================*/
10055        s.imagesToLoad = [];
10056        s.imagesLoaded = 0;
10057        
10058        s.loadImage = function (imgElement, src, srcset, sizes, checkForComplete, callback) {
10059            var image;
10060            function onReady () {
10061                if (callback) callback();
10062            }
10063            if (!imgElement.complete || !checkForComplete) {
10064                if (src) {
10065                    image = new window.Image();
10066                    image.onload = onReady;
10067                    image.onerror = onReady;
10068                    if (sizes) {
10069                        image.sizes = sizes;
10070                    }
10071                    if (srcset) {
10072                        image.srcset = srcset;
10073                    }
10074                    if (src) {
10075                        image.src = src;
10076                    }
10077                } else {
10078                    onReady();
10079                }
10080        
10081            } else {//image already loaded...
10082                onReady();
10083            }
10084        };
10085        s.preloadImages = function () {
10086            s.imagesToLoad = s.container.find('img');
10087            function _onReady() {
10088                if (typeof s === 'undefined' || s === null || !s) return;
10089                if (s.imagesLoaded !== undefined) s.imagesLoaded++;
10090                if (s.imagesLoaded === s.imagesToLoad.length) {
10091                    if (s.params.updateOnImagesReady) s.update();
10092                    s.emit('onImagesReady', s);
10093                }
10094            }
10095            for (var i = 0; i < s.imagesToLoad.length; i++) {
10096                s.loadImage(s.imagesToLoad[i], (s.imagesToLoad[i].currentSrc || s.imagesToLoad[i].getAttribute('src')), (s.imagesToLoad[i].srcset || s.imagesToLoad[i].getAttribute('srcset')), s.imagesToLoad[i].sizes || s.imagesToLoad[i].getAttribute('sizes'), true, _onReady);
10097            }
10098        };
10099        
10100        /*=========================
10101          Autoplay
10102          ===========================*/
10103        s.autoplayTimeoutId = undefined;
10104        s.autoplaying = false;
10105        s.autoplayPaused = false;
10106        function autoplay() {
10107            var autoplayDelay = s.params.autoplay;
10108            var activeSlide = s.slides.eq(s.activeIndex);
10109            if (activeSlide.attr('data-swiper-autoplay')) {
10110                autoplayDelay = activeSlide.attr('data-swiper-autoplay') || s.params.autoplay;
10111            }
10112            s.autoplayTimeoutId = setTimeout(function () {
10113                if (s.params.loop) {
10114                    s.fixLoop();
10115                    s._slideNext();
10116                    s.emit('onAutoplay', s);
10117                }
10118                else {
10119                    if (!s.isEnd) {
10120                        s._slideNext();
10121                        s.emit('onAutoplay', s);
10122                    }
10123                    else {
10124                        if (!params.autoplayStopOnLast) {
10125                            s._slideTo(0);
10126                            s.emit('onAutoplay', s);
10127                        }
10128                        else {
10129                            s.stopAutoplay();
10130                        }
10131                    }
10132                }
10133            }, autoplayDelay);
10134        }
10135        s.startAutoplay = function () {
10136            if (typeof s.autoplayTimeoutId !== 'undefined') return false;
10137            if (!s.params.autoplay) return false;
10138            if (s.autoplaying) return false;
10139            s.autoplaying = true;
10140            s.emit('onAutoplayStart', s);
10141            autoplay();
10142        };
10143        s.stopAutoplay = function (internal) {
10144            if (!s.autoplayTimeoutId) return;
10145            if (s.autoplayTimeoutId) clearTimeout(s.autoplayTimeoutId);
10146            s.autoplaying = false;
10147            s.autoplayTimeoutId = undefined;
10148            s.emit('onAutoplayStop', s);
10149        };
10150        s.pauseAutoplay = function (speed) {
10151            if (s.autoplayPaused) return;
10152            if (s.autoplayTimeoutId) clearTimeout(s.autoplayTimeoutId);
10153            s.autoplayPaused = true;
10154            if (speed === 0) {
10155                s.autoplayPaused = false;
10156                autoplay();
10157            }
10158            else {
10159                s.wrapper.transitionEnd(function () {
10160                    if (!s) return;
10161                    s.autoplayPaused = false;
10162                    if (!s.autoplaying) {
10163                        s.stopAutoplay();
10164                    }
10165                    else {
10166                        autoplay();
10167                    }
10168                });
10169            }
10170        };
10171        /*=========================
10172          Min/Max Translate
10173          ===========================*/
10174        s.minTranslate = function () {
10175            return (-s.snapGrid[0]);
10176        };
10177        s.maxTranslate = function () {
10178            return (-s.snapGrid[s.snapGrid.length - 1]);
10179        };
10180        /*=========================
10181          Slider/slides sizes
10182          ===========================*/
10183        s.updateAutoHeight = function () {
10184            var activeSlides = [];
10185            var newHeight = 0;
10186            var i;
10187        
10188            // Find slides currently in view
10189            if(s.params.slidesPerView !== 'auto' && s.params.slidesPerView > 1) {
10190                for (i = 0; i < Math.ceil(s.params.slidesPerView); i++) {
10191                    var index = s.activeIndex + i;
10192                    if(index > s.slides.length) break;
10193                    activeSlides.push(s.slides.eq(index)[0]);
10194                }
10195            } else {
10196                activeSlides.push(s.slides.eq(s.activeIndex)[0]);
10197            }
10198        
10199            // Find new height from heighest slide in view
10200            for (i = 0; i < activeSlides.length; i++) {
10201                if (typeof activeSlides[i] !== 'undefined') {
10202                    var height = activeSlides[i].offsetHeight;
10203                    newHeight = height > newHeight ? height : newHeight;
10204                }
10205            }
10206        
10207            // Update Height
10208            if (newHeight) s.wrapper.css('height', newHeight + 'px');
10209        };
10210        s.updateContainerSize = function () {
10211            var width, height;
10212            if (typeof s.params.width !== 'undefined') {
10213                width = s.params.width;
10214            }
10215            else {
10216                width = s.container[0].clientWidth;
10217            }
10218            if (typeof s.params.height !== 'undefined') {
10219                height = s.params.height;
10220            }
10221            else {
10222                height = s.container[0].clientHeight;
10223            }
10224            if (width === 0 && s.isHorizontal() || height === 0 && !s.isHorizontal()) {
10225                return;
10226            }
10227        
10228            //Subtract paddings
10229            width = width - parseInt(s.container.css('padding-left'), 10) - parseInt(s.container.css('padding-right'), 10);
10230            height = height - parseInt(s.container.css('padding-top'), 10) - parseInt(s.container.css('padding-bottom'), 10);
10231        
10232            // Store values
10233            s.width = width;
10234            s.height = height;
10235            s.size = s.isHorizontal() ? s.width : s.height;
10236        };
10237        
10238        s.updateSlidesSize = function () {
10239            s.slides = s.wrapper.children('.' + s.params.slideClass);
10240            s.snapGrid = [];
10241            s.slidesGrid = [];
10242            s.slidesSizesGrid = [];
10243        
10244            var spaceBetween = s.params.spaceBetween,
10245                slidePosition = -s.params.slidesOffsetBefore,
10246                i,
10247                prevSlideSize = 0,
10248                index = 0;
10249            if (typeof s.size === 'undefined') return;
10250            if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {
10251                spaceBetween = parseFloat(spaceBetween.replace('%', '')) / 100 * s.size;
10252            }
10253        
10254            s.virtualSize = -spaceBetween;
10255            // reset margins
10256            if (s.rtl) s.slides.css({marginLeft: '', marginTop: ''});
10257            else s.slides.css({marginRight: '', marginBottom: ''});
10258        
10259            var slidesNumberEvenToRows;
10260            if (s.params.slidesPerColumn > 1) {
10261                if (Math.floor(s.slides.length / s.params.slidesPerColumn) === s.slides.length / s.params.slidesPerColumn) {
10262                    slidesNumberEvenToRows = s.slides.length;
10263                }
10264                else {
10265                    slidesNumberEvenToRows = Math.ceil(s.slides.length / s.params.slidesPerColumn) * s.params.slidesPerColumn;
10266                }
10267                if (s.params.slidesPerView !== 'auto' && s.params.slidesPerColumnFill === 'row') {
10268                    slidesNumberEvenToRows = Math.max(slidesNumberEvenToRows, s.params.slidesPerView * s.params.slidesPerColumn);
10269                }
10270            }
10271        
10272            // Calc slides
10273            var slideSize;
10274            var slidesPerColumn = s.params.slidesPerColumn;
10275            var slidesPerRow = slidesNumberEvenToRows / slidesPerColumn;
10276            var numFullColumns = slidesPerRow - (s.params.slidesPerColumn * slidesPerRow - s.slides.length);
10277            for (i = 0; i < s.slides.length; i++) {
10278                slideSize = 0;
10279                var slide = s.slides.eq(i);
10280                if (s.params.slidesPerColumn > 1) {
10281                    // Set slides order
10282                    var newSlideOrderIndex;
10283                    var column, row;
10284                    if (s.params.slidesPerColumnFill === 'column') {
10285                        column = Math.floor(i / slidesPerColumn);
10286                        row = i - column * slidesPerColumn;
10287                        if (column > numFullColumns || (column === numFullColumns && row === slidesPerColumn-1)) {
10288                            if (++row >= slidesPerColumn) {
10289                                row = 0;
10290                                column++;
10291                            }
10292                        }
10293                        newSlideOrderIndex = column + row * slidesNumberEvenToRows / slidesPerColumn;
10294                        slide
10295                            .css({
10296                                '-webkit-box-ordinal-group': newSlideOrderIndex,
10297                                '-moz-box-ordinal-group': newSlideOrderIndex,
10298                                '-ms-flex-order': newSlideOrderIndex,
10299                                '-webkit-order': newSlideOrderIndex,
10300                                'order': newSlideOrderIndex
10301                            });
10302                    }
10303                    else {
10304                        row = Math.floor(i / slidesPerRow);
10305                        column = i - row * slidesPerRow;
10306                    }
10307                    slide
10308                        .css(
10309                            'margin-' + (s.isHorizontal() ? 'top' : 'left'),
10310                            (row !== 0 && s.params.spaceBetween) && (s.params.spaceBetween + 'px')
10311                        )
10312                        .attr('data-swiper-column', column)
10313                        .attr('data-swiper-row', row);
10314        
10315                }
10316                if (slide.css('display') === 'none') continue;
10317                if (s.params.slidesPerView === 'auto') {
10318                    slideSize = s.isHorizontal() ? slide.outerWidth(true) : slide.outerHeight(true);
10319                    if (s.params.roundLengths) slideSize = round(slideSize);
10320                }
10321                else {
10322                    slideSize = (s.size - (s.params.slidesPerView - 1) * spaceBetween) / s.params.slidesPerView;
10323                    if (s.params.roundLengths) slideSize = round(slideSize);
10324        
10325                    if (s.isHorizontal()) {
10326                        s.slides[i].style.width = slideSize + 'px';
10327                    }
10328                    else {
10329                        s.slides[i].style.height = slideSize + 'px';
10330                    }
10331                }
10332                s.slides[i].swiperSlideSize = slideSize;
10333                s.slidesSizesGrid.push(slideSize);
10334        
10335        
10336                if (s.params.centeredSlides) {
10337                    slidePosition = slidePosition + slideSize / 2 + prevSlideSize / 2 + spaceBetween;
10338                    if(prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - s.size / 2 - spaceBetween;
10339                    if (i === 0) slidePosition = slidePosition - s.size / 2 - spaceBetween;
10340                    if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;
10341                    if ((index) % s.params.slidesPerGroup === 0) s.snapGrid.push(slidePosition);
10342                    s.slidesGrid.push(slidePosition);
10343                }
10344                else {
10345                    if ((index) % s.params.slidesPerGroup === 0) s.snapGrid.push(slidePosition);
10346                    s.slidesGrid.push(slidePosition);
10347                    slidePosition = slidePosition + slideSize + spaceBetween;
10348                }
10349        
10350                s.virtualSize += slideSize + spaceBetween;
10351        
10352                prevSlideSize = slideSize;
10353        
10354                index ++;
10355            }
10356            s.virtualSize = Math.max(s.virtualSize, s.size) + s.params.slidesOffsetAfter;
10357            var newSlidesGrid;
10358        
10359            if (
10360                s.rtl && s.wrongRTL && (s.params.effect === 'slide' || s.params.effect === 'coverflow')) {
10361                s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'});
10362            }
10363            if (!s.support.flexbox || s.params.setWrapperSize) {
10364                if (s.isHorizontal()) s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'});
10365                else s.wrapper.css({height: s.virtualSize + s.params.spaceBetween + 'px'});
10366            }
10367        
10368            if (s.params.slidesPerColumn > 1) {
10369                s.virtualSize = (slideSize + s.params.spaceBetween) * slidesNumber
10369EvenToRows;
10370                s.virtualSize = Math.ceil(s.virtualSize / s.params.slidesPerColumn) - s.params.spaceBetween;
10371                if (s.isHorizontal()) s.wrapper.css({width: s.virtualSize + s.params.spaceBetween + 'px'});
10372                else s.wrapper.css({height: s.virtualSize + s.params.spaceBetween + 'px'});
10373                if (s.params.centeredSlides) {
10374                    newSlidesGrid = [];
10375                    for (i = 0; i < s.snapGrid.length; i++) {
10376                        if (s.snapGrid[i] < s.virtualSize + s.snapGrid[0]) newSlidesGrid.push(s.snapGrid[i]);
10377                    }
10378                    s.snapGrid = newSlidesGrid;
10379                }
10380            }
10381        
10382            // Remove last grid elements depending on width
10383            if (!s.params.centeredSlides) {
10384                newSlidesGrid = [];
10385                for (i = 0; i < s.snapGrid.length; i++) {
10386                    if (s.snapGrid[i] <= s.virtualSize - s.size) {
10387                        newSlidesGrid.push(s.snapGrid[i]);
10388                    }
10389                }
10390                s.snapGrid = newSlidesGrid;
10391                if (Math.floor(s.virtualSize - s.size) - Math.floor(s.snapGrid[s.snapGrid.length - 1]) > 1) {
10392                    s.snapGrid.push(s.virtualSize - s.size);
10393                }
10394            }
10395            if (s.snapGrid.length === 0) s.snapGrid = [0];
10396        
10397            if (s.params.spaceBetween !== 0) {
10398                if (s.isHorizontal()) {
10399                    if (s.rtl) s.slides.css({marginLeft: spaceBetween + 'px'});
10400                    else s.slides.css({marginRight: spaceBetween + 'px'});
10401                }
10402                else s.slides.css({marginBottom: spaceBetween + 'px'});
10403            }
10404            if (s.params.watchSlidesProgress) {
10405                s.updateSlidesOffset();
10406            }
10407        };
10408        s.updateSlidesOffset = function () {
10409            for (var i = 0; i < s.slides.length; i++) {
10410                s.slides[i].swiperSlideOffset = s.isHorizontal() ? s.slides[i].offsetLeft : s.slides[i].offsetTop;
10411            }
10412        };
10413        
10414        /*=========================
10415          Dynamic Slides Per View
10416          ===========================*/
10417        s.currentSlidesPerView = function () {
10418            var spv = 1, i, j;
10419            if (s.params.centeredSlides) {
10420                var size = s.slides[s.activeIndex].swiperSlideSize;
10421                var breakLoop;
10422                for (i = s.activeIndex + 1; i < s.slides.length; i++) {
10423                    if (s.slides[i] && !breakLoop) {
10424                        size += s.slides[i].swiperSlideSize;
10425                        spv ++;
10426                        if (size > s.size) breakLoop = true;
10427                    }
10428                }
10429                for (j = s.activeIndex - 1; j >= 0; j--) {
10430                    if (s.slides[j] && !breakLoop) {
10431                        size += s.slides[j].swiperSlideSize;
10432                        spv ++;
10433                        if (size > s.size) breakLoop = true;
10434                    }
10435                }
10436            }
10437            else {
10438                for (i = s.activeIndex + 1; i < s.slides.length; i++) {
10439                    if (s.slidesGrid[i] - s.slidesGrid[s.activeIndex] < s.size) {
10440                        spv++;
10441                    }
10442                }
10443            }
10444            return spv;
10445        };
10446        /*=========================
10447          Slider/slides progress
10448          ===========================*/
10449        s.updateSlidesProgress = function (translate) {
10450            if (typeof translate === 'undefined') {
10451                translate = s.translate || 0;
10452            }
10453            if (s.slides.length === 0) return;
10454            if (typeof s.slides[0].swiperSlideOffset === 'undefined') s.updateSlidesOffset();
10455        
10456            var offsetCenter = -translate;
10457            if (s.rtl) offsetCenter = translate;
10458        
10459            // Visible Slides
10460            s.slides.removeClass(s.params.slideVisibleClass);
10461            for (var i = 0; i < s.slides.length; i++) {
10462                var slide = s.slides[i];
10463                var slideProgress = (offsetCenter + (s.params.centeredSlides ? s.minTranslate() : 0) - slide.swiperSlideOffset) / (slide.swiperSlideSize + s.params.spaceBetween);
10464                if (s.params.watchSlidesVisibility) {
10465                    var slideBefore = -(offsetCenter - slide.swiperSlideOffset);
10466                    var slideAfter = slideBefore + s.slidesSizesGrid[i];
10467                    var isVisible =
10468                        (slideBefore >= 0 && slideBefore < s.size) ||
10469                        (slideAfter > 0 && slideAfter <= s.size) ||
10470                        (slideBefore <= 0 && slideAfter >= s.size);
10471                    if (isVisible) {
10472                        s.slides.eq(i).addClass(s.params.slideVisibleClass);
10473                    }
10474                }
10475                slide.progress = s.rtl ? -slideProgress : slideProgress;
10476            }
10477        };
10478        s.updateProgress = function (translate) {
10479            if (typeof translate === 'undefined') {
10480                translate = s.translate || 0;
10481            }
10482            var translatesDiff = s.maxTranslate() - s.minTranslate();
10483            var wasBeginning = s.isBeginning;
10484            var wasEnd = s.isEnd;
10485            if (translatesDiff === 0) {
10486                s.progress = 0;
10487                s.isBeginning = s.isEnd = true;
10488            }
10489            else {
10490                s.progress = (translate - s.minTranslate()) / (translatesDiff);
10491                s.isBeginning = s.progress <= 0;
10492                s.isEnd = s.progress >= 1;
10493            }
10494            if (s.isBeginning && !wasBeginning) s.emit('onReachBeginning', s);
10495            if (s.isEnd && !wasEnd) s.emit('onReachEnd', s);
10496        
10497            if (s.params.watchSlidesProgress) s.updateSlidesProgress(translate);
10498            s.emit('onProgress', s, s.progress);
10499        };
10500        s.updateActiveIndex = function () {
10501            var translate = s.rtl ? s.translate : -s.translate;
10502            var newActiveIndex, i, snapIndex;
10503            for (i = 0; i < s.slidesGrid.length; i ++) {
10504                if (typeof s.slidesGrid[i + 1] !== 'undefined') {
10505                    if (translate >= s.slidesGrid[i] && translate < s.slidesGrid[i + 1] - (s.slidesGrid[i + 1] - s.slidesGrid[i]) / 2) {
10506                        newActiveIndex = i;
10507                    }
10508                    else if (translate >= s.slidesGrid[i] && translate < s.slidesGrid[i + 1]) {
10509                        newActiveIndex = i + 1;
10510                    }
10511                }
10512                else {
10513                    if (translate >= s.slidesGrid[i]) {
10514                        newActiveIndex = i;
10515                    }
10516                }
10517            }
10518            // Normalize slideIndex
10519            if(s.params.normalizeSlideIndex){
10520                if (newActiveIndex < 0 || typeof newActiveIndex === 'undefined') newActiveIndex = 0;
10521            }
10522            // for (i = 0; i < s.slidesGrid.length; i++) {
10523                // if (- translate >= s.slidesGrid[i]) {
10524                    // newActiveIndex = i;
10525                // }
10526            // }
10527            snapIndex = Math.floor(newActiveIndex / s.params.slidesPerGroup);
10528            if (snapIndex >= s.snapGrid.length) snapIndex = s.snapGrid.length - 1;
10529        
10530            if (newActiveIndex === s.activeIndex) {
10531                return;
10532            }
10533            s.snapIndex = snapIndex;
10534            s.previousIndex = s.activeIndex;
10535            s.activeIndex = newActiveIndex;
10536            s.updateClasses();
10537            s.updateRealIndex();
10538        };
10539        s.updateRealIndex = function(){
10540            s.realIndex = parseInt(s.slides.eq(s.activeIndex).attr('data-swiper-slide-index') || s.activeIndex, 10);
10541        };
10542        
10543        /*=========================
10544          Classes
10545          ===========================*/
10546        s.updateClasses = function () {
10547            s.slides.removeClass(s.params.slideActiveClass + ' ' + s.params.slideNextClass + ' ' + s.params.slidePrevClass + ' ' + s.params.slideDuplicateActiveClass + ' ' + s.params.slideDuplicateNextClass + ' ' + s.params.slideDuplicatePrevClass);
10548            var activeSlide = s.slides.eq(s.activeIndex);
10549            // Active classes
10550            activeSlide.addClass(s.params.slideActiveClass);
10551            if (params.loop) {
10552                // Duplicate to all looped slides
10553                if (activeSlide.hasClass(s.params.slideDuplicateClass)) {
10554                    s.wrapper.children('.' + s.params.slideClass + ':not(.' + s.params.slideDuplicateClass + ')[data-swiper-slide-index="' + s.realIndex + '"]').addClass(s.params.slideDuplicateActiveClass);
10555                }
10556                else {
10557                    s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + s.realIndex + '"]').addClass(s.params.slideDuplicateActiveClass);
10558                }
10559            }
10560            // Next Slide
10561            var nextSlide = activeSlide.next('.' + s.params.slideClass).addClass(s.params.slideNextClass);
10562            if (s.params.loop && nextSlide.length === 0) {
10563                nextSlide = s.slides.eq(0);
10564                nextSlide.addClass(s.params.slideNextClass);
10565            }
10566            // Prev Slide
10567            var prevSlide = activeSlide.prev('.' + s.params.slideClass).addClass(s.params.slidePrevClass);
10568            if (s.params.loop && prevSlide.length === 0) {
10569                prevSlide = s.slides.eq(-1);
10570                prevSlide.addClass(s.params.slidePrevClass);
10571            }
10572            if (params.loop) {
10573                // Duplicate to all looped slides
10574                if (nextSlide.hasClass(s.params.slideDuplicateClass)) {
10575                    s.wrapper.children('.' + s.params.slideClass + ':not(.' + s.params.slideDuplicateClass + ')[data-swiper-slide-index="' + nextSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicateNextClass);
10576                }
10577                else {
10578                    s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + nextSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicateNextClass);
10579                }
10580                if (prevSlide.hasClass(s.params.slideDuplicateClass)) {
10581                    s.wrapper.children('.' + s.params.slideClass + ':not(.' + s.params.slideDuplicateClass + ')[data-swiper-slide-index="' + prevSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicatePrevClass);
10582                }
10583                else {
10584                    s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + prevSlide.attr('data-swiper-slide-index') + '"]').addClass(s.params.slideDuplicatePrevClass);
10585                }
10586            }
10587        
10588            // Pagination
10589            if (s.paginationContainer && s.paginationContainer.length > 0) {
10590                // Current/Total
10591                var current,
10592                    total = s.params.loop ? Math.ceil((s.slides.length - s.loopedSlides * 2) / s.params.slidesPerGroup) : s.snapGrid.length;
10593                if (s.params.loop) {
10594                    current = Math.ceil((s.activeIndex - s.loopedSlides)/s.params.slidesPerGroup);
10595                    if (current > s.slides.length - 1 - s.loopedSlides * 2) {
10596                        current = current - (s.slides.length - s.loopedSlides * 2);
10597                    }
10598                    if (current > total - 1) current = current - total;
10599                    if (current < 0 && s.params.paginationType !== 'bullets') current = total + current;
10600                }
10601                else {
10602                    if (typeof s.snapIndex !== 'undefined') {
10603                        current = s.snapIndex;
10604                    }
10605                    else {
10606                        current = s.activeIndex || 0;
10607                    }
10608                }
10609                // Types
10610                if (s.params.paginationType === 'bullets' && s.bullets && s.bullets.length > 0) {
10611                    s.bullets.removeClass(s.params.bulletActiveClass);
10612                    if (s.paginationContainer.length > 1) {
10613                        s.bullets.each(function () {
10614                            if ($(this).index() === current) $(this).addClass(s.params.bulletActiveClass);
10615                        });
10616                    }
10617                    else {
10618                        s.bullets.eq(current).addClass(s.params.bulletActiveClass);
10619                    }
10620                }
10621                if (s.params.paginationType === 'fraction') {
10622                    s.paginationContainer.find('.' + s.params.paginationCurrentClass).text(current + 1);
10623                    s.paginationContainer.find('.' + s.params.paginationTotalClass).text(total);
10624                }
10625                if (s.params.paginationType === 'progress') {
10626                    var scale = (current + 1) / total,
10627                        scaleX = scale,
10628                        scaleY = 1;
10629                    if (!s.isHorizontal()) {
10630                        scaleY = scale;
10631                        scaleX = 1;
10632                    }
10633                    s.paginationContainer.find('.' + s.params.paginationProgressbarClass).transform('translate3d(0,0,0) scaleX(' + scaleX + ') scaleY(' + scaleY + ')').transition(s.params.speed);
10634                }
10635                if (s.params.paginationType === 'custom' && s.params.paginationCustomRender) {
10636                    s.paginationContainer.html(s.params.paginationCustomRender(s, current + 1, total));
10637                    s.emit('onPaginationRendered', s, s.paginationContainer[0]);
10638                }
10639            }
10640        
10641            // Next/active buttons
10642            if (!s.params.loop) {
10643                if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) {
10644                    if (s.isBeginning) {
10645                        s.prevButton.addClass(s.params.buttonDisabledClass);
10646                        if (s.params.a11y && s.a11y) s.a11y.disable(s.prevButton);
10647                    }
10648                    else {
10649                        s.prevButton.removeClass(s.params.buttonDisabledClass);
10650                        if (s.params.a11y && s.a11y) s.a11y.enable(s.prevButton);
10651                    }
10652                }
10653                if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) {
10654                    if (s.isEnd) {
10655                        s.nextButton.addClass(s.params.buttonDisabledClass);
10656                        if (s.params.a11y && s.a11y) s.a11y.disable(s.nextButton);
10657                    }
10658                    else {
10659                        s.nextButton.removeClass(s.params.buttonDisabledClass);
10660                        if (s.params.a11y && s.a11y) s.a11y.enable(s.nextButton);
10661                    }
10662                }
10663            }
10664        };
10665        
10666        /*=========================
10667          Pagination
10668          ===========================*/
10669        s.updatePagination = function () {
10670            if (!s.params.pagination) return;
10671            if (s.paginationContainer && s.paginationContainer.length > 0) {
10672                var paginationHTML = '';
10673                if (s.params.paginationType === 'bullets') {
10674                    var numberOfBullets = s.params.loop ? Math.ceil((s.slides.length - s.loopedSlides * 2) / s.params.slidesPerGroup) : s.snapGrid.length;
10675                    for (var i = 0; i < numberOfBullets; i++) {
10676                        if (s.params.paginationBulletRender) {
10677                            paginationHTML += s.params.paginationBulletRender(s, i, s.params.bulletClass);
10678                        }
10679                        else {
10680                            paginationHTML += '<' + s.params.paginationElement+' class="' + s.params.bulletClass + '"></' + s.params.paginationElement + '>';
10681                        }
10682                    }
10683                    s.paginationContainer.html(paginationHTML);
10684                    s.bullets = s.paginationContainer.find('.' + s.params.bulletClass);
10685                    if (s.params.paginationClickable && s.params.a11y && s.a11y) {
10686                        s.a11y.initPagination();
10687                    }
10688                }
10689                if (s.params.paginationType === 'fraction') {
10690                    if (s.params.paginationFractionRender) {
10691                        paginationHTML = s.params.paginationFractionRender(s, s.params.paginationCurrentClass, s.params.paginationTotalClass);
10692                    }
10693                    else {
10694                        paginationHTML =
10695                            '<span class="' + s.params.paginationCurrentClass + '"></span>' +
10696                            ' / ' +
10697                            '<span class="' + s.params.paginationTotalClass+'"></span>';
10698                    }
10699                    s.paginationContainer.html(paginationHTML);
10700                }
10701                if (s.params.paginationType === 'progress') {
10702                    if (s.params.paginationProgressRender) {
10703                        paginationHTML = s.params.paginationProgressRender(s, s.params.paginationProgressbarClass);
10704                    }
10705                    else {
10706                        paginationHTML = '<span class="' + s.params.paginationProgressbarClass + '"></span>';
10707                    }
10708                    s.paginationContainer.html(paginationHTML);
10709                }
10710                if (s.params.paginationType !== 'custom') {
10711                    s.emit('onPaginationRendered', s, s.paginationContainer[0]);
10712                }
10713            }
10714        };
10715        /*=========================
10716          Common update method
10717          ===========================*/
10718        s.update = function (updateTranslate) {
10719            if (!s) return;
10720            s.updateContainerSize();
10721            s.updateSlidesSize();
10722            s.updateProgress();
10723            s.updatePagination();
10724            s.updateClasses();
10725            if (s.params.scrollbar && s.scrollbar) {
10726                s.scrollbar.set();
10727            }
10728            var newTranslate;
10729            function forceSetTranslate() {
10730                var translate = s.rtl ? -s.translate : s.translate;
10731                newTranslate = Math.min(Math.max(s.translate, s.maxTranslate()), s.minTranslate());
10732                s.setWrapperTranslate(newTranslate);
10733                s.updateActiveIndex();
10734                s.updateClasses();
10735            }
10736            if (updateTranslate) {
10737                var translated;
10738                if (s.controller && s.controller.spline) {
10739                    s.controller.spline = undefined;
10740                }
10741                if (s.params.freeMode) {
10742                    forceSetTranslate();
10743                    if (s.params.autoHeight) {
10744                        s.updateAutoHeight();
10745                    }
10746                }
10747                else {
10748                    if ((s.params.slidesPerView === 'auto' || s.params.slidesPerView > 1) && s.isEnd && !s.params.centeredSlides) {
10749                        translated = s.slideTo(s.slides.length - 1, 0, false, true);
10750                    }
10751                    else {
10752                        translated = s.slideTo(s.activeIndex, 0, false, true);
10753                    }
10754                    if (!translated) {
10755                        forceSetTranslate();
10756                    }
10757                }
10758            }
10759            else if (s.params.autoHeight) {
10760                s.updateAutoHeight();
10761            }
10762        };
10763        
10764        /*=========================
10765          Resize Handler
10766          ===========================*/
10767        s.onResize = function (forceUpdatePagination) {
10768            if (s.params.onBeforeResize) s.params.onBeforeResize(s);
10769            //Breakpoints
10770            if (s.params.breakpoints) {
10771                s.setBreakpoint();
10772            }
10773        
10774            // Disable locks on resize
10775            var allowSwipeToPrev = s.params.allowSwipeToPrev;
10776            var allowSwipeToNext = s.params.allowSwipeToNext;
10777            s.params.allowSwipeToPrev = s.params.allowSwipeToNext = true;
10778        
10779            s.updateContainerSize();
10780            s.updateSlidesSize();
10781            if (s.params.slidesPerView === 'auto' || s.params.freeMode || force
10781UpdatePagination) s.updatePagination();
10782            if (s.params.scrollbar && s.scrollbar) {
10783                s.scrollbar.set();
10784            }
10785            if (s.controller && s.controller.spline) {
10786                s.controller.spline = undefined;
10787            }
10788            var slideChangedBySlideTo = false;
10789            if (s.params.freeMode) {
10790                var newTranslate = Math.min(Math.max(s.translate, s.maxTranslate()), s.minTranslate());
10791                s.setWrapperTranslate(newTranslate);
10792                s.updateActiveIndex();
10793                s.updateClasses();
10794        
10795                if (s.params.autoHeight) {
10796                    s.updateAutoHeight();
10797                }
10798            }
10799            else {
10800                s.updateClasses();
10801                if ((s.params.slidesPerView === 'auto' || s.params.slidesPerView > 1) && s.isEnd && !s.params.centeredSlides) {
10802                    slideChangedBySlideTo = s.slideTo(s.slides.length - 1, 0, false, true);
10803                }
10804                else {
10805                    slideChangedBySlideTo = s.slideTo(s.activeIndex, 0, false, true);
10806                }
10807            }
10808            if (s.params.lazyLoading && !slideChangedBySlideTo && s.lazy) {
10809                s.lazy.load();
10810            }
10811            // Return locks after resize
10812            s.params.allowSwipeToPrev = allowSwipeToPrev;
10813            s.params.allowSwipeToNext = allowSwipeToNext;
10814            if (s.params.onAfterResize) s.params.onAfterResize(s);
10815        };
10816        
10817        /*=========================
10818          Events
10819          ===========================*/
10820        
10821        //Define Touch Events
10822        s.touchEventsDesktop = {start: 'mousedown', move: 'mousemove', end: 'mouseup'};
10823        if (window.navigator.pointerEnabled) s.touchEventsDesktop = {start: 'pointerdown', move: 'pointermove', end: 'pointerup'};
10824        else if (window.navigator.msPointerEnabled) s.touchEventsDesktop = {start: 'MSPointerDown', move: 'MSPointerMove', end: 'MSPointerUp'};
10825        s.touchEvents = {
10826            start : s.support.touch || !s.params.simulateTouch  ? 'touchstart' : s.touchEventsDesktop.start,
10827            move : s.support.touch || !s.params.simulateTouch ? 'touchmove' : s.touchEventsDesktop.move,
10828            end : s.support.touch || !s.params.simulateTouch ? 'touchend' : s.touchEventsDesktop.end
10829        };
10830        
10831        
10832        // WP8 Touch Events Fix
10833        if (window.navigator.pointerEnabled || window.navigator.msPointerEnabled) {
10834            (s.params.touchEventsTarget === 'container' ? s.container : s.wrapper).addClass('swiper-wp8-' + s.params.direction);
10835        }
10836        
10837        // Attach/detach events
10838        s.initEvents = function (detach) {
10839            var actionDom = detach ? 'off' : 'on';
10840            var action = detach ? 'removeEventListener' : 'addEventListener';
10841            var touchEventsTarget = s.params.touchEventsTarget === 'container' ? s.container[0] : s.wrapper[0];
10842            var target = s.support.touch ? touchEventsTarget : document;
10843        
10844            var moveCapture = s.params.nested ? true : false;
10845        
10846            //Touch Events
10847            if (s.browser.ie) {
10848                touchEventsTarget[action](s.touchEvents.start, s.onTouchStart, false);
10849                target[action](s.touchEvents.move, s.onTouchMove, moveCapture);
10850                target[action](s.touchEvents.end, s.onTouchEnd, false);
10851            }
10852            else {
10853                if (s.support.touch) {
10854                    var passiveListener = s.touchEvents.start === 'touchstart' && s.support.passiveListener && s.params.passiveListeners ? {passive: true, capture: false} : false;
10855                    touchEventsTarget[action](s.touchEvents.start, s.onTouchStart, passiveListener);
10856                    touchEventsTarget[action](s.touchEvents.move, s.onTouchMove, moveCapture);
10857                    touchEventsTarget[action](s.touchEvents.end, s.onTouchEnd, passiveListener);
10858                }
10859                if ((params.simulateTouch && !s.device.ios && !s.device.android) || (params.simulateTouch && !s.support.touch && s.device.ios)) {
10860                    touchEventsTarget[action]('mousedown', s.onTouchStart, false);
10861                    document[action]('mousemove', s.onTouchMove, moveCapture);
10862                    document[action]('mouseup', s.onTouchEnd, false);
10863                }
10864            }
10865            window[action]('resize', s.onResize);
10866        
10867            // Next, Prev, Index
10868            if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) {
10869                s.nextButton[actionDom]('click', s.onClickNext);
10870                if (s.params.a11y && s.a11y) s.nextButton[actionDom]('keydown', s.a11y.onEnterKey);
10871            }
10872            if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) {
10873                s.prevButton[actionDom]('click', s.onClickPrev);
10874                if (s.params.a11y && s.a11y) s.prevButton[actionDom]('keydown', s.a11y.onEnterKey);
10875            }
10876            if (s.params.pagination && s.params.paginationClickable) {
10877                s.paginationContainer[actionDom]('click', '.' + s.params.bulletClass, s.onClickIndex);
10878                if (s.params.a11y && s.a11y) s.paginationContainer[actionDom]('keydown', '.' + s.params.bulletClass, s.a11y.onEnterKey);
10879            }
10880        
10881            // Prevent Links Clicks
10882            if (s.params.preventClicks || s.params.preventClicksPropagation) touchEventsTarget[action]('click', s.preventClicks, true);
10883        };
10884        s.attachEvents = function () {
10885            s.initEvents();
10886        };
10887        s.detachEvents = function () {
10888            s.initEvents(true);
10889        };
10890        
10891        /*=========================
10892          Handle Clicks
10893          ===========================*/
10894        // Prevent Clicks
10895        s.allowClick = true;
10896        s.preventClicks = function (e) {
10897            if (!s.allowClick) {
10898                if (s.params.preventClicks) e.preventDefault();
10899                if (s.params.preventClicksPropagation && s.animating) {
10900                    e.stopPropagation();
10901                    e.stopImmediatePropagation();
10902                }
10903            }
10904        };
10905        // Clicks
10906        s.onClickNext = function (e) {
10907            e.preventDefault();
10908            if (s.isEnd && !s.params.loop) return;
10909            s.slideNext();
10910        };
10911        s.onClickPrev = function (e) {
10912            e.preventDefault();
10913            if (s.isBeginning && !s.params.loop) return;
10914            s.slidePrev();
10915        };
10916        s.onClickIndex = function (e) {
10917            e.preventDefault();
10918            var index = $(this).index() * s.params.slidesPerGroup;
10919            if (s.params.loop) index = index + s.loopedSlides;
10920            s.slideTo(index);
10921        };
10922        
10923        /*=========================
10924          Handle Touches
10925          ===========================*/
10926        function findElementInEvent(e, selector) {
10927            var el = $(e.target);
10928            if (!el.is(selector)) {
10929                if (typeof selector === 'string') {
10930                    el = el.parents(selector);
10931                }
10932                else if (selector.nodeType) {
10933                    var found;
10934                    el.parents().each(function (index, _el) {
10935                        if (_el === selector) found = selector;
10936                    });
10937                    if (!found) return undefined;
10938                    else return selector;
10939                }
10940            }
10941            if (el.length === 0) {
10942                return undefined;
10943            }
10944            return el[0];
10945        }
10946        s.updateClickedSlide = function (e) {
10947            var slide = findElementInEvent(e, '.' + s.params.slideClass);
10948            var slideFound = false;
10949            if (slide) {
10950                for (var i = 0; i < s.slides.length; i++) {
10951                    if (s.slides[i] === slide) slideFound = true;
10952                }
10953            }
10954        
10955            if (slide && slideFound) {
10956                s.clickedSlide = slide;
10957                s.clickedIndex = $(slide).index();
10958            }
10959            else {
10960                s.clickedSlide = undefined;
10961                s.clickedIndex = undefined;
10962                return;
10963            }
10964            if (s.params.slideToClickedSlide && s.clickedIndex !== undefined && s.clickedIndex !== s.activeIndex) {
10965                var slideToIndex = s.clickedIndex,
10966                    realIndex,
10967                    duplicatedSlides,
10968                    slidesPerView = s.params.slidesPerView === 'auto' ? s.currentSlidesPerView() : s.params.slidesPerView;
10969                if (s.params.loop) {
10970                    if (s.animating) return;
10971                    realIndex = parseInt($(s.clickedSlide).attr('data-swiper-slide-index'), 10);
10972                    if (s.params.centeredSlides) {
10973                        if ((slideToIndex < s.loopedSlides - slidesPerView/2) || (slideToIndex > s.slides.length - s.loopedSlides + slidesPerView/2)) {
10974                            s.fixLoop();
10975                            slideToIndex = s.wrapper.children('.' + s.params.slideClass + '[data-swiper-slide-index="' + realIndex + '"]:not(.' + s.params.slideDuplicateClass + ')').eq(0).index();
10976                            setTimeout(function () {
10977                                s.slideTo(slideToIndex);
10978                            }, 0);
10979                        }
10980                        else {
10981                            s.slideTo(slideToIndex);
10982                        }
10983                    }
10984                    else {
10985                        if (slideToIndex > s.slides.length - slidesPerView) {
10986                            s.fixLoop();
10987                            slideToIndex = s.wrapper.children('.' + s.params.slideClass + '[data-swiper-slide-index="' + realIndex + '"]:not(.' + s.params.slideDuplicateClass + ')').eq(0).index();
10988                            setTimeout(function () {
10989                                s.slideTo(slideToIndex);
10990                            }, 0);
10991                        }
10992                        else {
10993                            s.slideTo(slideToIndex);
10994                        }
10995                    }
10996                }
10997                else {
10998                    s.slideTo(slideToIndex);
10999                }
11000            }
11001        };
11002        
11003        var isTouched,
11004            isMoved,
11005            allowTouchCallbacks,
11006            touchStartTime,
11007            isScrolling,
11008            currentTranslate,
11009            startTranslate,
11010            allowThresholdMove,
11011            // Form elements to match
11012            formElements = 'input, select, textarea, button, video',
11013            // Last click time
11014            lastClickTime = Date.now(), clickTimeout,
11015            //Velocities
11016            velocities = [],
11017            allowMomentumBounce;
11018        
11019        // Animating Flag
11020        s.animating = false;
11021        
11022        // Touches information
11023        s.touches = {
11024            startX: 0,
11025            startY: 0,
11026            currentX: 0,
11027            currentY: 0,
11028            diff: 0
11029        };
11030        
11031        // Touch handlers
11032        var isTouchEvent, startMoving;
11033        s.onTouchStart = function (e) {
11034            if (e.originalEvent) e = e.originalEvent;
11035            isTouchEvent = e.type === 'touchstart';
11036            if (!isTouchEvent && 'which' in e && e.which === 3) return;
11037            if (s.params.noSwiping && findElementInEvent(e, '.' + s.params.noSwipingClass)) {
11038                s.allowClick = true;
11039                return;
11040            }
11041            if (s.params.swipeHandler) {
11042                if (!findElementInEvent(e, s.params.swipeHandler)) return;
11043            }
11044        
11045            var startX = s.touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
11046            var startY = s.touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
11047        
11048            // Do NOT start if iOS edge swipe is detected. Otherwise iOS app (UIWebView) cannot swipe-to-go-back anymore
11049            if(s.device.ios && s.params.iOSEdgeSwipeDetection && startX <= s.params.iOSEdgeSwipeThreshold) {
11050                return;
11051            }
11052        
11053            isTouched = true;
11054            isMoved = false;
11055            allowTouchCallbacks = true;
11056            isScrolling = undefined;
11057            startMoving = undefined;
11058            s.touches.startX = startX;
11059            s.touches.startY = startY;
11060            touchStartTime = Date.now();
11061            s.allowClick = true;
11062            s.updateContainerSize();
11063            s.swipeDirection = undefined;
11064            if (s.params.threshold > 0) allowThresholdMove = false;
11065            if (e.type !== 'touchstart') {
11066                var preventDefault = true;
11067                if ($(e.target).is(formElements)) preventDefault = false;
11068                if (document.activeElement && $(document.activeElement).is(formElements)) {
11069                    document.activeElement.blur();
11070                }
11071                if (preventDefault) {
11072                    e.preventDefault();
11073                }
11074            }
11075            s.emit('onTouchStart', s, e);
11076        };
11077        
11078        s.onTouchMove = function (e) {
11079            if (e.originalEvent) e = e.originalEvent;
11080            if (isTouchEvent && e.type === 'mousemove') return;
11081            if (e.preventedByNestedSwiper) {
11082                s.touches.startX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
11083                s.touches.startY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
11084                return;
11085            }
11086            if (s.params.onlyExternal) {
11087                // isMoved = true;
11088                s.allowClick = false;
11089                if (isTouched) {
11090                    s.touches.startX = s.touches.currentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
11091                    s.touches.startY = s.touches.currentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
11092                    touchStartTime = Date.now();
11093                }
11094                return;
11095            }
11096            if (isTouchEvent && s.params.touchReleaseOnEdges && !s.params.loop) {
11097                if (!s.isHorizontal()) {
11098                    // Vertical
11099                    if (
11100                        (s.touches.currentY < s.touches.startY && s.translate <= s.maxTranslate()) ||
11101                        (s.touches.currentY > s.touches.startY && s.translate >= s.minTranslate())
11102                        ) {
11103                        return;
11104                    }
11105                }
11106                else {
11107                    if (
11108                        (s.touches.currentX < s.touches.startX && s.translate <= s.maxTranslate()) ||
11109                        (s.touches.currentX > s.touches.startX && s.translate >= s.minTranslate())
11110                        ) {
11111                        return;
11112                    }
11113                }
11114            }
11115            if (isTouchEvent && document.activeElement) {
11116                if (e.target === document.activeElement && $(e.target).is(formElements)) {
11117                    isMoved = true;
11118                    s.allowClick = false;
11119                    return;
11120                }
11121            }
11122            if (allowTouchCallbacks) {
11123                s.emit('onTouchMove', s, e);
11124            }
11125            if (e.targetTouches && e.targetTouches.length > 1) return;
11126        
11127            s.touches.currentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
11128            s.touches.currentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
11129        
11130            if (typeof isScrolling === 'undefined') {
11131                var touchAngle;
11132                if (s.isHorizontal() && s.touches.currentY === s.touches.startY || !s.isHorizontal() && s.touches.currentX === s.touches.startX) {
11133                    isScrolling = false;
11134                }
11135                else {
11136                    touchAngle = Math.atan2(Math.abs(s.touches.currentY - s.touches.startY), Math.abs(s.touches.currentX - s.touches.startX)) * 180 / Math.PI;
11137                    isScrolling = s.isHorizontal() ? touchAngle > s.params.touchAngle : (90 - touchAngle > s.params.touchAngle);
11138                }
11139            }
11140            if (isScrolling) {
11141                s.emit('onTouchMoveOpposite', s, e);
11142            }
11143            if (typeof startMoving === 'undefined') {
11144                if (s.touches.currentX !== s.touches.startX || s.touches.currentY !== s.touches.startY) {
11145                    startMoving = true;
11146                }
11147            }
11148            if (!isTouched) return;
11149            if (isScrolling)  {
11150                isTouched = false;
11151                return;
11152            }
11153            if (!startMoving) {
11154                return;
11155            }
11156            s.allowClick = false;
11157            s.emit('onSliderMove', s, e);
11158            e.preventDefault();
11159            if (s.params.touchMoveStopPropagation && !s.params.nested) {
11160                e.stopPropagation();
11161            }
11162        
11163            if (!isMoved) {
11164                if (params.loop) {
11165                    s.fixLoop();
11166                }
11167                startTranslate = s.getWrapperTranslate();
11168                s.setWrapperTransition(0);
11169                if (s.animating) {
11170                    s.wrapper.trigger('webkitTransitionEnd transitionend oTransitionEnd MSTransitionEnd msTransitionEnd');
11171                }
11172                if (s.params.autoplay && s.autoplaying) {
11173                    if (s.params.autoplayDisableOnInteraction) {
11174                        s.stopAutoplay();
11175                    }
11176                    else {
11177                        s.pauseAutoplay();
11178                    }
11179                }
11180                allowMomentumBounce = false;
11181                //Grab Cursor
11182                if (s.params.grabCursor && (s.params.allowSwipeToNext === true || s.params.allowSwipeToPrev === true)) {
11183                    s.setGrabCursor(true);
11184                }
11185            }
11186            isMoved = true;
11187        
11188            var diff = s.touches.diff = s.isHorizontal() ? s.touches.currentX - s.touches.startX : s.touches.currentY - s.touches.startY;
11189        
11190            diff = diff * s.params.touchRatio;
11191            if (s.rtl) diff = -diff;
11192        
11193            s.swipeDirection = diff > 0 ? 'prev' : 'next';
11194            currentTranslate = diff + startTranslate;
11195        
11196            var disableParentSwiper = true;
11197            if ((diff > 0 && currentTranslate > s.minTranslate())) {
11198                disableParentSwiper = false;
11199                if (s.params.resistance) currentTranslate = s.minTranslate() - 1 + Math.pow(-s.minTranslate() + startTranslate + diff, s.params.resistanceRatio);
11200            }
11201            else if (diff < 0 && currentTranslate < s.maxTranslate()) {
11202                disableParentSwiper = false;
11203                if (s.params.resistance) currentTranslate = s.maxTranslate() + 1 - Math.pow(s.maxTranslate() - startTranslate - diff, s.params.resistanceRatio);
11204            }
11205        
11206            if (disableParentSwiper) {
11207                e.preventedByNestedSwiper = true;
11208            }
11209        
11210            // Directions locks
11211            if (!s.params.allowSwipeToNext && s.swipeDirection === 'next' && currentTranslate < startTranslate) {
11212                currentTranslate = startTranslate;
11213            }
11214            if (!s.params.allowSwipeToPrev && s.swipeDirection === 'prev' && currentTranslate > startTranslate) {
11215                currentTranslate = startTranslate;
11216            }
11217        
11218        
11219            // Threshold
11220            if (s.params.threshold > 0) {
11221                if (Math.abs(diff) > s.params.threshold || allowThresholdMove) {
11222                    if (!allowThresholdMove) {
11223                        allowThresholdMove = true;
11224                        s.touches.startX = s.touches.currentX;
11225                        s.touches.startY = s.touches.currentY;
11226                        currentTranslate = startTranslate;
11227                        s.touches.diff = s.isHorizontal() ? s.touches.currentX - s.touches.startX : s.touches.currentY - s.touches.startY;
11228                        return;
11229                    }
11230                }
11231                else {
11232                    currentTranslate = startTranslate;
11233                    return;
11234                }
11235            }
11236        
11237            if (!s.params.followFinger) return;
11238        
11239            // Update active index in free mode
11240            if (s.params.freeMode || s.params.watchSlidesProgress) {
11241                s.updateActiveIndex();
11242            }
11243            if (s.params.freeMode) {
11244                //Velocity
11245                if (velocities.length === 0) {
11246                    velocities.push({
11247                        position: s.touches[s.isHorizontal() ? 'startX' : 'startY'],
11248                        time: touchStartTime
11249                    });
11250                }
11251                velocities.push({
11252                    position: s.touches[s.isHorizontal() ? 'currentX' : 'currentY'],
11253                    time: (new window.Date()).getTime()
11254                });
11255            }
11256            // Update progress
11257            s.updateProgress(currentTranslate);
11258            // Update translate
11259            s.setWrapperTranslate(currentTranslate);
11260        };
11261        s.onTouchEnd = function (e) {
11262            if (e.originalEvent) e = e.originalEvent;
11263            if (allowTouchCallbacks) {
11264                s.emit('onTouchEnd', s, e);
11265            }
11266            allowTouchCallbacks = false;
11267            if (!isTouched) return;
11268            //Return Grab Cursor
11269            if (s.params.grabCursor && isMoved && isTouched  && (s.params.allowSwipeToNext === true || s.params.allowSwipeToPrev === true)) {
11270                s.setGrabCursor(false);
11271            }
11272        
11273            // Time diff
11274            var touchEndTime = Date.now();
11275            var timeDiff = touchEndTime - touchStartTime;
11276        
11277            // Tap, doubleTap, Click
11278            if (s.allowClick) {
11279                s.updateClickedSlide(e);
11280                s.emit('onTap', s, e);
11281                if (timeDiff < 300 && (touchEndTime - lastClickTime) > 300) {
11282                    if (clickTimeout) clearTimeout(clickTimeout);
11283                    clickTimeout = setTimeout(function () {
11284                        if (!s) return;
11285                        if (s.params.paginationHide && s.paginationContainer.length > 0 && !$(e.target).hasClass(s.params.bulletClass)) {
11286                            s.paginationContainer.toggleClass(s.params.paginationHiddenClass);
11287                        }
11288                        s.emit('onClick', s, e);
11289                    }, 300);
11290        
11291                }
11292                if (timeDiff < 300 && (touchEndTime - lastClickTime) < 300) {
11293                    if (clickTimeout) clearTimeout(clickTimeout);
11294                    s.emit('onDoubleTap', s, e);
11295                }
11296            }
11297        
11298            lastClickTime = Date.now();
11299            setTimeout(function () {
11300                if (s) s.allowClick = true;
11301            }, 0);
11302        
11303            if (!isTouched || !isMoved || !s.swipeDirection || s.touches.diff === 0 || currentTranslate === startTranslate) {
11304                isTouched = isMoved = false;
11305                return;
11306            }
11307            isTouched = isMoved = false;
11308        
11309            var currentPos;
11310            if (s.params.followFinger) {
11311                currentPos = s.rtl ? s.translate : -s.translate;
11312            }
11313            else {
11314                currentPos = -currentTranslate;
11315            }
11316            if (s.params.freeMode) {
11317                if (currentPos < -s.minTranslate()) {
11318                    s.slideTo(s.activeIndex);
11319                    return;
11320                }
11321                else if (currentPos > -s.maxTranslate()) {
11322                    if (s.slides.length < s.snapGrid.length) {
11323                        s.slideTo(s.snapGrid.length - 1);
11324                    }
11325                    else {
11326                        s.slideTo(s.slides.length - 1);
11327                    }
11328                    return;
11329                }
11330        
11331                if (s.params.freeModeMomentum) {
11332                    if (velocities.length > 1) {
11333                        var lastMoveEvent = velocities.pop(), velocityEvent = velocities.pop();
11334        
11335                        var distance = lastMoveEvent.position - velocityEvent.position;
11336                        var time = lastMoveEvent.time - velocityEvent.time;
11337                        s.velocity = distance / time;
11338                        s.velocity = s.velocity / 2;
11339                        if (Math.abs(s.velocity) < s.params.freeModeMinimumVelocity) {
11340                            s.velocity = 0;
11341                        }
11342                        // this implies that the user stopped moving a finger then released.
11343                        // There would be no events with distance zero, so the last event is stale.
11344                        if (time > 150 || (new window.Date().getTime() - lastMoveEvent.time) > 300) {
11345                            s.velocity = 0;
11346                        }
11347                    } else {
11348                        s.velocity = 0;
11349                    }
11350                    s.velocity = s.velocity * s.params.freeModeMomentumVelocityRatio;
11351        
11352                    velocities.length = 0;
11353                    var momentumDuration = 1000 * s.params.freeModeMomentumRatio;
11354                    var momentumDistance = s.velocity * momentumDuration;
11355        
11356                    var newPosition = s.translate + momentumDistance;
11357                    if (s.rtl) newPosition = - newPosition;
11358                    var doBounce = false;
11359                    var afterBouncePosition;
11360                    var bounceAmount = Math.abs(s.velocity) * 20 * s.params.freeModeMomentumBounceRatio;
11361                    if (newPosition < s.maxTranslate()) {
11362                        if (s.params.freeModeMomentumBounce) {
11363                            if (newPosition + s.maxTranslate() < -bounceAmount) {
11364                                newPosition = s.maxTranslate() - bounceAmount;
11365                            }
11366                            afterBouncePosition = s.maxTranslate();
11367                            doBounce = true;
11368                            allowMomentumBounce = true;
11369                        }
11370                        else {
11371                            newPosition = s.maxTranslate();
11372                        }
11373                    }
11374                    else if (newPosition > s.minTranslate()) {
11375                        if (s.params.freeModeMomentumBounce) {
11376                            if (newPosition - s.minTranslate() > bounceAmount) {
11377                                newPosition = s.minTranslate() + bounceAmount;
11378                            }
11379                            afterBouncePosition = s.minTranslate();
11380                            doBounce = true;
11381                            allowMomentumBounce = true;
11382                        }
11383                        else {
11384                            newPosition = s.minTranslate();
11385                        }
11386                    }
11387                    else if (s.params.freeModeSticky) {
11388                        var j = 0,
11389                            nextSlide;
11390                        for (j = 0; j < s.snapGrid.length; j += 1) {
11391                            if (s.snapGrid[j] > -newPosition) {
11392                                nextSlide = j;
11393                                break;
11394                            }
11395        
11396                        }
11397                        if (Math.abs(s.snapGrid[nextSlide] - newPosition) < Math.abs(s.snapGrid[nextSlide - 1] - newPosition) || s.swipeDirection === 'next') {
11398                            newPosition = s.snapGrid[nextSlide];
11399                        } else {
11400                            newPosition = s.snapGrid[nextSlide - 1];
11401                        }
11402                        if (!s.rtl) newPosition = - newPosition;
11403                    }
11404                    //Fix duration
11405                    if (s.velocity !== 0) {
11406                        if (s.rtl) {
11407                            momentumDuration = Math.abs((-newPosition - s.translate) / s.velocity);
11408                        }
11409                        else {
11410                            momentumDuration = Math.abs((newPosition - s.translate) / s.velocity);
11411                        }
11412                    }
11413                    else if (s.params.freeModeSticky) {
11414                        s.slideReset();
11415                        return;
11416                    }
11417        
11418                    if (s.params.freeModeMomentumBounce && doBounce) {
11419                        s.updateProgress(afterBouncePosition);
11420                        s.setWrapperTransition(momentumDuration);
11421                        s.setWrapperTranslate(newPosition);
11422                        s.onTransitionStart();
11423                        s.animating = true;
11424                        s.wrapper.transitionEnd(function () {
11425                            if (!s || !allowMomentumBounce) return;
11426                            s.emit('onMomentumBounce', s);
11427        
11428                            s.setWrapperTransition(s.params.speed);
11429                            s.setWrapperTranslate(afterBouncePosition);
11430                            s.wrapper.transitionEnd(function () {
11431                                if (!s) return;
11432                                s.onTransitionEnd();
11433                            });
11434                        });
11435                    } else if (s.velocity) {
11436                        s.updateProgress(newPosition);
11437                        s.setWrapperTransition(momentumDuration);
11438                        s.setWrapperTranslate(newPosition);
11439                        s.onTransitionStart();
11440                        if (!s.animating) {
11441                            s.animating = true;
11442                            s.wrapper.transitionEnd(function () {
11443                                if (!s) return;
11444                                s.onTransitionEnd();
11445                            });
11446                        }
11447        
11448                    } else {
11449                        s.updateProgress(newPosition);
11450                    }
11451        
11452                    s.updateActiveIndex();
11453                }
11454                if (!s.params.freeModeMomentum || timeDiff >= s.params.longSwipesMs) {
11455                    s.updateProgress();
11456                    s.updateActiveIndex();
11457                }
11458                return;
11459            }
11460        
11461            // Find current slide
11462            var i, stopIndex = 0, groupSize = s.slidesSizesGrid[0];
11463            for (i = 0; i < s.slidesGrid.length; i += s.params.slidesPerGroup) {
11464                if (typeof s.slidesGrid[i + s.params.slidesPerGroup] !== 'undefined') {
11465                    if (currentPos >= s.slidesGrid[i] && currentPos < s.slidesGrid[i + s.params.slidesPerGroup]) {
11466                        stopIndex = i;
11467                        groupSize = s.slidesGrid[i + s.params.slidesPerGroup] - s.slidesGrid[i];
11468                    }
11469                }
11470                else {
11471                    if (currentPos >= s.slidesGrid[i]) {
11472                        stopIndex = i;
11473                        groupSize = s.slidesGrid[s.slidesGrid.length - 1] - s.slidesGrid[s.slidesGrid.length - 2];
11474                    }
11475                }
11476            }
11477        
11478            // Find current slide size
11479            var ratio = (currentPos - s.slidesGrid[stopIndex]) / groupSize;
11480        
11481            if (timeDiff > s.params.longSwipesMs) {
11482                // Long touches
11483                if (!s.params.longSwipes) {
11484                    s.slideTo(s.activeIndex);
11485                    return;
11486                }
11487                if (s.swipeDirection === 'next') {
11488                    if (ratio >= s.params.longSwipesRatio) s.slideTo(stopIndex + s.params.slidesPerGroup);
11489                    else s.slideTo(stopIndex);
11490        
11491                }
11492                if (s.swipeDirection === 'prev') {
11493                    if (ratio > (1 - s.params.longSwipesRatio)) s.slideTo(stopIndex + s.params.slidesPerGroup);
11494                    else s.slideTo(stopIndex);
11495                }
11496            }
11497            else {
11498                // Short swipes
11499                if (!s.params.shortSwipes) {
11500                    s.slideTo(s.activeIndex);
11501                    return;
11502                }
11503                if (s.swipeDirection === 'next') {
11504                    s.slideTo(stopIndex + s.params.slidesPerGroup);
11505        
11506                }
11507                if (s.swipeDirection === 'prev') {
11508                    s.slideTo(stopIndex);
11509                }
11510            }
11511        };
11512        /*=========================
11513          Transitions
11514          ===========================*/
11515        s._slideTo = function (slideIndex, speed) {
11516            return s.slideTo(slideIndex, speed, true, true);
11517        };
11518        s.slideTo = function (slideIndex, speed, runCallbacks, internal) {
11519            if (typeof runCallbacks === 'undefined') runCallbacks = true;
11520            if (typeof slideIndex === 'undefined') slideIndex = 0;
11521            if (slideIndex < 0) slideIndex = 0;
11522            s.snapIndex = Math.floor(slideIndex / s.params.slidesPerGroup);
11523            if (s.snapIndex >= s.snapGrid.length) s.snapIndex = s.snapGrid.length - 1;
11524        
11525            var translate = - s.snapGrid[s.snapIndex];
11526            // Stop autoplay
11527            if (s.params.autoplay && s.autoplaying) {
11528                if (internal || !s.params.autoplayDisableOnInteraction) {
11529                    s.pauseAutoplay(speed);
11530                }
11531                else {
11532                    s.stopAutoplay();
11533                }
11534            }
11535            // Update progress
11536            s.updateProgress(translate);
11537        
11538            // Normalize slideIndex
11539            if(s.params.normalizeSlideIndex){
11540                for (var i = 0; i < s.slidesGrid.length; i++) {
11541                    if (- Math.floor(translate * 100) >= Math.floor(s.slidesGrid[i] * 100)) {
11542                        slideIndex = i;
11543                    }
11544                }
11545            }
11546        
11547            // Directions locks
11548            if (!s.params.allowSwipeToNext && translate < s.translate && translate < s.minTranslate()) {
11549                return false;
11550            }
11551            if (!s.params.allowSwipeToPrev && translate > s.translate && translate > s.maxTranslate()) {
11552                if ((s.activeIndex || 0) !== slideIndex ) return false;
11553            }
11554        
11555            // Update Index
11556            if (typeof speed === 'undefined') speed = s.params.speed;
11557            s.previousIndex = s.activeIndex || 0;
11558            s.activeIndex = slideIndex;
11559            s.updateRealIndex();
11560            if ((s.rtl && -translate === s.translate) || (!s.rtl && translate === s.translate)) {
11561                // Update Height
11562                if (s.params.autoHeight) {
11563                    s.updateAutoHeight();
11564                }
11565                s.updateClasses();
11566                if (s.params.effect !== 'slide') {
11567                    s.setWrapperTranslate(translate);
11568                }
11569                return false;
11570            }
11571            s.updateClasses();
11572            s.onTransitionStart(runCallbacks);
11573        
11574            if (speed === 0 || s.browser.lteIE9) {
11575                s.setWrapperTranslate(translate);
11576                s.setWrapperTransition(0);
11577                s.onTransitionEnd(runCallbacks);
11578            }
11579            else {
11580                s.setWrapperTranslate(translate);
11581                s.setWrapperTransition(speed);
11582                if (!s.animating) {
11583                    s.animating = true;
11584                    s.wrapper.transitionEnd(function () {
11585                        if (!s) return;
11586                        s.onTransitionEnd(runCallbacks);
11587                    });
11588                }
11589        
11590            }
11591        
11592            return true;
11593        };
11594        
11595        s.onTransitionStart = function (runCallbacks) {
11596            if (typeof runCallbacks === 'undefined') runCallbacks = true;
11597            if (s.params.autoHeight) {
11598                s.updateAutoHeight();
11599            }
11600            if (s.lazy) s.lazy.onTransitionStart();
11601            if (runCallbacks) {
11602                s.emit('onTransitionStart', s);
11603                if (s.activeIndex !== s.previousIndex) {
11604                    s.emit('onSlideChangeStart', s);
11605                    if (s.activeIndex > s.previousIndex) {
11606                        s.emit('onSlideNextStart', s);
11607                    }
11608                    else {
11609                        s.emit('onSlidePrevStart', s);
11610                    }
11611                }
11612        
11613            }
11614        };
11615        s.onTransitionEnd = function (runCallbacks) {
11616            s.animating = false;
11617            s.setWrapperTransition(0);
11618            if (typeof runCallbacks === 'undefined') runCallbacks = true;
11619            if (s.lazy) s.lazy.onTransitionEnd();
11620            if (runCallbacks) {
11621                s.emit('onTransitionEnd', s);
11622                if (s.activeIndex !== s.previousIndex) {
11623                    s.emit('onSlideChangeEnd', s);
11624                    if (s.activeIndex > s.previousIndex) {
11625                        s.emit('onSlideNextEnd', s);
11626                    }
11627                    else {
11628                        s.emit('onSlidePrevEnd', s);
11629                    }
11630                }
11631            }
11632            if (s.params.history && s.history) {
11633                s.history.setHistory(s.params.history, s.activeIndex);
11634            }
11635            if (s.params.hashnav && s.hashnav) {
11636                s.hashnav.setHash();
11637            }
11638        
11639        };
11640        s.slideNext = function (runCallbacks, speed, internal) {
11641            if (s.params.loop) {
11642                if (s.animating) return false;
11643                s.fixLoop();
11644                var clientLeft = s.container[0].clientLeft;
11645                return s.slideTo(s.activeIndex + s.params.slidesPerGroup, speed, runCallbacks, internal);
11646            }
11647            else return s.slideTo(s.activeIndex + s.params.slidesPerGroup, speed, runCallbacks, internal);
11648        };
11649        s._slideNext = function (speed) {
11650            return s.slideNext(true, speed, true);
11651        };
11652        s.slidePrev = function (runCallbacks, speed, internal) {
11653            if (s.params.loop) {
11654                if (s.animating) return false;
11655                s.fixLoop();
11656                var clientLeft = s.container[0].clientLeft;
11657                return s.slideTo(s.activeIndex - 1, speed, runCallbacks, internal);
11658            }
11659            else return s.slideTo(s.activeIndex - 1, speed, runCallbacks, internal);
11660        };
11661        s._slidePrev = function (speed) {
11662            return s.slidePrev(true, speed, true);
11663        };
11664        s.slideReset = function (runCallbacks, speed, internal) {
11665            return s.slideTo(s.activeIndex, speed, runCallbacks);
11666        };
11667        
11668        s.disableTouchControl = function () {
11669            s.params.onlyExternal = true;
11670            return true;
11671        };
11672        s.enableTouchControl = function () {
11673            s.params.onlyExternal = false;
11674            return true;
11675        };
11676        
11677        /*=========================
11678          Translate/transition helpers
11679          ===========================*/
11680        s.setWrapperTransition = function (duration, byController) {
11681            s.wrapper.transition(duration);
11682            if (s.params.effect !== 'slide' && s.effects[s.params.effect]) {
11683                s.effects[s.params.effect].setTransition(duration);
11684            }
11685            if (s.params.parallax && s.parallax) {
11686                s.parallax.setTransition(duration);
11687            }
11688            if (s.params.scrollbar && s.scrollbar) {
11689                s.scrollbar.setTransition(duration);
11690            }
11691            if (s.params.control && s.controller) {
11692                s.controller.setTransition(duration, byController);
11693            }
11694            s.emit('onSetTransition', s, duration);
11695        };
11696        s.setWrapperTranslate = function (translate, updateActiveIndex, byController) {
11697            var x = 0, y = 0, z = 0;
11698            if (s.isHorizontal()) {
11699                x = s.rtl ? -translate : translate;
11700            }
11701            else {
11702                y = translate;
11703            }
11704        
11705            if (s.params.roundLengths) {
11706                x = round(x);
11707                y = round(y);
11708            }
11709        
11710            if (!s.params.virtualTranslate) {
11711                if (s.support.transforms3d) s.wrapper.transform('translate3d(' + x + 'px, ' + y + 'px, ' + z + 'px)');
11712                else s.wrapper.transform('translate(' + x + 'px, ' + y + 'px)');
11713            }
11714        
11715            s.translate = s.isHorizontal() ? x : y;
11716        
11717            // Check if we need to update progress
11718            var progress;
11719            var translatesDiff = s.maxTranslate() - s.minTranslate();
11720            if (translatesDiff === 0) {
11721                progress = 0;
11722            }
11723            else {
11724                progress = (translate - s.minTranslate()) / (translatesDiff);
11725            }
11726            if (progress !== s.progress) {
11727                s.updateProgress(translate);
11728            }
11729        
11730            if (updateActiveIndex) s.updateActiveIndex();
11731            if (s.params.effect !== 'slide' && s.effects[s.params.effect]) {
11732                s.effects[s.params.effect].setTranslate(s.translate);
11733            }
11734            if (s.params.parallax && s.parallax) {
11735                s.parallax.setTranslate(s.translate);
11736            }
11737            if (s.params.scrollbar && s.scrollbar) {
11738                s.scrollbar.setTranslate(s.translate);
11739            }
11740            if (s.params.control && s.controller) {
11741                s.controller.setTranslate(s.translate, byController);
11742            }
11743            s.emit('onSetTranslate', s, s.translate);
11744        };
11745        
11746        s.getTranslate = function (el, axis) {
11747            var matrix, curTransform, curStyle, transformMatrix;
11748        
11749            // automatic axis detection
11750            if (typeof axis === 'undefined') {
11751                axis = 'x';
11752            }
11753        
11754            if (s.params.virtualTranslate) {
11755                return s.rtl ? -s.translate : s.translate;
11756            }
11757        
11758            curStyle = window.getComputedStyle(el, null);
11759            if (window.WebKitCSSMatrix) {
11760                curTransform = curStyle.transform || curStyle.webkitTransform;
11761                if (curTransform.split(',').length > 6) {
11762                    curTransform = curTransform.split(', ').map(function(a){
11763                        return a.replace(',','.');
11764                    }).join(', ');
11765                }
11766                // Some old versions of Webkit choke when 'none' is passed; pass
11767                // empty string instead in this case
11768                transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
11769            }
11770            else {
11771                transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform  || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
11772                matrix = transformMatrix.toString().split(',');
11773            }
11774        
11775            if (axis === 'x') {
11776                //Latest Chrome and webkits Fix
11777                if (window.WebKitCSSMatrix)
11778                    curTransform = transformMatrix.m41;
11779                //Crazy IE10 Matrix
11780                else if (matrix.length === 16)
11781                    curTransform = parseFloat(matrix[12]);
11782                //Normal Browsers
11783                else
11784                    curTransform = parseFloat(matrix[4]);
11785            }
11786            if (axis === 'y') {
11787                //Latest Chrome and webkits Fix
11788                if (window.WebKitCSSMatrix)
11789                    curTransform = transformMatrix.m42;
11790                //Crazy IE10 Matrix
11791                else if (matrix.length === 16)
11792                    curTransform = parseFloat(matrix[13]);
11793                //Normal Browsers
11794                else
11795                    curTransform = parseFloat(matrix[5]);
11796            }
11797            if (s.rtl && curTransform) curTransform = -curTransform;
11798            return curTransform || 0;
11799        };
11800        s.getWrapperTranslate = function (axis) {
11801            if (typeof axis === 'undefined') {
11802                axis = s.isHorizontal() ? 'x' : 'y';
11803            }
11804            return s.getTranslate(s.wrapper[0], axis);
11805        };
11806        
11807        /*=========================
11808          Observer
11809          ===========================*/
11810        s.observers = [];
11811        function initObserver(target, options) {
11812            options = options || {};
11813            // create an observer instance
11814            var ObserverFunc = window.MutationObserver || window.WebkitMutationObserver;
11815            var observer = new ObserverFunc(function (mutations) {
11816                mutations.forEach(function (mutation) {
11817                    s.onResize(true);
11818                    s.emit('onObserverUpdate', s, mutation);
11819                });
11820            });
11821        
11822            observer.observe(target, {
11823                attributes: typeof options.attributes === 'undefined' ? true : options.attributes,
11824                childList: typeof options.childList === 'undefined' ? true : options.childList,
11825                characterData: typeof options.characterData === 'undefined' ? true : options.characterData
11826            });
11827        
11828            s.observers.push(observer);
11829        }
11830        s.initObservers = function () {
11831            if (s.params.observeParents) {
11832                var containerParents = s.container.parents();
11833                for (var i = 0; i < containerParents.length; i++) {
11834                    initObserver(containerParents[i]);
11835                }
11836            }
11837        
11838            // Observe container
11839            initObserver(s.container[0], {childList: false});
11840        
11841            // Observe wrapper
11842            initObserver(s.wrapper[0], {attributes: false});
11843        };
11844        s.disconnectObservers = function () {
11845            for (var i = 0; i < s.observers.length; i++) {
11846                s.observers[i].disconnect();
11847            }
11848            s.observers = [];
11849        };
11850        /*=========================
11851          Loop
11852          ===========================*/
11853        // Create looped slides
11854        s.createLoop = function () {
11855            // Remove duplicated slides
11856            s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass).remove();
11857        
11858            var slides = s.wrapper.children('.' + s.params.slideClass);
11859        
11860            if(s.params.slidesPerView === 'auto' && !s.params.loopedSlides) s.params.loopedSlides = slides.length;
11861        
11862            s.loopedSlides = parseInt(s.params.loopedSlides || s.params.slidesPerView, 10);
11863            s.loopedSlides = s.loopedSlides + s.params.loopAdditionalSlides;
11864            if (s.loopedSlides > slides.length) {
11865                s.loopedSlides = slides.length;
11866            }
11867        
11868            var prependSlides = [], appendSlides = [], i;
11869            slides.each(function (index, el) {
11870                var slide = $(this);
11871                if (index < s.loopedSlides) appendSlides.push(el);
11872                if (index < slides.length && index >= slides.length - s.loopedSlides) prependSlides.push(el);
11873                slide.attr('data-swiper-slide-index', index);
11874            });
11875            for (i = 0; i < appendSlides.length; i++) {
11876                s.wrapper.append($(appendSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));
11877            }
11878            for (i = prependSlides.length - 1; i >= 0; i--) {
11879                s.wrapper.prepend($(prependSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));
11880            }
11881        };
11882        s.destroyLoop = function () {
11883            s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass).remove();
11884            s.slides.removeAttr('data-swiper-slide-index');
11885        };
11886        s.reLoop = function (updatePosition) {
11887            var oldIndex = s.activeIndex - s.loopedSlides;
11888            s.destroyLoop();
11889            s.createLoop();
11890            s.updateSlidesSize();
11891            if (updatePosition) {
11892                s.slideTo(oldIndex + s.loopedSlides, 0, false);
11893            }
11894        
11895        };
11896        s.fixLoop = function () {
11897            var newIndex;
11898            //Fix For Negative Oversliding
11899            if (s.activeIndex < s.loopedSlides) {
11900                newIndex = s.slides.length - s.loopedSlides * 3 + s.activeIndex;
11901                newIndex = newIndex + s.loopedSlides;
11902                s.slideTo(newIndex, 0, false, true);
11903            }
11904            //Fix For Positive Oversliding
11905            else if ((s.params.slidesPerView === 'auto' && s.activeIndex >= s.loopedSlides * 2) || (s.activeIndex > s.slides.length - s.params.slidesPerView * 2)) {
11906                newIndex = -s.slides.length + s.activeIndex + s.loopedSlides;
11907                newIndex = newIndex + s.loopedSlides;
11908                s.slideTo(newIndex, 0, false, true);
11909            }
11910        };
11911        /*=========================
11912          Append/Prepend/Remove Slides
11913          ===========================*/
11914        s.appendSlide = function (slides) {
11915            if (s.params.loop) {
11916                s.destroyLoop();
11917            }
11918            if (typeof slides === 'object' && slides.length) {
11919                for (var i = 0; i < slides.length; i++) {
11920                    if (slides[i]) s.wrapper.append(slides[i]);
11921                }
11922            }
11923            else {
11924                s.wrapper.append(slides);
11925            }
11926            if (s.params.loop) {
11927                s.createLoop();
11928            }
11929            if (!(s.params.observer && s.support.observer)) {
11930                s.update(true);
11931            }
11932        };
11933        s.prependSlide = function (slides) {
11934            if (s.params.loop) {
11935                s.destroyLoop();
11936            }
11937            var newActiveIndex = s.activeIndex + 1;
11938            if (typeof slides === 'object' && slides.length) {
11939                for (var i = 0; i < slides.length; i++) {
11940                    if (slides[i]) s.wrapper.prepend(slides[i]);
11941                }
11942                newActiveIndex = s.activeIndex + slides.length;
11943            }
11944            else {
11945                s.wrapper.prepend(slides);
11946            }
11947            if (s.params.loop) {
11948                s.createLoop();
11949            }
11950            if (!(s.params.observer && s.support.observer)) {
11951                s.update(true);
11952            }
11953            s.slideTo(newActiveIndex, 0, false);
11954        };
11955        s.removeSlide = function (slidesIndexes) {
11956            if (s.params.loop) {
11957                s.destroyLoop();
11958                s.slides = s.wrapper.children('.' + s.params.slideClass);
11959            }
11960            var newActiveIndex = s.activeIndex,
11961                indexToRemove;
11962            if (typeof slidesIndexes === 'object' && slidesIndexes.length) {
11963                for (var i = 0; i < slidesIndexes.length; i++) {
11964                    indexToRemove = slidesIndexes[i];
11965                    if (s.slides[indexToRemove]) s.slides.eq(indexToRemove).remove();
11966                    if (indexToRemove < newActiveIndex) newActiveIndex--;
11967                }
11968                newActiveIndex = Math.max(newActiveIndex, 0);
11969            }
11970            else {
11971                indexToRemove = slidesIndexes;
11972                if (s.slides[indexToRemove]) s.slides.eq(indexToRemove).remove();
11973                if (indexToRemove < newActiveIndex) newActiveIndex--;
11974                newActiveIndex = Math.max(newActiveIndex, 0);
11975            }
11976        
11977            if (s.params.loop) {
11978                s.createLoop();
11979            }
11980        
11981            if (!(s.params.observer && s.support.observer)) {
11982                s.update(true);
11983            }
11984            if (s.params.loop) {
11985                s.slideTo(newActiveIndex + s.loopedSlides, 0, false);
11986            }
11987            else {
11988                s.slideTo(newActiveIndex, 0, false);
11989            }
11990        
11991        };
11992        s.removeAllSlides = function () {
11993            var slidesIndexes = [];
11994            for (var i = 0; i < s.slides.length; i++) {
11995                slidesIndexes.push(i);
11996            }
11997            s.removeSlide(slidesIndexes);
11998        };
11999        
12000
12001        /*=========================
12002          Effects
12003          ===========================*/
12004        s.effects = {
12005            fade: {
12006                setTranslate: function () {
12007                    for (var i = 0; i < s.slides.length; i++) {
12008                        var slide = s.slides.eq(i);
12009                        var offset = slide[0].swiperSlideOffset;
12010                        var tx = -offset;
12011                        if (!s.params.virtualTranslate) tx = tx - s.translate;
12012                        var ty = 0;
12013                        if (!s.isHorizontal()) {
12014                            ty = tx;
12015                            tx = 0;
12016                        }
12017                        var slideOpacity = s.params.fade.crossFade ?
12018                                Math.max(1 - Math.abs(slide[0].progress), 0) :
12019                                1 + Math.min(Math.max(slide[0].progress, -1), 0);
12020                        slide
12021                            .css({
12022                                opacity: slideOpacity
12023                            })
12024                            .transform('translate3d(' + tx + 'px, ' + ty + 'px, 0px)');
12025        
12026                    }
12027        
12028                },
12029                setTransition: function (duration) {
12030                    s.slides.transition(duration);
12031                    if (s.params.virtualTranslate && duration !== 0) {
12032                        var eventTriggered = false;
12033                        s.slides.transitionEnd(function () {
12034                            if (eventTriggered) return;
12035                            if (!s) return;
12036                            eventTriggered = true;
12037                            s.animating = false;
12038                            var triggerEvents = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'];
12039                            for (var i = 0; i < triggerEvents.length; i++) {
12040                                s.wrapper.trigger(triggerEvents[i]);
12041                            }
12042                        });
12043                    }
12044                }
12045            },
12046            flip: {
12047                setTranslate: function () {
12048                    for (var i = 0; i < s.slides.length; i++) {
12049                        var slide = s.slides.eq(i);
12050                        var progress = slide[0].progress;
12051                        if (s.params.flip.limitRotation) {
12052                            progress = Math.max(Math.min(slide[0].progress, 1), -1);
12053                        }
12054                        var offset = slide[0].swiperSlideOffset;
12055                        var rotate = -180 * progress,
12056                            rotateY = rotate,
12057                            rotateX = 0,
12058                            tx = -offset,
12059                            ty = 0;
12060                        if (!s.isHorizontal()) {
12061                            ty = tx;
12062                            tx = 0;
12063                            rotateX = -rotateY;
12064                            rotateY = 0;
12065                        }
12066                        else if (s.rtl) {
12067                            rotateY = -rotateY;
12068                        }
12069        
12070                        slide[0].style.zIndex = -Math.abs(Math.round(progress)) + s.slides.length;
12071        
12072                        if (s.params.flip.slideShadows) {
12073                            //Set shadows
12074                            var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top');
12075                            var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom');
12076                            if (shadowBefore.length === 0) {
12077                                shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>');
12078                                slide.append(shadowBefore);
12079                            }
12080                            if (shadowAfter.length === 0) {
12081                                shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>');
12082                                slide.append(shadowAfter);
12083                            }
12084                            if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
12085                            if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
12086                        }
12087        
12088                        slide
12089                            .transform('translate3d(' + tx + 'px, ' + ty + 'px, 0px) rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg)');
12090                    }
12091                },
12092                setTransition: function (duration) {
12093                    s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);
12094                    if (s.params.virtualTranslate && duration !== 0) {
12095                        var eventTriggered = false;
12096                        s.slides.eq(s.activeIndex).transitionEnd(function () {
12097                            if (eventTriggered) return;
12098                            if (!s) return;
12099                            if (!$(this).hasClass(s.params.slideActiveClass)) return;
12100                            eventTriggered = true;
12101                            s.animating = false;
12102                            var triggerEvents = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'];
12103                            for (var i = 0; i < triggerEvents.length; i++) {
12104                                s.wrapper.trigger(triggerEvents[i]);
12105                            }
12106                        });
12107                    }
12108                }
12109            },
12110            cube: {
12111                setTranslate: function () {
12112                    var wrapperRotate = 0, cubeShadow;
12113                    if (s.params.cube.shadow) {
12114                        if (s.isHorizontal()) {
12115                            cubeShadow = s.wrapper.find('.swiper-cube-shadow');
12116                            if (cubeShadow.length === 0) {
12117                                cubeShadow = $('<div class="swiper-cube-shadow"></div>');
12118                                s.wrapper.append(cubeShadow);
12119                            }
12120                            cubeShadow.css({height: s.width + 'px'});
12121                        }
12122                        else {
12123                            cubeShadow = s.container.find('.swiper-cube-shadow');
12124                            if (cubeShadow.length === 0) {
12125                                cubeShadow = $('<div class="swiper-cube-shadow"></div>');
12126                                s.container.append(cubeShadow);
12127                            }
12128                        }
12129                    }
12130                    for (var i = 0; i < s.slides.length; i++) {
12131                        var slide = s.slides.eq(i);
12132                        var slideAngle = i * 90;
12133                        var round = Math.floor(slideAngle / 360);
12134                        if (s.rtl) {
12135                            slideAngle = -slideAngle;
12136                            round = Math.floor(-slideAngle / 360);
12137                        }
12138                        var progress = Math.max(Math.min(slide[0].progress, 1), -1);
12139                        var tx = 0, ty = 0, tz = 0;
12140                        if (i % 4 === 0) {
12141                            tx = - round * 4 * s.size;
12142                            tz = 0;
12143                        }
12144                        else if ((i - 1) % 4 === 0) {
12145                            tx = 0;
12146                            tz = - round * 4 * s.size;
12147                        }
12148                        else if ((i - 2) % 4 === 0) {
12149                            tx = s.size + round * 4 * s.size;
12150                            tz = s.size;
12151                        }
12152                        else if ((i - 3) % 4 === 0) {
12153                            tx = - s.size;
12154                            tz = 3 * s.size + s.size * 4 * round;
12155                        }
12156                        if (s.rtl) {
12157                            tx = -tx;
12158                        }
12159        
12160                        if (!s.isHorizontal()) {
12161                            ty = tx;
12162                            tx = 0;
12163                        }
12164        
12165                        var transform = 'rotateX(' + (s.isHorizontal() ? 0 : -slideAngle) + 'deg) rotateY(' + (s.isHorizontal() ? slideAngle : 0) + 'deg) translate3d(' + tx + 'px, ' + ty + 'px, ' + tz + 'px)';
12166                        if (progress <= 1 && progress > -1) {
12167                            wrapperRotate = i * 90 + progress * 90;
12168                            if (s.rtl) wrapperRotate = -i * 90 - progress * 90;
12169                        }
12170                        slide.transform(transform);
12171                        if (s.params.cube.slideShadows) {
12172                            //Set shadows
12173                            var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top');
12174                            var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom');
12175                            if (shadowBefore.length === 0) {
12176                                shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>');
12177                                slide.append(shadowBefore);
12178                            }
12179                            if (shadowAfter.length === 0) {
12180                                shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>');
12181                                slide.append(shadowAfter);
12182                            }
12183                            if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
12184                            if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
12185                        }
12186                    }
12187                    s.wrapper.css({
12188                        '-webkit-transform-origin': '50% 50% -' + (s.size / 2) + 'px',
12189                        '-moz-transform-origin': '50% 50% -' + (s.size / 2) + 'px',
12190                        '-ms-transform-origin': '50% 50% -' + (s.size / 2) + 'px',
12191                        'transform-origin': '50% 50% -' + (s.size / 2) + 'px'
12192                    });
12193        
12194                    if (s.params.cube.shadow) {
12195                        if (s.isHorizontal()) {
12196                            cubeShadow.transform('translate3d(0px, ' + (s.width / 2 + s.params.cube.shadowOffset) + 'px, ' + (-s.width / 2) + 'px) rotateX(90deg) rotateZ(0deg) scale(' + (s.params.cube.shadowScale) + ')');
12197                        }
12198                        else {
12199                            var shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90;
12200                            var multiplier = 1.5 - (Math.sin(shadowAngle * 2 * Math.PI / 360) / 2 + Math.cos(shadowAngle * 2 * Math.PI / 360) / 2);
12201                            var scale1 = s.params.cube.shadowScale,
12202                                scale2 = s.params.cube.shadowScale / multiplier,
12203                                offset = s.params.cube.shadowOffset;
12204                            cubeShadow.transform('scale3d(' + scale1 + ', 1, ' + scale2 + ') translate3d(0px, ' + (s.height / 2 + offset) + 'px, ' + (-s.height / 2 / scale2) + 'px) rotateX(-90deg)');
12205                        }
12206                    }
12207                    var zFactor = (s.isSafari || s.isUiWebView) ? (-s.size / 2) : 0;
12208                    s.wrapper.transform('translate3d(0px,0,' + zFactor + 'px) rotateX(' + (s.isHorizontal() ? 0 : wrapperRotate) + 'deg) rotateY(' + (s.isHorizontal() ? -wrapperRotate : 0) + 'deg)');
12209                },
12210                setTransition: function (duration) {
12211                    s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);
12212                    if (s.params.cube.shadow && !s.isHorizontal()) {
12213                        s.container.find('.swiper-cube-shadow').transition(duration);
12214                    }
12215                }
12216            },
12217            coverflow: {
12218                setTranslate: function () {
12219                    var transform = s.translate;
12220                    var center = s.isHorizontal() ? -transform + s.width / 2 : -transform + s.height / 2;
12221                    var rotate = s.isHorizontal() ? s.params.coverflow.rotate: -s.params.coverflow.rotate;
12222                    var translate = s.params.coverflow.depth;
12223                    //Each slide offset from center
12224                    for (var i = 0, length = s.slides.length; i < length; i++) {
12225                        var slide = s.slides.eq(i);
12226                        var slideSize = s.slidesSizesGrid[i];
12227                        var slideOffset = slide[0].swiperSlideOffset;
12228                        var offsetMultiplier = (center - slideOffset - slideSize / 2) / slideSize * s.params.coverflow.modifier;
12229        
12230                        var rotateY = s.isHorizontal() ? rotate * offsetMultiplier : 0;
12231                        var rotateX = s.isHorizontal() ? 0 : rotate * offsetMultiplier;
12232                        // var rotateZ = 0
12233                        var translateZ = -translate * Math.abs(offsetMultiplier);
12234        
12235                        var translateY = s.isHorizontal() ? 0 : s.params.coverflow.stretch * (offsetMultiplier);
12236                        var translateX = s.isHorizontal() ? s.params.coverflow.stretch * (offsetMultiplier) : 0;
12237        
12238                        //Fix for ultra small values
12239                        if (Math.abs(translateX) < 0.001) translateX = 0;
12240                        if (Math.abs(translateY) < 0.001) translateY = 0;
12241                        if (Math.abs(translateZ) < 0.001) translateZ = 0;
12242                        if (Math.abs(rotateY) < 0.001) rotateY = 0;
12243                        if (Math.abs(rotateX) < 0.001) rotateX = 0;
12244        
12245                        var slideTransform = 'translate3d(' + translateX + 'px,' + translateY + 'px,' + translateZ + 'px)  rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg)';
12246        
12247                        slide.transform(slideTransform);
12248                        slide[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1;
12249                        if (s.params.coverflow.slideShadows) {
12250                            //Set shadows
12251                            var shadowBefore = s.isHorizontal() ? slide.find('.swiper-slide-shadow-left') : slide.find('.swiper-slide-shadow-top');
12252                            var shadowAfter = s.isHorizontal() ? slide.find('.swiper-slide-shadow-right') : slide.find('.swiper-slide-shadow-bottom');
12253                            if (shadowBefore.length === 0) {
12254                                shadowBefore = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'left' : 'top') + '"></div>');
12255                                slide.append(shadowBefore);
12256                            }
12257                            if (shadowAfter.length === 0) {
12258                                shadowAfter = $('<div class="swiper-slide-shadow-' + (s.isHorizontal() ? 'right' : 'bottom') + '"></div>');
12259                                slide.append(shadowAfter);
12260                            }
12261                            if (shadowBefore.length) shadowBefore[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0;
12262                            if (shadowAfter.length) shadowAfter[0].style.opacity = (-offsetMultiplier) > 0 ? -offsetMultiplier : 0;
12263                        }
12264                    }
12265        
12266                    //Set correct perspective for IE10
12267                    if (s.browser.ie) {
12268                        var ws = s.wrapper[0].style;
12269                        ws.perspectiveOrigin = center + 'px 50%';
12270                    }
12271                },
12272                setTransition: function (duration) {
12273                    s.slides.transition(duration).find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left').transition(duration);
12274                }
12275            }
12276        };
12277        
12278
12279        /*=========================
12280          Images Lazy Loading
12281          ===========================*/
12282        s.lazy = {
12283            initialImageLoaded: false,
12284            loadImageInSlide: function (index, loadInDuplicate) {
12285                if (typeof index === 'undefined') return;
12286                if (typeof loadInDuplicate === 'undefined') loadInDuplicate = true;
12287                if (s.slides.length === 0) return;
12288        
12289                var slide = s.slides.eq(index);
12290                var img = slide.find('.' + s.params.lazyLoadingClass + ':not(.' + s.params.lazyStatusLoadedClass + '):not(.' + s.params.lazyStatusLoadingClass + ')');
12291                if (slide.hasClass(s.params.lazyLoadingClass) && !slide.hasClass(s.params.lazyStatusLoadedClass) && !slide.hasClass(s.params.lazyStatusLoadingClass)) {
12292                    img = img.add(slide[0]);
12293                }
12294                if (img.length === 0) return;
12295        
12296                img.each(function () {
12297                    var _img = $(this);
12298                    _img.addClass(s.params.lazyStatusLoadingClass);
12299                    var background = _img.attr('data-background');
12300                    var src = _img.attr('data-src'),
12301                        srcset = _img.attr('data-srcset'),
12302                        sizes = _img.attr('data-sizes');
12303                    s.loadImage(_img[0], (src || background), srcset, sizes, false, function () {
12304                        if (typeof s === 'undefined' || s === null || !s) return;
12305                        if (background) {
12306                            _img.css('background-image', 'url("' + background + '")');
12307                            _img.removeAttr('data-background');
12308                        }
12309                        else {
12310                            if (srcset) {
12311                                _img.attr('srcset', srcset);
12312                                _img.removeAttr('data-srcset');
12313                            }
12314                            if (sizes) {
12315                                _img.attr('sizes', sizes);
12316                                _img.removeAttr('data-sizes');
12317                            }
12318                            if (src) {
12319                                _img.attr('src', src);
12320                                _img.removeAttr('data-src');
12321                            }
12322        
12323                        }
12324        
12325                        _img.addClass(s.params.lazyStatusLoadedClass).removeClass(s.params.lazyStatusLoadingClass);
12326                        slide.find('.' + s.params.lazyPreloaderClass + ', .' + s.params.preloaderClass).remove();
12327                        if (s.params.loop && loadInDuplicate) {
12328                            var slideOriginalIndex = slide.attr('data-swiper-slide-index');
12329                            if (slide.hasClass(s.params.slideDuplicateClass)) {
12330                                var originalSlide = s.wrapper.children('[data-swiper-slide-index="' + slideOriginalIndex + '"]:not(.' + s.params.slideDuplicateClass + ')');
12331                                s.lazy.loadImageInSlide(originalSlide.index(), false);
12332                            }
12333                            else {
12334                                var duplicatedSlide = s.wrapper.children('.' + s.params.slideDuplicateClass + '[data-swiper-slide-index="' + slideOriginalIndex + '"]');
12335                                s.lazy.loadImageInSlide(duplicatedSlide.index(), false);
12336                            }
12337                        }
12338                        s.emit('onLazyImageReady', s, slide[0], _img[0]);
12339                    });
12340        
12341                    s.emit('onLazyImageLoad', s, slide[0], _img[0]);
12342                });
12343        
12344            },
12345            load: function () {
12346                var i;
12347                var slidesPerView = s.params.slidesPerView;
12348                if (slidesPerView === 'auto') {
12349                    slidesPerView = 0;
12350                }
12351                if (!s.lazy.initialImageLoaded) s.lazy.initialImageLoaded = true;
12352                if (s.params.watchSlidesVisibility) {
12353                    s.wrapper.children('.' + s.params.slideVisibleClass).each(function () {
12354                        s.lazy.loadImageInSlide($(this).index());
12355                    });
12356                }
12357                else {
12358                    if (slidesPerView > 1) {
12359                        for (i = s.activeIndex; i < s.activeIndex + slidesPerView ; i++) {
12360                            if (s.slides[i]) s.lazy.loadImageInSlide(i);
12361                        }
12362                    }
12363                    else {
12364                        s.lazy.loadImageInSlide(s.activeIndex);
12365                    }
12366                }
12367                if (s.params.lazyLoadingInPrevNext) {
12368                    if (slidesPerView > 1 || (s.params.lazyLoadingInPrevNextAmount && s.params.lazyLoadingInPrevNextAmount > 1)) {
12369                        var amount = s.params.lazyLoadingInPrevNextAmount;
12370                        var spv = slidesPerView;
12371                        var maxIndex = Math.min(s.activeIndex + spv + Math.max(amount, spv), s.slides.length);
12372                        var minIndex = Math.max(s.activeIndex - Math.max(spv, amount), 0);
12373                        // Next Slides
12374                        for (i = s.activeIndex + slidesPerView; i < maxIndex; i++) {
12375                            if (s.slides[i]) s.lazy.loadImageInSlide(i);
12376                        }
12377                        // Prev Slides
12378                        for (i = minIndex; i < s.activeIndex ; i++) {
12379                            if (s.slides[i]) s.lazy.loadImageInSlide(i);
12380                        }
12381                    }
12382                    else {
12383                        var nextSlide = s.wrapper.children('.' + s.params.slideNextClass);
12384                        if (nextSlide.length > 0) s.lazy.loadImageInSlide(nextSlide.index());
12385        
12386                        var prevSlide = s.wrapper.children('.' + s.params.slidePrevClass);
12387                        if (prevSlide.length > 0) s.lazy.loadImageInSlide(prevSlide.index());
12388                    }
12389                }
12390            },
12391            onTransitionStart: function () {
12392                if (s.params.lazyLoading) {
12393                    if (s.params.lazyLoadingOnTransitionStart || (!s.params.lazyLoadingOnTransitionStart && !s.lazy.initialImageLoaded)) {
12394                        s.lazy.load();
12395                    }
12396                }
12397            },
12398            onTransitionEnd: function () {
12399                if (s.params.lazyLoading && !s.params.lazyLoadingOnTransitionStart) {
12400                    s.lazy.load();
12401                }
12402            }
12403        };
12404        
12405
12406        /*=========================
12407          Scrollbar
12408          ===========================*/
12409        s.scrollbar = {
12410            isTouched: false,
12411            setDragPosition: function (e) {
12412                var sb = s.scrollbar;
12413                var x = 0, y = 0;
12414                var translate;
12415                var pointerPosition = s.isHorizontal() ?
12416                    ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageX : e.pageX || e.clientX) :
12417                    ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageY : e.pageY || e.clientY) ;
12418                var position = (pointerPosition) - sb.track.offset()[s.isHorizontal() ? 'left' : 'top'] - sb.dragSize / 2;
12419                var positionMin = -s.minTranslate() * sb.moveDivider;
12420                var positionMax = -s.maxTranslate() * sb.moveDivider;
12421                if (position < positionMin) {
12422                    position = positionMin;
12423                }
12424                else if (position > positionMax) {
12425                    position = positionMax;
12426                }
12427                position = -position / sb.moveDivider;
12428                s.updateProgress(position);
12429                s.setWrapperTranslate(position, true);
12430            },
12431            dragStart: function (e) {
12432                var sb = s.scrollbar;
12433                sb.isTouched = true;
12434                e.preventDefault();
12435                e.stopPropagation();
12436        
12437                sb.setDragPosition(e);
12438                clearTimeout(sb.dragTimeout);
12439        
12440                sb.track.transition(0);
12441                if (s.params.scrollbarHide) {
12442                    sb.track.css('opacity', 1);
12443                }
12444                s.wrapper.transition(100);
12445                sb.drag.transition(100);
12446                s.emit('onScrollbarDragStart', s);
12447            },
12448            dragMove: function (e) {
12449                var sb = s.scrollbar;
12450                if (!sb.isTouched) return;
12451                if (e.preventDefault) e.preventDefault();
12452                else e.returnValue = false;
12453                sb.setDragPosition(e);
12454                s.wrapper.transition(0);
12455                sb.track.transition(0);
12456                sb.drag.transition(0);
12457                s.emit('onScrollbarDragMove', s);
12458            },
12459            dragEnd: function (e) {
12460                var sb = s.scrollbar;
12461                if (!sb.isTouched) return;
12462                sb.isTouched = false;
12463                if (s.params.scrollbarHide) {
12464                    clearTimeout(sb.dragTimeout);
12465                    sb.dragTimeout = setTimeout(function () {
12466                        sb.track.css('opacity', 0);
12467                        sb.track.transition(400);
12468                    }, 1000);
12469        
12470                }
12471                s.emit('onScrollbarDragEnd', s);
12472                if (s.params.scrollbarSnapOnRelease) {
12473                    s.slideReset();
12474                }
12475            },
12476            draggableEvents: (function () {
12477                if ((s.params.simulateTouch === false && !s.support.touch)) return s.touchEventsDesktop;
12478                else return s.touchEvents;
12479            })(),
12480            enableDraggable: function () {
12481                var sb = s.scrollbar;
12482                var target = s.support.touch ? sb.track : document;
12483                $(sb.track).on(sb.draggableEvents.start, sb.dragStart);
12484                $(target).on(sb.draggableEvents.move, sb.dragMove);
12485                $(target).on(sb.draggableEvents.end, sb.dragEnd);
12486            },
12487            disableDraggable: function () {
12488                var sb = s.scrollbar;
12489                var target = s.support.touch ? sb.track : document;
12490                $(sb.track).off(sb.draggableEvents.start, sb.dragStart);
12491                $(target).off(sb.draggableEvents.move, sb.dragMove);
12492                $(target).off(sb.draggableEvents.end, sb.dragEnd);
12493            },
12494            set: function () {
12495                if (!s.params.scrollbar) return;
12496                var sb = s.scrollbar;
12497                sb.track = $(s.params.scrollbar);
12498                if (s.params.uniqueNavElements && typeof s.params.scrollbar === 'string' && sb.track.length > 1 && s.container.find(s.params.scrollbar).length === 1) {
12499                    sb.track = s.container.find(s.params.scrollbar);
12500                }
12501                sb.drag = sb.track.find('.swiper-scrollbar-drag');
12502                if (sb.drag.length === 0) {
12503                    sb.drag = $('<div class="swiper-scrollbar-drag"></div>');
12504                    sb.track.append(sb.drag);
12505                }
12506                sb.drag[0].style.width = '';
12507                sb.drag[0].style.height = '';
12508                sb.trackSize = s.isHorizontal() ? sb.track[0].offsetWidth : sb.track[0].offsetHeight;
12509        
12510                sb.divider = s.size / s.virtualSize;
12511                sb.moveDivider = sb.divider * (sb.trackSize / s.size);
12512                sb.dragSize = sb.trackSize * sb.divider;
12513        
12514                if (s.isHorizontal()) {
12515                    sb.drag[0].style.width = sb.dragSize + 'px';
12516                }
12517                else {
12518                    sb.drag[0].style.height = sb.dragSize + 'px';
12519                }
12520        
12521                if (sb.divider >= 1) {
12522                    sb.track[0].style.display = 'none';
12523                }
12524                else {
12525                    sb.track[0].style.display = '';
12526                }
12527                if (s.params.scrollbarHide) {
12528                    sb.track[0].style.opacity = 0;
12529                }
12530            },
12531            setTranslate: function () {
12532                if (!s.params.scrollbar) return;
12533                var diff;
12534                var sb = s.scrollbar;
12535                var translate = s.translate || 0;
12536                var newPos;
12537        
12538                var newSize = sb.dragSize;
12539                newPos = (sb.trackSize - sb.dragSize) * s.progress;
12540                if (s.rtl && s.isHorizontal()) {
12541                    newPos = -newPos;
12542                    if (newPos > 0) {
12543                        newSize = sb.dragSize - newPos;
12544                        newPos = 0;
12545                    }
12546                    else if (-newPos + sb.dragSize > sb.trackSize) {
12547                        newSize = sb.trackSize + newPos;
12548                    }
12549                }
12550                else {
12551                    if (newPos < 0) {
12552                        newSize = sb.dragSize + newPos;
12553                        newPos = 0;
12554                    }
12555                    else if (newPos + sb.dragSize > sb.trackSize) {
12556                        newSize = sb.trackSize - newPos;
12557                    }
12558                }
12559                if (s.isHorizontal()) {
12560                    if (s.support.transforms3d) {
12561                        sb.drag.transform('translate3d(' + (newPos) + 'px, 0, 0)');
12562                    }
12563                    else {
12564                        sb.drag.transform('translateX(' + (newPos) + 'px)');
12565                    }
12566                    sb.drag[0].style.width = newSize + 'px';
12567                }
12568                else {
12569                    if (s.support.transforms3d) {
12570                        sb.drag.transform('translate3d(0px, ' + (newPos) + 'px, 0)');
12571                    }
12572                    else {
12573                        sb.drag.transform('translateY(' + (newPos) + 'px)');
12574                    }
12575                    sb.drag[0].style.height = newSize + 'px';
12576                }
12577                if (s.params.scrollbarHide) {
12578                    clearTimeout(sb.timeout);
12579                    sb.track[0].style.opacity = 1;
12580                    sb.timeout = setTimeout(function () {
12581                        sb.track[0].style.opacity = 0;
12582                        sb.track.transition(400);
12583                    }, 1000);
12584                }
12585            },
12586            setTransition: function (duration) {
12587                if (!s.params.scrollbar) return;
12588                s.scrollbar.drag.transition(duration);
12589            }
12590        };
12591        
12592
12593        /*=========================
12594          Controller
12595          ===========================*/
12596        s.controller = {
12597            LinearSpline: function (x, y) {
12598                var binarySearch = (function() {
12599                    var maxIndex, minIndex, guess;
12600                    return function(array, val) {
12601                        minIndex = -1;
12602                        maxIndex = array.length;
12603                        while (maxIndex - minIndex > 1)
12604                            if (array[guess = maxIndex + minIndex >> 1] <= val) {
12605                                minIndex = guess;
12606                            } else {
12607                                maxIndex = guess;
12608                            }
12609                        return maxIndex;
12610                    };
12611                })();
12612                this.x = x;
12613                this.y = y;
12614                this.lastIndex = x.length - 1;
12615                // Given an x value (x2), return the expected y2 value:
12616                // (x1,y1) is the known point before given value,
12617                // (x3,y3) is the known point after given value.
12618                var i1, i3;
12619                var l = this.x.length;
12620        
12621                this.interpolate = function (x2) {
12622                    if (!x2) return 0;
12623        
12624                    // Get the indexes of x1 and x3 (the array indexes before and after given x2):
12625                    i3 = binarySearch(this.x, x2);
12626                    i1 = i3 - 1;
12627        
12628                    // We have our indexes i1 & i3, so we can calculate already:
12629                    // y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1
12630                    return ((x2 - this.x[i1]) * (this.y[i3] - this.y[i1])) / (this.x[i3] - this.x[i1]) + this.y[i1];
12631                };
12632            },
12633            //xxx: for now i will just save one spline function to to
12634            getInterpolateFunction: function(c){
12635                if(!s.controller.spline) s.controller.spline = s.params.loop ?
12636                    new s.controller.LinearSpline(s.slidesGrid, c.slidesGrid) :
12637                    new s.controller.LinearSpline(s.snapGrid, c.snapGrid);
12638            },
12639            setTranslate: function (translate, byController) {
12640               var controlled = s.params.control;
12641               var multiplier, controlledTranslate;
12642               function setControlledTranslate(c) {
12643                    // this will create an Interpolate function based on the snapGrids
12644                    // x is the Grid of the scrolled scroller and y will be the controlled scroller
12645                    // it makes sense to create this only once and recall it for the interpolation
12646                    // the function does a lot of value caching for performance
12647                    translate = c.rtl && c.params.direction === 'horizontal' ? -s.translate : s.translate;
12648                    if (s.params.controlBy === 'slide') {
12649                        s.controller.getInterpolateFunction(c);
12650                        // i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid
12651                        // but it did not work out
12652                        controlledTranslate = -s.controller.spline.interpolate(-translate);
12653                    }
12654        
12655                    if(!controlledTranslate || s.params.controlBy === 'container'){
12656                        multiplier = (c.maxTranslate() - c.minTranslate()) / (s.maxTranslate() - s.minTranslate());
12657                        controlledTranslate = (translate - s.minTranslate()) * multiplier + c.minTranslate();
12658                    }
12659        
12660                    if (s.params.controlInverse) {
12661                        controlledTranslate = c.maxTranslate() - controlledTranslate;
12662                    }
12663                    c.updateProgress(controlledTranslate);
12664                    c.setWrapperTranslate(controlledTranslate, false, s);
12665                    c.updateActiveIndex();
12666               }
12667               if (Array.isArray(controlled)) {
12668                   for (var i = 0; i < controlled.length; i++) {
12669                       if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
12670                           setControlledTranslate(controlled[i]);
12671                       }
12672                   }
12673               }
12674               else if (controlled instanceof Swiper && byController !== controlled) {
12675        
12676                   setControlledTranslate(controlled);
12677               }
12678            },
12679            setTransition: function (duration, byController) {
12680                var controlled = s.params.control;
12681                var i;
12682                function setControlledTransition(c) {
12683                    c.setWrapperTransition(duration, s);
12684                    if (duration !== 0) {
12685                        c.onTransitionStart();
12686                        c.wrapper.transitionEnd(function(){
12687                            if (!controlled) return;
12688                            if (c.params.loop && s.params.controlBy === 'slide') {
12689                                c.fixLoop();
12690                            }
12691                            c.onTransitionEnd();
12692        
12693                        });
12694                    }
12695                }
12696                if (Array.isArray(controlled)) {
12697                    for (i = 0; i < controlled.length; i++) {
12698                        if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
12699                            setControlledTransition(controlled[i]);
12700                        }
12701                    }
12702                }
12703                else if (controlled instanceof Swiper && byController !== controlled) {
12704                    setControlledTransition(controlled);
12705                }
12706            }
12707        };
12708        
12709
12710        /*=========================
12711          Hash Navigation
12712          ===========================*/
12713        s.hashnav = {
12714            onHashCange: function (e, a) {
12715                var newHash = document.location.hash.replace('#', '');
12716                var activeSlideHash = s.slides.eq(s.activeIndex).attr('data-hash');
12717                if (newHash !== activeSlideHash) {
12718                    s.slideTo(s.wrapper.children('.' + s.params.slideClass + '[data-hash="' + (newHash) + '"]').index());
12719                }
12720            },
12721            attachEvents: function (detach) {
12722                var action = detach ? 'off' : 'on';
12723                $(window)[action]('hashchange', s.hashnav.onHashCange);
12724            },
12725            setHash: function () {
12726                if (!s.hashnav.initialized || !s.params.hashnav) return;
12727                if (s.params.replaceState && window.history && window.history.replaceState) {
12728                    window.history.replaceState(null, null, ('#' + s.slides.eq(s.activeIndex).attr('data-hash') || ''));
12729                } else {
12730                    var slide = s.slides.eq(s.activeIndex);
12731                    var hash = slide.attr('data-hash') || slide.attr('data-history');
12732                    document.location.hash = hash || '';
12733                }
12734            },
12735            init: function () {
12736                if (!s.params.hashnav || s.params.history) return;
12737                s.hashnav.initialized = true;
12738                var hash = document.location.hash.replace('#', '');
12739                if (hash) {
12740                    var speed = 0;
12741                    for (var i = 0, length = s.slides.length; i < length; i++) {
12742                        var slide = s.slides.eq(i);
12743                        var slideHash = slide.attr('data-hash') || slide.attr('data-history');
12744                        if (slideHash === hash && !slide.hasClass(s.params.slideDuplicateClass)) {
12745                            var index = slide.index();
12746                            s.slideTo(index, speed, s.params.runCallbacksOnInit, true);
12747                        }
12748                    }
12749                }
12750                if (s.params.hashnavWatchState) s.hashnav.attachEvents();
12751            },
12752            destroy: function () {
12753                if (s.params.hashnavWatchState) s.hashnav.attachEvents(true);
12754            }
12755        };
12756        
12757
12758        /*=========================
12759          History Api with fallback to Hashnav
12760          ===========================*/
12761        s.history = {
12762            init: function () {
12763                if (!s.params.history) return;
12764                if (!window.history || !window.history.pushState) {
12765                    s.params.history = false;
12766                    s.params.hashnav = true;
12767                    return;
12768                }
12769                s.history.initialized = true;
12770                this.paths = this.getPathValues();
12771                if (!this.paths.key && !this.paths.value) return;
12772                this.scrollToSlide(0, this.paths.value, s.params.runCallbacksOnInit);
12773                if (!s.params.replaceState) {
12774                    window.addEventListener('popstate', this.setHistoryPopState);
12775                }
12776            },
12777            setHistoryPopState: function() {
12778                s.history.paths = s.history.getPathValues();
12779                s.history.scrollToSlide(s.params.speed, s.history.paths.value, false);
12780            },
12781            getPathValues: function() {
12782                var pathArray = window.location.pathname.slice(1).split('/');
12783                var total = pathArray.length;
12784                var key = pathArray[total - 2];
12785                var value = pathArray[total - 1];
12786                return { key: key, value: value };
12787            },
12788            setHistory: function (key, index) {
12789                if (!s.history.initialized || !s.params.history) return;
12790                var slide = s.slides.eq(index);
12791                var value = this.slugify(slide.attr('data-history'));
12792                if (!window.location.pathname.includes(key)) {
12793                    value = key + '/' + value;
12794                }
12795                if (s.params.replaceState) {
12796                    window.history.replaceState(null, null, value);
12797                } else {
12798                    window.history.pushState(null, null, value);
12799                }
12800            },
12801            slugify: function(text) {
12802                return text.toString().toLowerCase()
12803                    .replace(/\s+/g, '-')
12804                    .replace(/[^\w\-]+/g, '')
12805                    .replace(/\-\-+/g, '-')
12806                    .replace(/^-+/, '')
12807                    .replace(/-+$/, '');
12808            },
12809            scrollToSlide: function(speed, value, runCallbacks) {
12810                if (value) {
12811                    for (var i = 0, length = s.slides.length; i < length; i++) {
12812                        var slide = s.slides.eq(i);
12813                        var slideHistory = this.slugify(slide.attr('data-history'));
12814                        if (slideHistory === value && !slide.hasClass(s.params.slideDuplicateClass)) {
12815                            var index = slide.index();
12816                            s.slideTo(index, speed, runCallbacks);
12817                        }
12818                    }
12819                } else {
12820                    s.slideTo(0, speed, runCallbacks);
12821                }
12822            }
12823        };
12824        
12825
12826        /*=========================
12827          Keyboard Control
12828          ===========================*/
12829        function handleKeyboard(e) {
12830            if (e.originalEvent) e = e.originalEvent; //jquery fix
12831            var kc = e.keyCode || e.charCode;
12832            // Directions locks
12833            if (!s.params.allowSwipeToNext && (s.isHorizontal() && kc === 39 || !s.isHorizontal() && kc === 40)) {
12834                return false;
12835            }
12836            if (!s.params.allowSwipeToPrev && (s.isHorizontal() && kc === 37 || !s.isHorizontal() && kc === 38)) {
12837                return false;
12838            }
12839            if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) {
12840                return;
12841            }
12842            if (document.activeElement && document.activeElement.nodeName && (document.activeElement.nodeName.toLowerCase() === 'input' || document.activeElement.nodeName.toLowerCase() === 'textarea')) {
12843                return;
12844            }
12845            if (kc === 37 || kc === 39 || kc === 38 || kc === 40) {
12846                var inView = false;
12847                //Check that swiper should be inside of visible area of window
12848                if (s.container.parents('.' + s.params.slideClass).length > 0 && s.container.parents('.' + s.params.slideActiveClass).length === 0) {
12849                    return;
12850                }
12851                var windowScroll = {
12852                    left: window.pageXOffset,
12853                    top: window.pageYOffset
12854                };
12855                var windowWidth = window.innerWidth;
12856                var windowHeight = window.innerHeight;
12857                var swiperOffset = s.container.offset();
12858                if (s.rtl) swiperOffset.left = swiperOffset.left - s.container[0].scrollLeft;
12859                var swiperCoord = [
12860                    [swiperOffset.left, swiperOffset.top],
12861                    [swiperOffset.left + s.width, swiperOffset.top],
12862                    [swiperOffset.left, swiperOffset.top + s.height],
12863                    [swiperOffset.left + s.width, swiperOffset.top + s.height]
12864                ];
12865                for (var i = 0; i < swiperCoord.length; i++) {
12866                    var point = swiperCoord[i];
12867                    if (
12868                        point[0] >= windowScroll.left && point[0] <= windowScroll.left + windowWidth &&
12869                        point[1] >= windowScroll.top && point[1] <= windowScroll.top + windowHeight
12870                    ) {
12871                        inView = true;
12872                    }
12873        
12874                }
12875                if (!inView) return;
12876            }
12877            if (s.isHorizontal()) {
12878                if (kc === 37 || kc === 39) {
12879                    if (e.preventDefault) e.preventDefault();
12880                    else e.returnValue = false;
12881                }
12882                if ((kc === 39 && !s.rtl) || (kc === 37 && s.rtl)) s.slideNext();
12883                if ((kc === 37 && !s.rtl) || (kc === 39 && s.rtl)) s.slidePrev();
12884            }
12885            else {
12886                if (kc === 38 || kc === 40) {
12887                    if (e.preventDefault) e.preventDefault();
12888                    else e.returnValue = false;
12889                }
12890                if (kc === 40) s.slideNext();
12891                if (kc === 38) s.slidePrev();
12892            }
12893            s.emit('onKeyPress', s, kc);
12894        }
12895        s.disableKeyboardControl = function () {
12896            s.params.keyboardControl = false;
12897            $(document).off('keydown', handleKeyboard);
12898        };
12899        s.enableKeyboardControl = function () {
12900            s.params.keyboardControl = true;
12901            $(document).on('keydown', handleKeyboard);
12902        };
12903        
12904
12905        /*=========================
12906          Mousewheel Control
12907          ===========================*/
12908        s.mousewheel = {
12909            event: false,
12910            lastScrollTime: (new window.Date()).getTime()
12911        };
12912        function isEventSupported() {
12913            var eventName = 'onwheel';
12914            var isSupported = eventName in document;
12915        
12916            if (!isSupported) {
12917                var element = document.createElement('div');
12918                element.setAttribute(eventName, 'return;');
12919                isSupported = typeof element[eventName] === 'function';
12920            }
12921        
12922            if (!isSupported &&
12923                document.implementation &&
12924                document.implementation.hasFeature &&
12925                    // always returns true in newer browsers as per the standard.
12926                    // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
12927                document.implementation.hasFeature('', '') !== true ) {
12928                // This is the only way to test support for the `wheel` event in IE9+.
12929                isSupported = document.implementation.hasFeature('Events.wheel', '3.0');
12930            }
12931        
12932            return isSupported;
12933        }
12934        /**
12935         * Mouse wheel (and 2-finger trackpad) support on the web sucks.  It is
12936         * complicated, thus this doc is long and (hopefully) detailed enough to answer
12937         * your questions.
12938         *
12939         * If you need to react to the mouse wheel in a predictable way, this code is
12940         * like your bestest friend. * hugs *
12941         *
12942         * As of today, there are 4 DOM event types you can listen to:
12943         *
12944         *   'wheel'                -- Chrome(31+), FF(17+), IE(9+)
12945         *   'mousewheel'           -- Chrome, IE(6+), Opera, Safari
12946         *   'MozMousePixelScroll'  -- FF(3.5 only!) (2010-2013) -- don't bother!
12947         *   'DOMMouseScroll'       -- FF(0.9.7+) since 2003
12948         *
12949         * So what to do?  The is the best:
12950         *
12951         *   normalizeWheel.getEventType();
12952         *
12953         * In your event callback, use this code to get sane interpretation of the
12954         * deltas.  This code will return an object with properties:
12955         *
12956         *   spinX   -- normalized spin speed (use for zoom) - x plane
12957         *   spinY   -- " - y plane
12958         *   pixelX  -- normalized distance (to pixels) - x plane
12959         *   pixelY  -- " - y plane
12960         *
12961         * Wheel values are provided by the browser assuming you are using the wheel to
12962         * scroll a web page by a number of lines or pixels (or pages).  Values can vary
12963         * significantly on different platforms and browsers, forgetting that you can
12964         * scroll at different speeds.  Some devices (like trackpads) emit more events
12965         * at smaller increments with fine granularity, and some emit massive jumps with
12966         * linear speed or acceleration.
12967         *
12968         * This code does its best to normalize the deltas for you:
12969         *
12970         *   - spin is trying to normalize how far the wheel was spun (or trackpad
12971         *     dragged).  This is super useful for zoom support where you want to
12972         *     throw away the chunky scroll steps on the PC and make those equal to
12973         *     the slow and smooth tiny steps on the Mac. Key data: This code tries to
12974         *     resolve a single slow step on a wheel to 1.
12975         *
12976         *   - pixel is normalizing the desired scroll delta in pixel units.  You'll
12977         *     get the crazy differences between browsers, but at least it'll be in
12978         *     pixels!
12979         *
12980         *   - positive value indicates scrolling DOWN/RIGHT, negative UP/LEFT.  This
12981         *     should translate to positive value zooming IN, negative zooming OUT.
12982         *     This matches the newer 'wheel' event.
12983         *
12984         * Why are there spinX, spinY (or pixels)?
12985         *
12986         *   - spinX is a 2-finger side drag on the trackpad, and a shift + wheel turn
12987         *     with a mouse.  It results in side-scrolling in the browser by default.
12988         *
12989         *   - spinY is what you expect -- it's the classic axis of a mouse wheel.
12990         *
12991         *   - I dropped spinZ/pixelZ.  It is supported by the DOM 3 'wheel' event and
12992         *     probably is by browsers in conjunction with fancy 3D controllers .. but
12993         *     you know.
12994         *
12995         * Implementation info:
12996         *
12997         * Examples of 'wheel' event if you scroll slowly (down) by one step with an
12998         * average mouse:
12999         *
13000         *   OS X + Chrome  (mouse)     -    4   pixel delta  (wheelDelta -120)
13001         *   OS X + Safari  (mouse)     -  N/A   pixel delta  (wheelDelta  -12)
13002         *   OS X + Firefox (mouse)     -    0.1 line  delta  (wheelDelta  N/A)
13003         *   Win8 + Chrome  (mouse)     -  100   pixel delta  (wheelDelta -120)
13004         *   Win8 + Firefox (mouse)     -    3   line  delta  (wheelDelta -120)
13005         *
13006         * On the trackpad:
13007         *
13008         *   OS X + Chrome  (trackpad)  -    2   pixel delta  (wheelDelta   -6)
13009         *   OS X + Firefox (trackpad)  -    1   pixel delta  (wheelDelta  N/A)
13010         *
13011         * On other/older browsers.. it's more complicated as there can be multiple and
13012         * also missing delta values.
13013         *
13014         * The 'wheel' event is more standard:
13015         *
13016         * http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
13017         *
13018         * The basics is that it includes a unit, deltaMode (pixels, lines, pages), and
13019         * deltaX, deltaY and deltaZ.  Some browsers provide other values to maintain
13020         * backward compatibility with older events.  Those other values help us
13021         * better normalize spin speed.  Example of what the browsers provide:
13022         *
13023         *                          | event.wheelDelta | event.detail
13024         *        ------------------+------------------+--------------
13025         *          Safari v5/OS X  |       -120       |       0
13026         *          Safari v5/Win7  |       -120       |       0
13027         *         Chrome v17/OS X  |       -120       |       0
13028         *         Chrome v17/Win7  |       -120       |       0
13029         *                IE9/Win7  |       -120       |   undefined
13030         *         Firefox v4/OS X  |     undefined    |       1
13031         *         Firefox v4/Win7  |     undefined    |       3
13032         *
13033         */
13034        function normalizeWheel( /*object*/ event ) /*object*/ {
13035            // Reasonable defaults
13036            var PIXEL_STEP = 10;
13037            var LINE_HEIGHT = 40;
13038            var PAGE_HEIGHT = 800;
13039        
13040            var sX = 0, sY = 0,       // spinX, spinY
13041                pX = 0, pY = 0;       // pixelX, pixelY
13042        
13043            // Legacy
13044            if( 'detail' in event ) {
13045                sY = event.detail;
13046            }
13047            if( 'wheelDelta' in event ) {
13048                sY = -event.wheelDelta / 120;
13049            }
13050            if( 'wheelDeltaY' in event ) {
13051                sY = -event.wheelDeltaY / 120;
13052            }
13053            if( 'wheelDeltaX' in event ) {
13054                sX = -event.wheelDeltaX / 120;
13055            }
13056        
13057            // side scrolling on FF with DOMMouseScroll
13058            if( 'axis' in event && event.axis === event.HORIZONTAL_AXIS ) {
13059                sX = sY;
13060                sY = 0;
13061            }
13062        
13063            pX = sX * PIXEL_STEP;
13064            pY = sY * PIXEL_STEP;
13065        
13066            if( 'deltaY' in event ) {
13067                pY = event.deltaY;
13068            }
13069            if( 'deltaX' in event ) {
13070                pX = event.deltaX;
13071            }
13072        
13073            if( (pX || pY) && event.deltaMode ) {
13074                if( event.deltaMode === 1 ) {          // delta in LINE units
13075                    pX *= LINE_HEIGHT;
13076                    pY *= LINE_HEIGHT;
13077                } else {                             // delta in PAGE units
13078                    pX *= PAGE_HEIGHT;
13079                    pY *= PAGE_HEIGHT;
13080                }
13081            }
13082        
13083            // Fall-back if spin cannot be determined
13084            if( pX && !sX ) {
13085                sX = (pX < 1) ? -1 : 1;
13086            }
13087            if( pY && !sY ) {
13088                sY = (pY < 1) ? -1 : 1;
13089            }
13090        
13091            return {
13092                spinX: sX,
13093                spinY: sY,
13094                pixelX: pX,
13095                pixelY: pY
13096            };
13097        }
13098        if (s.params.mousewheelControl) {
13099            /**
13100             * The best combination if you prefer spinX + spinY normalization.  It favors
13101             * the older DOMMouseScroll for Firefox, as FF does not include wheelDelta with
13102             * 'wheel' event, making spin speed determination impossible.
13103             */
13104            s.mousewheel.event = (navigator.userAgent.indexOf('firefox') > -1) ?
13105                'DOMMouseScroll' :
13106                isEventSupported() ?
13107                    'wheel' : 'mousewheel';
13108        }
13109        function handleMousewheel(e) {
13110            if (e.originalEvent) e = e.originalEvent; //jquery fix
13111            var delta = 0;
13112            var rtlFactor = s.rtl ? -1 : 1;
13113        
13114            var data = normalizeWheel( e );
13115        
13116            if (s.params.mousewheelForceToAxis) {
13117                if (s.isHorizontal()) {
13118                    if (Math.abs(data.pixelX) > Math.abs(data.pixelY)) delta = data.pixelX * rtlFactor;
13119                    else return;
13120                }
13121                else {
13122                    if (Math.abs(data.pixelY) > Math.abs(data.pixelX)) delta = data.pixelY;
13123                    else return;
13124                }
13125            }
13126            else {
13127                delta = Math.abs(data.pixelX) > Math.abs(data.pixelY) ? - data.pixelX * rtlFactor : - data.pixelY;
13128            }
13129        
13130            if (delta === 0) return;
13131        
13132            if (s.params.mousewheelInvert) delta = -delta;
13133        
13134            if (!s.params.freeMode) {
13135                if ((new window.Date()).getTime() - s.mousewheel.lastScrollTime > 60) {
13136                    if (delta < 0) {
13137                        if ((!s.isEnd || s.params.loop) && !s.animating) {
13138                            s.slideNext();
13139                            s.emit('onScroll', s, e);
13140                        }
13141                        else if (s.params.mousewheelReleaseOnEdges) return true;
13142                    }
13143                    else {
13144                        if ((!s.isBeginning || s.params.loop) && !s.animating) {
13145                            s.slidePrev();
13146                            s.emit('onScroll', s, e);
13147                        }
13148                        else if (s.params.mousewheelReleaseOnEdges) return true;
13149                    }
13150                }
13151                s.mousewheel.lastScrollTime = (new window.Date()).getTime();
13152        
13153            }
13154            else {
13155                //Freemode or scrollContainer:
13156                var position = s.getWrapperTranslate() + delta * s.params.mousewheelSensitivity;
13157                var wasBeginning = s.isBeginning,
13158                    wasEnd = s.isEnd;
13159        
13160                if (position >= s.minTranslate()) position = s.minTranslate();
13161                if (position <= s.maxTranslate()) position = s.maxTranslate();
13162        
13163                s.setWrapperTransition(0);
13164                s.setWrapperTranslate(position);
13165                s.updateProgress();
13166                s.updateActiveIndex();
13167        
13168                if (!wasBeginning && s.isBeginning || !wasEnd && s.isEnd) {
13169                    s.updateClasses();
13170                }
13171        
13172                if (s.params.freeModeSticky) {
13173                    clearTimeout(s.mousewheel.timeout);
13174                    s.mousewheel.timeout = setTimeout(function () {
13175                        s.slideReset();
13176                    }, 300);
13177                }
13178                else {
13179                    if (s.params.lazyLoading && s.lazy) {
13180                        s.lazy.load();
13181                    }
13182                }
13183                // Emit event
13184                s.emit('onScroll', s, e);
13185        
13186                // Stop autoplay
13187                if (s.params.autoplay && s.params.autoplayDisableOnInteraction) s.stopAutoplay();
13188        
13189                // Return page scroll on edge positions
13190                if (position === 0 || position === s.maxTranslate()) return;
13191            }
13192        
13193            if (e.preventDefault) e.preventDefault();
13194            else e.returnValue = false;
13195            return false;
13196        }
13197        s.disableMousewheelControl = function () {
13198            if (!s.mousewheel.event) return false;
13199            var target = s.container;
13200            if (s.params.mousewheelEventsTarged !== 'container') {
13201                target = $(s.params.mousewheelEventsTarged);
13202            }
13203            target.off(s.mousewheel.event, handleMousewheel);
13204            s.params.mousewheelControl = false;
13205            return true;
13206        };
13207        
13208        s.enableMousewheelControl = function () {
13209            if (!s.mousewheel.event) return false;
13210            var target = s.container;
13211            if (s.params.mousewheelEventsTarged !== 'container') {
13212                target = $(s.params.mousewheelEventsTarged);
13213            }
13214            target.on(s.mousewheel.event, handleMousewheel);
13215            s.params.mousewheelControl = true;
13216            return true;
13217        };
13218        
13219
13220        /*=========================
13221          Parallax
13222          ===========================*/
13223        function setParallaxTransform(el, progress) {
13224            el = $(el);
13225            var p, pX, pY;
13226            var rtlFactor = s.rtl ? -1 : 1;
13227        
13228            p = el.attr('data-swiper-parallax') || '0';
13229            pX = el.attr('data-swiper-parallax-x');
13230            pY = el.attr('data-swiper-parallax-y');
13231            if (pX || pY) {
13232                pX = pX || '0';
13233                pY = pY || '0';
13234            }
13235            else {
13236                if (s.isHorizontal()) {
13237                    pX = p;
13238                    pY = '0';
13239                }
13240                else {
13241                    pY = p;
13242                    pX = '0';
13243                }
13244            }
13245        
13246            if ((pX).indexOf('%') >= 0) {
13247                pX = parseInt(pX, 10) * progress * rtlFactor + '%';
13248            }
13249            else {
13250                pX = pX * progress * rtlFactor + 'px' ;
13251            }
13252            if ((pY).indexOf('%') >= 0) {
13253                pY = parseInt(pY, 10) * progress + '%';
13254            }
13255            else {
13256                pY = pY * progress + 'px' ;
13257            }
13258        
13259            el.transform('translate3d(' + pX + ', ' + pY + ',0px)');
13260        }
13261        s.parallax = {
13262            setTranslate: function () {
13263                s.container.children('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function(){
13264                    setParallaxTransform(this, s.progress);
13265        
13266                });
13267                s.slides.each(function () {
13268                    var slide = $(this);
13269                    slide.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function () {
13270                        var progress = Math.min(Math.max(slide[0].progress, -1), 1);
13271                        setParallaxTransform(this, progress);
13272                    });
13273                });
13274            },
13275            setTransition: function (duration) {
13276                if (typeof duration === 'undefined') duration = s.params.speed;
13277                s.container.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]').each(function(){
13278                    var el = $(this);
13279                    var parallaxDuration = parseInt(el.attr('data-swiper-parallax-duration'), 10) || duration;
13280                    if (duration === 0) parallaxDuration = 0;
13281                    el.transition(parallaxDuration);
13282                });
13283            }
13284        };
13285        
13286
13287        /*=========================
13288          Zoom
13289          ===========================*/
13290        s.zoom = {
13291            // "Global" Props
13292            scale: 1,
13293            currentScale: 1,
13294            isScaling: false,
13295            gesture: {
13296                slide: undefined,
13297                slideWidth: undefined,
13298                slideHeight: undefined,
13299                image: undefined,
13300                imageWrap: undefined,
13301                zoomMax: s.params.zoomMax
13302            },
13303            image: {
13304                isTouched: undefined,
13305                isMoved: undefined,
13306                currentX: undefined,
13307                currentY: undefined,
13308                minX: undefined,
13309                minY: undefined,
13310                maxX: undefined,
13311                maxY: undefined,
13312                width: undefined,
13313                height: undefined,
13314                startX: undefined,
13315                startY: undefined,
13316                touchesStart: {},
13317                touchesCurrent: {}
13318            },
13319            velocity: {
13320                x: undefined,
13321                y: undefined,
13322                prevPositionX: undefined,
13323                prevPositionY: undefined,
13324                prevTime: undefined
13325            },
13326            // Calc Scale From Multi-touches
13327            getDistanceBetweenTouches: function (e) {
13328                if (e.targetTouches.length < 2) return 1;
13329                var x1 = e.targetTouches[0].pageX,
13330                    y1 = e.targetTouches[0].pageY,
13331                    x2 = e.targetTouches[1].pageX,
13332                    y2 = e.targetTouches[1].pageY;
13333                var distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
13334                return distance;
13335            },
13336            // Events
13337            onGestureStart: function (e) {
13338                var z = s.zoom;
13339                if (!s.support.gestures) {
13340                    if (e.type !== 'touchstart' || e.type === 'touchstart' && e.targetTouches.length < 2) {
13341                        return;
13342                    }
13343                    z.gesture.scaleStart = z.getDistanceBetweenTouches(e);
13344                }
13345                if (!z.gesture.slide || !z.gesture.slide.length) {
13346                    z.gesture.slide = $(this);
13347                    if (z.gesture.slide.length === 0) z.gesture.slide = s.slides.eq(s.activeIndex);
13348                    z.gesture.image = z.gesture.slide.find('img, svg, canvas');
13349                    z.gesture.imageWrap = z.gesture.image.parent('.' + s.params.zoomContainerClass);
13350                    z.gesture.zoomMax = z.gesture.imageWrap.attr('data-swiper-zoom') || s.params.zoomMax ;
13351                    if (z.gesture.imageWrap.length === 0) {
13352                        z.gesture.image = undefined;
13353                        return;
13354                    }
13355                }
13356                z.gesture.image.transition(0);
13357                z.isScaling = true;
13358            },
13359            onGestureChange: function (e) {
13360                var z = s.zoom;
13361                if (!s.support.gestures) {
13362                    if (e.type !== 'touchmove' || e.type === 'touchmove' && e.targetTouches.length < 2) {
13363                        return;
13364                    }
13365                    z.gesture.scaleMove = z.getDistanceBetweenTouches(e);
13366                }
13367                if (!z.gesture.image || z.gesture.image.length === 0) return;
13368                if (s.support.gestures) {
13369                    z.scale = e.scale * z.currentScale;
13370                }
13371                else {
13372                    z.scale = (z.gesture.scaleMove / z.gesture.scaleStart) * z.currentScale;
13373                }
13374                if (z.scale > z.gesture.zoomMax) {
13375                    z.scale = z.gesture.zoomMax - 1 + Math.pow((z.scale - z.gesture.zoomMax + 1), 0.5);
13376                }
13377                if (z.scale < s.params.zoomMin) {
13378                    z.scale =  s.params.zoomMin + 1 - Math.pow((s.params.zoomMin - z.scale + 1), 0.5);
13379                }
13380                z.gesture.image.transform('translate3d(0,0,0) scale(' + z.scale + ')');
13381            },
13382            onGestureEnd: function (e) {
13383                var z = s.zoom;
13384                if (!s.support.gestures) {
13385                    if (e.type !== 'touchend' || e.type === 'touchend' && e.changedTouches.length < 2) {
13386                        return;
13387                    }
13388                }
13389                if (!z.gesture.image || z.gesture.image.length === 0) return;
13390                z.scale = Math.max(Math.min(z.scale, z.gesture.zoomMax), s.params.zoomMin);
13391                z.gesture.image.transition(s.params.speed).transform('translate3d(0,0,0) scale(' + z.scale + ')');
13392                z.currentScale = z.scale;
13393                z.isScaling = false;
13394                if (z.scale === 1) z.gesture.slide = undefined;
13395            },
13396            onTouchStart: function (s, e) {
13397                var z = s.zoom;
13398                if (!z.gesture.image || z.gesture.image.length === 0) return;
13399                if (z.image.isTouched) return;
13400                if (s.device.os === 'android') e.preventDefault();
13401                z.image.isTouched = true;
13402                z.image.touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
13403                z.image.touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
13404            },
13405            onTouchMove: function (e) {
13406                var z = s.zoom;
13407                if (!z.gesture.image || z.gesture.image.length === 0) return;
13408                s.allowClick = false;
13409                if (!z.image.isTouched || !z.gesture.slide) return;
13410        
13411                if (!z.image.isMoved) {
13412                    z.image.width = z.gesture.image[0].offsetWidth;
13413                    z.image.height = z.gesture.image[0].offsetHeight;
13414                    z.image.startX = s.getTranslate(z.gesture.imageWrap[0], 'x') || 0;
13415                    z.image.startY = s.getTranslate(z.gesture.imageWrap[0], 'y') || 0;
13416                    z.gesture.slideWidth = z.gesture.slide[0].offsetWidth;
13417                    z.gesture.slideHeight = z.gesture.slide[0].offsetHeight;
13418                    z.gesture.imageWrap.transition(0);
13419                    if (s.rtl) z.image.startX = -z.image.startX;
13420                    if (s.rtl) z.image.startY = -z.image.startY;
13421                }
13422                // Define if we need image drag
13423                var scaledWidth = z.image.width * z.scale;
13424                var scaledHeight = z.image.height * z.scale;
13425        
13426                if (scaledWidth < z.gesture.slideWidth && scaledHeight < z.gesture.slideHeight) return;
13427        
13428                z.image.minX = Math.min((z.gesture.slideWidth / 2 - scaledWidth / 2), 0);
13429                z.image.maxX = -z.image.minX;
13430                z.image.minY = Math.min((z.gesture.slideHeight / 2 - scaledHeight / 2), 0);
13431                z.image.maxY = -z.image.minY;
13432        
13433                z.image.touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
13434                z.image.touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
13435        
13436                if (!z.image.isMoved && !z.isScaling) {
13437                    if (s.isHorizontal() &&
13438                        (Math.floor(z.image.minX) === Math.floor(z.image.startX) && z.image.touchesCurrent.x < z.image.touchesStart.x) ||
13439                        (Math.floor(z.image.maxX) === Math.floor(z.image.startX) && z.image.touchesCurrent.x > z.image.touchesStart.x)
13440                        ) {
13441                        z.image.isTouched = false;
13442                        return;
13443                    }
13444                    else if (!s.isHorizontal() &&
13445                        (Math.floor(z.image.minY) === Math.floor(z.image.startY) && z.image.touchesCurrent.y < z.image.touchesStart.y) ||
13446                        (Math.floor(z.image.maxY) === Math.floor(z.image.startY) && z.image.touchesCurrent.y > z.image.touchesStart.y)
13447                        ) {
13448                        z.image.isTouched = false;
13449                        return;
13450                    }
13451                }
13452                e.preventDefault();
13453                e.stopPropagation();
13454        
13455                z.image.isMoved = true;
13456                z.image.currentX = z.image.touchesCurrent.x - z.image.touchesStart.x + z.image.startX;
13457                z.image.currentY = z.image.touchesCurrent.y - z.image.touchesStart.y + z.image.startY;
13458        
13459                if (z.image.currentX < z.image.minX) {
13460                    z.image.currentX =  z.image.minX + 1 - Math.pow((z.image.minX - z.image.currentX + 1), 0.8);
13461                }
13462                if (z.image.currentX > z.image.maxX) {
13463                    z.image.currentX = z.image.maxX - 1 + Math.pow((z.image.currentX - z.image.maxX + 1), 0.8);
13464                }
13465        
13466                if (z.image.currentY < z.image.minY) {
13467                    z.image.currentY =  z.image.minY + 1 - Math.pow((z.image.minY - z.image.currentY + 1), 0.8);
13468                }
13469                if (z.image.currentY > z.image.maxY) {
13470                    z.image.currentY = z.image.maxY - 1 + Math.pow((z.image.currentY - z.image.maxY + 1), 0.8);
13471                }
13472        
13473                //Velocity
13474                if (!z.velocity.prevPositionX) z.velocity.prevPositionX = z.image.touchesCurrent.x;
13475                if (!z.velocity.prevPositionY) z.velocity.prevPositionY = z.image.touchesCurrent.y;
13476                if (!z.velocity.prevTime) z.velocity.prevTime = Date.now();
13477                z.velocity.x = (z.image.touchesCurrent.x - z.velocity.prevPositionX) / (Date.now() - z.velocity.prevTime) / 2;
13478                z.velocity.y = (z.image.touchesCurrent.y - z.velocity.prevPositionY) / (Date.now() - z.velocity.prevTime) / 2;
13479                if (Math.abs(z.image.touchesCurrent.x - z.velocity.prevPositionX) < 2) z.velocity.x = 0;
13480                if (Math.abs(z.image.touchesCurrent.y - z.velocity.prevPositionY) < 2) z.velocity.y = 0;
13481                z.velocity.prevPositionX = z.image.touchesCurrent.x;
13482                z.velocity.prevPositionY = z.image.touchesCurrent.y;
13483                z.velocity.prevTime = Date.now();
13484        
13485                z.gesture.imageWrap.transform('translate3d(' + z.image.currentX + 'px, ' + z.image.currentY + 'px,0)');
13486            },
13487            onTouchEnd: function (s, e) {
13488                var z = s.zoom;
13489                if (!z.gesture.image || z.gesture.image.length === 0) return;
13490                if (!z.image.isTouched || !z.image.isMoved) {
13491                    z.image.isTouched = false;
13492                    z.image.isMoved = false;
13493                    return;
13494                }
13495                z.image.isTouched = false;
13496                z.image.isMoved = false;
13497                var momentumDurationX = 300;
13498                var momentumDurationY = 300;
13499                var momentumDistanceX = z.velocity.x * momentumDurationX;
13500                var newPositionX = z.image.currentX + momentumDistanceX;
13501                var momentumDistanceY = z.velocity.y * momentumDurationY;
13502                var newPositionY = z.image.currentY + momentumDistanceY;
13503        
13504                //Fix duration
13505                if (z.velocity.x !== 0) momentumDurationX = Math.abs((newPositionX - z.image.currentX) / z.velocity.x);
13506                if (z.velocity.y !== 0) momentumDurationY = Math.abs((newPositionY - z.image.currentY) / z.velocity.y);
13507                var momentumDuration = Math.max(momentumDurationX, momentumDurationY);
13508        
13509                z.image.currentX = newPositionX;
13510                z.image.currentY = newPositionY;
13511        
13512                // Define if we need image drag
13513                var scaledWidth = z.image.width * z.scale;
13514                var scaledHeight = z.image.height * z.scale;
13515                z.image.minX = Math.min((z.gesture.slideWidth / 2 - scaledWidth / 2), 0);
13516                z.image.maxX = -z.image.minX;
13517                z.image.minY = Math.min((z.gesture.slideHeight / 2 - scaledHeight / 2), 0);
13518                z.image.maxY = -z.image.minY;
13519                z.image.currentX = Math.max(Math.min(z.image.currentX, z.image.maxX), z.image.minX);
13520                z.image.currentY = Math.max(Math.min(z.image.currentY, z.image.maxY), z.image.minY);
13521        
13522                z.gesture.imageWrap.transition(momentumDuration).transform('translate3d(' + z.image.currentX + 'px, ' + z.image.currentY + 'px,0)');
13523            },
13524            onTransitionEnd: function (s) {
13525                var z = s.zoom;
13526                if (z.gesture.slide && s.previousIndex !== s.activeIndex) {
13527                    z.gesture.image.transform('translate3d(0,0,0) scale(1)');
13528                    z.gesture.imageWrap.transform('translate3d(0,0,0)');
13529                    z.gesture.slide = z.gesture.image = z.gesture.imageWrap = undefined;
13530                    z.scale = z.currentScale = 1;
13531                }
13532            },
13533            // Toggle Zoom
13534            toggleZoom: function (s, e) {
13535                var z = s.zoom;
13536                if (!z.gesture.slide) {
13537                    z.gesture.slide = s.clickedSlide ? $(s.clickedSlide) : s.slides.eq(s.activeIndex);
13538                    z.gesture.image = z.gesture.slide.find('img, svg, canvas');
13539                    z.gesture.imageWrap = z.gesture.image.parent('.' + s.params.zoomContainerClass);
13540                }
13541                if (!z.gesture.image || z.gesture.image.length === 0) return;
13542        
13543                var touchX, touchY, offsetX, offsetY, diffX, diffY, translateX, translateY, imageWidth, imageHeight, scaledWidth, scaledHeight, translateMinX, translateMinY, translateMaxX, translateMaxY, slideWidth, slideHeight;
13544        
13545                if (typeof z.image.touchesStart.x === 'undefined' && e) {
13546                    touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX;
13547                    touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY;
13548                }
13549                else {
13550                    touchX = z.image.touchesStart.x;
13551                    touchY = z.image.touchesStart.y;
13552                }
13553        
13554                if (z.scale && z.scale !== 1) {
13555                    // Zoom Out
13556                    z.scale = z.currentScale = 1;
13557                    z.gesture.imageWrap.transition(300).transform('translate3d(0,0,0)');
13558                    z.gesture.image.transition(300).transform('translate3d(0,0,0) scale(1)');
13559                    z.gesture.slide = undefined;
13560                }
13561                else {
13562                    // Zoom In
13563                    z.scale = z.currentScale = z.gesture.imageWrap.attr('data-swiper-zoom') || s.params.zoomMax;
13564                    if (e) {
13565                        slideWidth = z.gesture.slide[0].offsetWidth;
13566                        slideHeight = z.gesture.slide[0].offsetHeight;
13567                        offsetX = z.gesture.slide.offset().left;
13568                        offsetY = z.gesture.slide.offset().top;
13569                        diffX = offsetX + slideWidth/2 - touchX;
13570                        diffY = offsetY + slideHeight/2 - touchY;
13571        
13572                        imageWidth = z.gesture.image[0].offsetWidth;
13573                        imageHeight = z.gesture.image[0].offsetHeight;
13574                        scaledWidth = imageWidth * z.scale;
13575                        scaledHeight = imageHeight * z.scale;
13576        
13577                        translateMinX = Math.min((slideWidth / 2 - scaledWidth / 2), 0);
13578                        translateMinY = Math.min((slideHeight / 2 - scaledHeight / 2), 0);
13579                        translateMaxX = -translateMinX;
13580                        translateMaxY = -translateMinY;
13581        
13582                        translateX = diffX * z.scale;
13583                        translateY = diffY * z.scale;
13584        
13585                        if (translateX < translateMinX) {
13586                            translateX =  translateMinX;
13587                        }
13588                        if (translateX > translateMaxX) {
13589                            translateX = translateMaxX;
13590                        }
13591        
13592                        if (translateY < translateMinY) {
13593                            translateY =  translateMinY;
13594                        }
13595                        if (translateY > translateMaxY) {
13596                            translateY = translateMaxY;
13597                        }
13598                    }
13599                    else {
13600                        translateX = 0;
13601                        translateY = 0;
13602                    }
13603                    z.gesture.imageWrap.transition(300).transform('translate3d(' + translateX + 'px, ' + translateY + 'px,0)');
13604                    z.gesture.image.transition(300).transform('translate3d(0,
136040,0) scale(' + z.scale + ')');
13605                }
13606            },
13607            // Attach/Detach Events
13608            attachEvents: function (detach) {
13609                var action = detach ? 'off' : 'on';
13610        
13611                if (s.params.zoom) {
13612                    var target = s.slides;
13613                    var passiveListener = s.touchEvents.start === 'touchstart' && s.support.passiveListener && s.params.passiveListeners ? {passive: true, capture: false} : false;
13614                    // Scale image
13615                    if (s.support.gestures) {
13616                        s.slides[action]('gesturestart', s.zoom.onGestureStart, passiveListener);
13617                        s.slides[action]('gesturechange', s.zoom.onGestureChange, passiveListener);
13618                        s.slides[action]('gestureend', s.zoom.onGestureEnd, passiveListener);
13619                    }
13620                    else if (s.touchEvents.start === 'touchstart') {
13621                        s.slides[action](s.touchEvents.start, s.zoom.onGestureStart, passiveListener);
13622                        s.slides[action](s.touchEvents.move, s.zoom.onGestureChange, passiveListener);
13623                        s.slides[action](s.touchEvents.end, s.zoom.onGestureEnd, passiveListener);
13624                    }
13625        
13626                    // Move image
13627                    s[action]('touchStart', s.zoom.onTouchStart);
13628                    s.slides.each(function (index, slide){
13629                        if ($(slide).find('.' + s.params.zoomContainerClass).length > 0) {
13630                            $(slide)[action](s.touchEvents.move, s.zoom.onTouchMove);
13631                        }
13632                    });
13633                    s[action]('touchEnd', s.zoom.onTouchEnd);
13634        
13635                    // Scale Out
13636                    s[action]('transitionEnd', s.zoom.onTransitionEnd);
13637                    if (s.params.zoomToggle) {
13638                        s.on('doubleTap', s.zoom.toggleZoom);
13639                    }
13640                }
13641            },
13642            init: function () {
13643                s.zoom.attachEvents();
13644            },
13645            destroy: function () {
13646                s.zoom.attachEvents(true);
13647            }
13648        };
13649        
13650
13651        /*=========================
13652          Plugins API. Collect all and init all plugins
13653          ===========================*/
13654        s._plugins = [];
13655        for (var plugin in s.plugins) {
13656            var p = s.plugins[plugin](s, s.params[plugin]);
13657            if (p) s._plugins.push(p);
13658        }
13659        // Method to call all plugins event/method
13660        s.callPlugins = function (eventName) {
13661            for (var i = 0; i < s._plugins.length; i++) {
13662                if (eventName in s._plugins[i]) {
13663                    s._plugins[i][eventName](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
13664                }
13665            }
13666        };
13667        
13668
13669        /*=========================
13670          Events/Callbacks/Plugins Emitter
13671          ===========================*/
13672        function normalizeEventName (eventName) {
13673            if (eventName.indexOf('on') !== 0) {
13674                if (eventName[0] !== eventName[0].toUpperCase()) {
13675                    eventName = 'on' + eventName[0].toUpperCase() + eventName.substring(1);
13676                }
13677                else {
13678                    eventName = 'on' + eventName;
13679                }
13680            }
13681            return eventName;
13682        }
13683        s.emitterEventListeners = {
13684        
13685        };
13686        s.emit = function (eventName) {
13687            // Trigger callbacks
13688            if (s.params[eventName]) {
13689                s.params[eventName](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
13690            }
13691            var i;
13692            // Trigger events
13693            if (s.emitterEventListeners[eventName]) {
13694                for (i = 0; i < s.emitterEventListeners[eventName].length; i++) {
13695                    s.emitterEventListeners[eventName][i](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
13696                }
13697            }
13698            // Trigger plugins
13699            if (s.callPlugins) s.callPlugins(eventName, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
13700        };
13701        s.on = function (eventName, handler) {
13702            eventName = normalizeEventName(eventName);
13703            if (!s.emitterEventListeners[eventName]) s.emitterEventListeners[eventName] = [];
13704            s.emitterEventListeners[eventName].push(handler);
13705            return s;
13706        };
13707        s.off = function (eventName, handler) {
13708            var i;
13709            eventName = normalizeEventName(eventName);
13710            if (typeof handler === 'undefined') {
13711                // Remove all handlers for such event
13712                s.emitterEventListeners[eventName] = [];
13713                return s;
13714            }
13715            if (!s.emitterEventListeners[eventName] || s.emitterEventListeners[eventName].length === 0) return;
13716            for (i = 0; i < s.emitterEventListeners[eventName].length; i++) {
13717                if(s.emitterEventListeners[eventName][i] === handler) s.emitterEventListeners[eventName].splice(i, 1);
13718            }
13719            return s;
13720        };
13721        s.once = function (eventName, handler) {
13722            eventName = normalizeEventName(eventName);
13723            var _handler = function () {
13724                handler(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
13725                s.off(eventName, _handler);
13726            };
13727            s.on(eventName, _handler);
13728            return s;
13729        };
13730        
13731
13732        // Accessibility tools
13733        s.a11y = {
13734            makeFocusable: function ($el) {
13735                $el.attr('tabIndex', '0');
13736                return $el;
13737            },
13738            addRole: function ($el, role) {
13739                $el.attr('role', role);
13740                return $el;
13741            },
13742        
13743            addLabel: function ($el, label) {
13744                $el.attr('aria-label', label);
13745                return $el;
13746            },
13747        
13748            disable: function ($el) {
13749                $el.attr('aria-disabled', true);
13750                return $el;
13751            },
13752        
13753            enable: function ($el) {
13754                $el.attr('aria-disabled', false);
13755                return $el;
13756            },
13757        
13758            onEnterKey: function (event) {
13759                if (event.keyCode !== 13) return;
13760                if ($(event.target).is(s.params.nextButton)) {
13761                    s.onClickNext(event);
13762                    if (s.isEnd) {
13763                        s.a11y.notify(s.params.lastSlideMessage);
13764                    }
13765                    else {
13766                        s.a11y.notify(s.params.nextSlideMessage);
13767                    }
13768                }
13769                else if ($(event.target).is(s.params.prevButton)) {
13770                    s.onClickPrev(event);
13771                    if (s.isBeginning) {
13772                        s.a11y.notify(s.params.firstSlideMessage);
13773                    }
13774                    else {
13775                        s.a11y.notify(s.params.prevSlideMessage);
13776                    }
13777                }
13778                if ($(event.target).is('.' + s.params.bulletClass)) {
13779                    $(event.target)[0].click();
13780                }
13781            },
13782        
13783            liveRegion: $('<span class="' + s.params.notificationClass + '" aria-live="assertive" aria-atomic="true"></span>'),
13784        
13785            notify: function (message) {
13786                var notification = s.a11y.liveRegion;
13787                if (notification.length === 0) return;
13788                notification.html('');
13789                notification.html(message);
13790            },
13791            init: function () {
13792                // Setup accessibility
13793                if (s.params.nextButton && s.nextButton && s.nextButton.length > 0) {
13794                    s.a11y.makeFocusable(s.nextButton);
13795                    s.a11y.addRole(s.nextButton, 'button');
13796                    s.a11y.addLabel(s.nextButton, s.params.nextSlideMessage);
13797                }
13798                if (s.params.prevButton && s.prevButton && s.prevButton.length > 0) {
13799                    s.a11y.makeFocusable(s.prevButton);
13800                    s.a11y.addRole(s.prevButton, 'button');
13801                    s.a11y.addLabel(s.prevButton, s.params.prevSlideMessage);
13802                }
13803        
13804                $(s.container).append(s.a11y.liveRegion);
13805            },
13806            initPagination: function () {
13807                if (s.params.pagination && s.params.paginationClickable && s.bullets && s.bullets.length) {
13808                    s.bullets.each(function () {
13809                        var bullet = $(this);
13810                        s.a11y.makeFocusable(bullet);
13811                        s.a11y.addRole(bullet, 'button');
13812                        s.a11y.addLabel(bullet, s.params.paginationBulletMessage.replace(/{{index}}/, bullet.index() + 1));
13813                    });
13814                }
13815            },
13816            destroy: function () {
13817                if (s.a11y.liveRegion && s.a11y.liveRegion.length > 0) s.a11y.liveRegion.remove();
13818            }
13819        };
13820        
13821
13822        /*=========================
13823          Init/Destroy
13824          ===========================*/
13825        s.init = function () {
13826            if (s.params.loop) s.createLoop();
13827            s.updateContainerSize();
13828            s.updateSlidesSize();
13829            s.updatePagination();
13830            if (s.params.scrollbar && s.scrollbar) {
13831                s.scrollbar.set();
13832                if (s.params.scrollbarDraggable) {
13833                    s.scrollbar.enableDraggable();
13834                }
13835            }
13836            if (s.params.effect !== 'slide' && s.effects[s.params.effect]) {
13837                if (!s.params.loop) s.updateProgress();
13838                s.effects[s.params.effect].setTranslate();
13839            }
13840            if (s.params.loop) {
13841                s.slideTo(s.params.initialSlide + s.loopedSlides, 0, s.params.runCallbacksOnInit);
13842            }
13843            else {
13844                s.slideTo(s.params.initialSlide, 0, s.params.runCallbacksOnInit);
13845                if (s.params.initialSlide === 0) {
13846                    if (s.parallax && s.params.parallax) s.parallax.setTranslate();
13847                    if (s.lazy && s.params.lazyLoading) {
13848                        s.lazy.load();
13849                        s.lazy.initialImageLoaded = true;
13850                    }
13851                }
13852            }
13853            s.attachEvents();
13854            if (s.params.observer && s.support.observer) {
13855                s.initObservers();
13856            }
13857            if (s.params.preloadImages && !s.params.lazyLoading) {
13858                s.preloadImages();
13859            }
13860            if (s.params.zoom && s.zoom) {
13861                s.zoom.init();
13862            }
13863            if (s.params.autoplay) {
13864                s.startAutoplay();
13865            }
13866            if (s.params.keyboardControl) {
13867                if (s.enableKeyboardControl) s.enableKeyboardControl();
13868            }
13869            if (s.params.mousewheelControl) {
13870                if (s.enableMousewheelControl) s.enableMousewheelControl();
13871            }
13872            // Deprecated hashnavReplaceState changed to replaceState for use in hashnav and history
13873            if (s.params.hashnavReplaceState) {
13874                s.params.replaceState = s.params.hashnavReplaceState;
13875            }
13876            if (s.params.history) {
13877                if (s.history) s.history.init();
13878            }
13879            if (s.params.hashnav) {
13880                if (s.hashnav) s.hashnav.init();
13881            }
13882            if (s.params.a11y && s.a11y) s.a11y.init();
13883            s.emit('onInit', s);
13884        };
13885        
13886        // Cleanup dynamic styles
13887        s.cleanupStyles = function () {
13888            // Container
13889            s.container.removeClass(s.classNames.join(' ')).removeAttr('style');
13890        
13891            // Wrapper
13892            s.wrapper.removeAttr('style');
13893        
13894            // Slides
13895            if (s.slides && s.slides.length) {
13896                s.slides
13897                    .removeClass([
13898                      s.params.slideVisibleClass,
13899                      s.params.slideActiveClass,
13900                      s.params.slideNextClass,
13901                      s.params.slidePrevClass
13902                    ].join(' '))
13903                    .removeAttr('style')
13904                    .removeAttr('data-swiper-column')
13905                    .removeAttr('data-swiper-row');
13906            }
13907        
13908            // Pagination/Bullets
13909            if (s.paginationContainer && s.paginationContainer.length) {
13910                s.paginationContainer.removeClass(s.params.paginationHiddenClass);
13911            }
13912            if (s.bullets && s.bullets.length) {
13913                s.bullets.removeClass(s.params.bulletActiveClass);
13914            }
13915        
13916            // Buttons
13917            if (s.params.prevButton) $(s.params.prevButton).removeClass(s.params.buttonDisabledClass);
13918            if (s.params.nextButton) $(s.params.nextButton).removeClass(s.params.buttonDisabledClass);
13919        
13920            // Scrollbar
13921            if (s.params.scrollbar && s.scrollbar) {
13922                if (s.scrollbar.track && s.scrollbar.track.length) s.scrollbar.track.removeAttr('style');
13923                if (s.scrollbar.drag && s.scrollbar.drag.length) s.scrollbar.drag.removeAttr('style');
13924            }
13925        };
13926        
13927        // Destroy
13928        s.destroy = function (deleteInstance, cleanupStyles) {
13929            // Detach evebts
13930            s.detachEvents();
13931            // Stop autoplay
13932            s.stopAutoplay();
13933            // Disable draggable
13934            if (s.params.scrollbar && s.scrollbar) {
13935                if (s.params.scrollbarDraggable) {
13936                    s.scrollbar.disableDraggable();
13937                }
13938            }
13939            // Destroy loop
13940            if (s.params.loop) {
13941                s.destroyLoop();
13942            }
13943            // Cleanup styles
13944            if (cleanupStyles) {
13945                s.cleanupStyles();
13946            }
13947            // Disconnect observer
13948            s.disconnectObservers();
13949        
13950            // Destroy zoom
13951            if (s.params.zoom && s.zoom) {
13952                s.zoom.destroy();
13953            }
13954            // Disable keyboard/mousewheel
13955            if (s.params.keyboardControl) {
13956                if (s.disableKeyboardControl) s.disableKeyboardControl();
13957            }
13958            if (s.params.mousewheelControl) {
13959                if (s.disableMousewheelControl) s.disableMousewheelControl();
13960            }
13961            // Disable a11y
13962            if (s.params.a11y && s.a11y) s.a11y.destroy();
13963            // Delete history popstate
13964            if (s.params.history && !s.params.replaceState) {
13965                window.removeEventListener('popstate', s.history.setHistoryPopState);
13966            }
13967            if (s.params.hashnav && s.hashnav)  {
13968                s.hashnav.destroy();
13969            }
13970            // Destroy callback
13971            s.emit('onDestroy');
13972            // Delete instance
13973            if (deleteInstance !== false) s = null;
13974        };
13975        
13976        s.init();
13977        
13978
13979    
13980        // Return swiper instance
13981        return s;
13982    };
13983    
13984
13985    /*==================================================
13986        Prototype
13987    ====================================================*/
13988    Swiper.prototype = {
13989        isSafari: (function () {
13990            var ua = window.navigator.userAgent.toLowerCase();
13991            return (ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0 && ua.indexOf('android') < 0);
13992        })(),
13993        isUiWebView: /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(window.navigator.userAgent),
13994        isArray: function (arr) {
13995            return Object.prototype.toString.apply(arr) === '[object Array]';
13996        },
13997        /*==================================================
13998        Browser
13999        ====================================================*/
14000        browser: {
14001            ie: window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
14002            ieTouch: (window.navigator.msPointerEnabled && window.navigator.msMaxTouchPoints > 1) || (window.navigator.pointerEnabled && window.navigator.maxTouchPoints > 1),
14003            lteIE9: (function() {
14004                // create temporary DIV
14005                var div = document.createElement('div');
14006                // add content to tmp DIV which is wrapped into the IE HTML conditional statement
14007                div.innerHTML = '<!--[if lte IE 9]><i></i><![endif]-->';
14008                // return true / false value based on what will browser render
14009                return div.getElementsByTagName('i').length === 1;
14010            })()
14011        },
14012        /*==================================================
14013        Devices
14014        ====================================================*/
14015        device: (function () {
14016            var ua = window.navigator.userAgent;
14017            var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
14018            var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
14019            var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
14020            var iphone = !ipad && ua.match(/(iPhone\sOS|iOS)\s([\d_]+)/);
14021            return {
14022                ios: ipad || iphone || ipod,
14023                android: android
14024            };
14025        })(),
14026        /*==================================================
14027        Feature Detection
14028        ====================================================*/
14029        support: {
14030            touch : (window.Modernizr && Modernizr.touch === true) || (function () {
14031                return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);
14032            })(),
14033    
14034            transforms3d : (window.Modernizr && Modernizr.csstransforms3d === true) || (function () {
14035                var div = document.createElement('div').style;
14036                return ('webkitPerspective' in div || 'MozPerspective' in div || 'OPerspective' in div || 'MsPerspective' in div || 'perspective' in div);
14037            })(),
14038    
14039            flexbox: (function () {
14040                var div = document.createElement('div').style;
14041                var styles = ('alignItems webkitAlignItems webkitBoxAlign msFlexAlign mozBoxAlign webkitFlexDirection msFlexDirection mozBoxDirection mozBoxOrient webkitBoxDirection webkitBoxOrient').split(' ');
14042                for (var i = 0; i < styles.length; i++) {
14043                    if (styles[i] in div) return true;
14044                }
14045            })(),
14046    
14047            observer: (function () {
14048                return ('MutationObserver' in window || 'WebkitMutationObserver' in window);
14049            })(),
14050    
14051            passiveListener: (function () {
14052                var supportsPassive = false;
14053                try {
14054                    var opts = Object.defineProperty({}, 'passive', {
14055                        get: function() {
14056                            supportsPassive = true;
14057                        }
14058                    });
14059                    window.addEventListener('testPassiveListener', null, opts);
14060                } catch (e) {}
14061                return supportsPassive;
14062            })(),
14063    
14064            gestures: (function () {
14065                return 'ongesturestart' in window;
14066            })()
14067        },
14068        /*==================================================
14069        Plugins
14070        ====================================================*/
14071        plugins: {}
14072    };
14073    
14074
14075    /*===========================
14076     Get Dom libraries
14077     ===========================*/
14078    var swiperDomPlugins = ['jQuery', 'Zepto', 'Dom7'];
14079    for (var i = 0; i < swiperDomPlugins.length; i++) {
14080    	if (window[swiperDomPlugins[i]]) {
14081    		addLibraryPlugin(window[swiperDomPlugins[i]]);
14082    	}
14083    }
14084    // Required DOM Plugins
14085    var domLib;
14086    if (typeof Dom7 === 'undefined') {
14087    	domLib = window.Dom7 || window.Zepto || window.jQuery;
14088    }
14089    else {
14090    	domLib = Dom7;
14091    }
14092    
14093
14094    /*===========================
14095    Add .swiper plugin from Dom libraries
14096    ===========================*/
14097    function addLibraryPlugin(lib) {
14098        lib.fn.swiper = function (params) {
14099            var firstInstance;
14100            lib(this).each(function () {
14101                var s = new Swiper(this, params);
14102                if (!firstInstance) firstInstance = s;
14103            });
14104            return firstInstance;
14105        };
14106    }
14107    
14108    if (domLib) {
14109        if (!('transitionEnd' in domLib.fn)) {
14110            domLib.fn.transitionEnd = function (callback) {
14111                var events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'],
14112                    i, j, dom = this;
14113                function fireCallBack(e) {
14114                    /*jshint validthis:true */
14115                    if (e.target !== this) return;
14116                    callback.call(this, e);
14117                    for (i = 0; i < events.length; i++) {
14118                        dom.off(events[i], fireCallBack);
14119                    }
14120                }
14121                if (callback) {
14122                    for (i = 0; i < events.length; i++) {
14123                        dom.on(events[i], fireCallBack);
14124                    }
14125                }
14126                return this;
14127            };
14128        }
14129        if (!('transform' in domLib.fn)) {
14130            domLib.fn.transform = function (transform) {
14131                for (var i = 0; i < this.length; i++) {
14132                    var elStyle = this[i].style;
14133                    elStyle.webkitTransform = elStyle.MsTransform = elStyle.msTransform = elStyle.MozTransform = elStyle.OTransform = elStyle.transform = transform;
14134                }
14135                return this;
14136            };
14137        }
14138        if (!('transition' in domLib.fn)) {
14139            domLib.fn.transition = function (duration) {
14140                if (typeof duration !== 'string') {
14141                    duration = duration + 'ms';
14142                }
14143                for (var i = 0; i < this.length; i++) {
14144                    var elStyle = this[i].style;
14145                    elStyle.webkitTransitionDuration = elStyle.MsTransitionDuration = elStyle.msTransitionDuration = elStyle.MozTransitionDuration = elStyle.OTransitionDuration = elStyle.transitionDuration = duration;
14146                }
14147                return this;
14148            };
14149        }
14150        if (!('outerWidth' in domLib.fn)) {
14151            domLib.fn.outerWidth = function (includeMargins) {
14152                if (this.length > 0) {
14153                    if (includeMargins)
14154                        return this[0].offsetWidth + parseFloat(this.css('margin-right')) + parseFloat(this.css('margin-left'));
14155                    else
14156                        return this[0].offsetWidth;
14157                }
14158                else return null;
14159            };
14160        }
14161    }
14162    
14163
14164    window.Swiper = Swiper;
14165})();
14166
14167/*===========================
14168Swiper AMD Export
14169===========================*/
14170if (typeof(module) !== 'undefined')
14171{
14172    module.exports = window.Swiper;
14173}
14174else if (typeof define === 'function' && define.amd) {
14175    define([], function () {
14176        'use strict';
14177        return window.Swiper;
14178    });
14179}
14180
14181//# sourceMappingURL=maps/swiper.jquery.js.map
14182
14183/* ------------------------------------------------------------------------
14184	Class: prettyPhoto
14185	Use: Lightbox clone for jQuery
14186	Author: Stephane Caron (http://www.no-margin-for-errors.com)
14187	Version: 3.1.6
14188------------------------------------------------------------------------- */
14189(function($) {
14190	$.prettyPhoto = {version: '3.1.6'};
14191	
14192	$.fn.prettyPhoto = function(pp_settings) {
14193		pp_settings = jQuery.extend({
14194			hook: 'rel', /* the attribute tag to use for prettyPhoto hooks. default: 'rel'. For HTML5, use "data-rel" or similar. */
14195			animation_speed: 'fast', /* fast/slow/normal */
14196			ajaxcallback: function() {},
14197			slideshow: 5000, /* false OR interval time in ms */
14198			autoplay_slideshow: false, /* true/false */
14199			opacity: 0.80, /* Value between 0 and 1 */
14200			show_title: true, /* true/false */
14201			allow_resize: true, /* Resize the photos bigger than viewport. true/false */
14202			allow_expand: true, /* Allow the user to expand a resized image. true/false */
14203			default_width: 500,
14204			default_height: 344,
14205			counter_separator_label: '/', /* The separator for the gallery counter 1 "of" 2 */
14206			theme: 'pp_default', /* light_rounded / dark_rounded / light_square / dark_square / facebook */
14207			horizontal_padding: 20, /* The padding on each side of the picture */
14208			hideflash: false, /* Hides all the flash object on a page, set to TRUE if flash appears over prettyPhoto */
14209			wmode: 'opaque', /* Set the flash wmode attribute */
14210			autoplay: true, /* Automatically start videos: True/False */
14211			modal: false, /* If set to true, only the close button will close the window */
14212			deeplinking: true, /* Allow prettyPhoto to update the url to enable deeplinking. */
14213			overlay_gallery: true, /* If set to true, a gallery will overlay the fullscreen image on mouse over */
14214			overlay_gallery_max: 30, /* Maximum number of pictures in the overlay gallery */
14215			keyboard_shortcuts: true, /* Set to false if you open forms inside prettyPhoto */
14216			changepicturecallback: function(){}, /* Called everytime an item is shown/changed */
14217			callback: function(){}, /* Called when prettyPhoto is closed */
14218			ie6_fallback: true,
14219			markup: '<div class="pp_pic_holder"> \
14220						<div class="ppt">&nbsp;</div> \
14221						<div class="pp_top"> \
14222							<div class="pp_left"></div> \
14223							<div class="pp_middle"></div> \
14224							<div class="pp_right"></div> \
14225						</div> \
14226						<div class="pp_content_container"> \
14227							<div class="pp_left"> \
14228							<div class="pp_right"> \
14229								<div class="pp_content"> \
14230									<div class="pp_loaderIcon"></div> \
14231									<div class="pp_fade"> \
14232										<a href="#" class="pp_expand" title="Expand the image">Expand</a> \
14233										<div class="pp_hoverContainer"> \
14234											<a class="pp_next" href="#">next</a> \
14235											<a class="pp_previous" href="#">previous</a> \
14236										</div> \
14237										<div id="pp_full_res"></div> \
14238										<div class="pp_details"> \
14239											<div class="pp_nav"> \
14240												<a href="#" class="pp_arrow_previous">Previous</a> \
14241												<p class="currentTextHolder">0/0</p> \
14242												<a href="#" class="pp_arrow_next">Next</a> \
14243											</div> \
14244											<p class="pp_description"></p> \
14245											<div class="pp_social">{pp_social}</div> \
14246											<a class="pp_close" href="#">Close</a> \
14247										</div> \
14248									</div> \
14249								</div> \
14250							</div> \
14251							</div> \
14252						</div> \
14253						<div class="pp_bottom"> \
14254							<div class="pp_left"></div> \
14255							<div class="pp_middle"></div> \
14256							<div class="pp_right"></div> \
14257						</div> \
14258					</div> \
14259					<div class="pp_overlay"></div>',
14260			gallery_markup: '<div class="pp_gallery"> \
14261								<a href="#" class="pp_arrow_previous">Previous</a> \
14262								<div> \
14263									<ul> \
14264										{gallery} \
14265									</ul> \
14266								</div> \
14267								<a href="#" class="pp_arrow_next">Next</a> \
14268							</div>',
14269			image_markup: '<img id="fullResImage" src="{path}" />',
14270			flash_markup: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="{width}" height="{height}"><param name="wmode" value="{wmode}" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{path}" /><embed src="{path}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="{width}" height="{height}" wmode="{wmode}"></embed></object>',
14271			quicktime_markup: '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab" height="{height}" width="{width}"><param name="src" value="{path}"><param name="autoplay" value="{autoplay}"><param name="type" value="video/quicktime"><embed src="{path}" height="{height}" width="{width}" autoplay="{autoplay}" type="video/quicktime" pluginspage="http://www.apple.com/quicktime/download/"></embed></object>',
14272			iframe_markup: '<iframe src ="{path}" width="{width}" height="{height}" frameborder="no"></iframe>',
14273			inline_markup: '<div class="pp_inline">{content}</div>',
14274			custom_markup: '',
14275			social_tools: '<div class="twitter"><a href="http://twitter.com/share" class="twitter-share-button" data-count="none">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script></div><div class="facebook"><iframe src="//www.facebook.com/plugins/like.php?locale=en_US&href={location_href}&amp;layout=button_count&amp;show_faces=true&amp;width=500&amp;action=like&amp;font&amp;colorscheme=light&amp;height=23" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:23px;" allowTransparency="true"></iframe></div>' /* html or false to disable */
14276		}, pp_settings);
14277		
14278		// Global variables accessible only by prettyPhoto
14279		var matchedObjects = this, percentBased = false, pp_dimensions, pp_open,
14280		
14281		// prettyPhoto container specific
14282		pp_contentHeight, pp_contentWidth, pp_containerHeight, pp_containerWidth,
14283		
14284		// Window size
14285		windowHeight = $(window).height(), windowWidth = $(window).width(),
14286
14287		// Global elements
14288		pp_slideshow;
14289		
14290		doresize = true, scroll_pos = _get_scroll();
14291	
14292		// Window/Keyboard events
14293		$(window).unbind('resize.prettyphoto').bind('resize.prettyphoto',function(){ _center_overlay(); _resize_overlay(); });
14294		
14295		if(pp_settings.keyboard_shortcuts) {
14296			$(document).unbind('keydown.prettyphoto').bind('keydown.prettyphoto',function(e){
14297				if(typeof $pp_pic_holder != 'undefined'){
14298					if($pp_pic_holder.is(':visible')){
14299						switch(e.keyCode){
14300							case 37:
14301								$.prettyPhoto.changePage('previous');
14302								e.preventDefault();
14303								break;
14304							case 39:
14305								$.prettyPhoto.changePage('next');
14306								e.preventDefault();
14307								break;
14308							case 27:
14309								if(!settings.modal)
14310								$.prettyPhoto.close();
14311								e.preventDefault();
14312								break;
14313						};
14314						// return false;
14315					};
14316				};
14317			});
14318		};
14319		
14320		/**
14321		* Initialize prettyPhoto.
14322		*/
14323		$.prettyPhoto.initialize = function() {
14324			
14325			settings = pp_settings;
14326			
14327			if(settings.theme == 'pp_default') settings.horizontal_padding = 16;
14328			
14329			// Find out if the picture is part of a set
14330			theRel = $(this).attr(settings.hook);
14331			galleryRegExp = /\[(?:.*)\]/;
14332			isSet = (galleryRegExp.exec(theRel)) ? true : false;
14333			
14334			// Put the SRCs, TITLEs, ALTs into an array.
14335			pp_images = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return $(n).attr('href'); }) : $.makeArray($(this).attr('href'));
14336			pp_titles = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).find('img').attr('alt')) ? $(n).find('img').attr('alt') : ""; }) : $.makeArray($(this).find('img').attr('alt'));
14337			pp_descriptions = (isSet) ? jQuery.map(matchedObjects, function(n, i){ if($(n).attr(settings.hook).indexOf(theRel) != -1) return ($(n).attr('title')) ? $(n).attr('title') : ""; }) : $.makeArray($(this).attr('title'));
14338			
14339			if(pp_images.length > settings.overlay_gallery_max) settings.overlay_gallery = false;
14340			
14341			set_position = jQuery.inArray($(this).attr('href'), pp_images); // Define where in the array the clicked item is positionned
14342			rel_index = (isSet) ? set_position : $("a["+settings.hook+"^='"+theRel+"']").index($(this));
14343			
14344			_build_overlay(this); // Build the overlay {this} being the caller
14345			
14346			if(settings.allow_resize)
14347				$(window).bind('scroll.prettyphoto',function(){ _center_overlay(); });
14348			
14349			
14350			$.prettyPhoto.open();
14351			
14352			return false;
14353		}
14354
14355
14356		/**
14357		* Opens the prettyPhoto modal box.
14358		* @param image {String,Array} Full path to the image to be open, can also be an array containing full images paths.
14359		* @param title {String,Array} The title to be displayed with the picture, can also be an array containing all the titles.
14360		* @param description {String,Array} The description to be displayed with the picture, can also be an array containing all the descriptions.
14361		*/
14362		$.prettyPhoto.open = function(event) {
14363			if(typeof settings == "undefined"){ // Means it's an API call, need to manually get the settings and set the variables
14364				settings = pp_settings;
14365				pp_images = $.makeArray(arguments[0]);
14366				pp_titles = (arguments[1]) ? $.makeArray(arguments[1]) : $.makeArray("");
14367				pp_descriptions = (arguments[2]) ? $.makeArray(arguments[2]) : $.makeArray("");
14368				isSet = (pp_images.length > 1) ? true : false;
14369				set_position = (arguments[3])? arguments[3]: 0;
14370				_build_overlay(event.target); // Build the overlay {this} being the caller
14371			}
14372			
14373			if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','hidden'); // Hide the flash
14374
14375			_checkPosition($(pp_images).size()); // Hide the next/previous links if on first or last images.
14376		
14377			$('.pp_loaderIcon').show();
14378		
14379			if(settings.deeplinking)
14380				setHashtag();
14381		
14382			// Rebuild Facebook Like Button with updated href
14383			if(settings.social_tools){
14384				facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); 
14385				$pp_pic_holder.find('.pp_social').html(facebook_like_link);
14386			}
14387			
14388			// Fade the content in
14389			if($ppt.is(':hidden')) $ppt.css('opacity',0).show();
14390			$pp_overlay.show().fadeTo(settings.animation_speed,settings.opacity);
14391
14392			// Display the current position
14393			$pp_pic_holder.find('.currentTextHolder').text((set_position+1) + settings.counter_separator_label + $(pp_images).size());
14394
14395			// Set the description
14396			if(typeof pp_descriptions[set_position] != 'undefined' && pp_descriptions[set_position] != ""){
14397				$pp_pic_holder.find('.pp_description').show().html(unescape(pp_descriptions[set_position]));
14398			}else{
14399				$pp_pic_holder.find('.pp_description').hide();
14400			}
14401			
14402			// Get the dimensions
14403			movie_width = ( parseFloat(getParam('width',pp_images[set_position])) ) ? getParam('width',pp_images[set_position]) : settings.default_width.toString();
14404			movie_height = ( parseFloat(getParam('height',pp_images[set_position])) ) ? getParam('height',pp_images[set_position]) : settings.default_height.toString();
14405			
14406			// If the size is % based, calculate according to window dimensions
14407			percentBased=false;
14408			if(movie_height.indexOf('%') != -1) { movie_height = parseFloat(($(window).height() * parseFloat(movie_height) / 100) - 150); percentBased = true; }
14409			if(movie_width.indexOf('%') != -1) { movie_width = parseFloat(($(window).width() * parseFloat(movie_width) / 100) - 150); percentBased = true; }
14410			
14411			// Fade the holder
14412			$pp_pic_holder.fadeIn(function(){
14413				// Set the title
14414				(settings.show_title && pp_titles[set_position] != "" && typeof pp_titles[set_position] != "undefined") ? $ppt.html(unescape(pp_titles[set_position])) : $ppt.html('&nbsp;');
14415				
14416				imgPreloader = "";
14417				skipInjection = false;
14418				
14419				// Inject the proper content
14420				switch(_getFileType(pp_images[set_position])){
14421					case 'image':
14422						imgPreloader = new Image();
14423
14424						// Preload the neighbour images
14425						nextImage = new Image();
14426						if(isSet && set_position < $(pp_images).size() -1) nextImage.src = pp_images[set_position + 1];
14427						prevImage = new Image();
14428						if(isSet && pp_images[set_position - 1]) prevImage.src = pp_images[set_position - 1];
14429
14430						$pp_pic_holder.find('#pp_full_res')[0].innerHTML = settings.image_markup.replace(/{path}/g,pp_images[set_position]);
14431
14432						imgPreloader.onload = function(){
14433							// Fit item to viewport
14434							pp_dimensions = _fitToViewport(imgPreloader.width,imgPreloader.height);
14435
14436							_showContent();
14437						};
14438
14439						imgPreloader.onerror = function(){
14440							alert('Image cannot be loaded. Make sure the path is correct and image exist.');
14441							$.prettyPhoto.close();
14442						};
14443					
14444						imgPreloader.src = pp_images[set_position];
14445					break;
14446				
14447					case 'youtube':
14448						pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport
14449						
14450						// Regular youtube link
14451						movie_id = getParam('v',pp_images[set_position]);
14452						
14453						// youtu.be link
14454						if(movie_id == ""){
14455							movie_id = pp_images[set_position].split('youtu.be/');
14456							movie_id = movie_id[1];
14457							if(movie_id.indexOf('?') > 0)
14458								movie_id = movie_id.substr(0,movie_id.indexOf('?')); // Strip anything after the ?
14459
14460							if(movie_id.indexOf('&') > 0)
14461								movie_id = movie_id.substr(0,movie_id.indexOf('&')); // Strip anything after the &
14462						}
14463
14464						movie = '//www.youtube.com/embed/'+movie_id;
14465						(getParam('rel',pp_images[set_position])) ? movie+="?rel="+getParam('rel',pp_images[set_position]) : movie+="?rel=1";
14466							
14467						if(settings.autoplay) movie += "&autoplay=1";
14468					
14469						toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,movie);
14470					break;
14471				
14472					case 'vimeo':
14473						pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport
14474					
14475						movie_id = pp_images[set_position];
14476						var regExp = /http(s?):\/\/(www\.)?vimeo.com\/(\d+)/;
14477						var match = movie_id.match(regExp);
14478						
14479						movie = '//player.vimeo.com/video/'+ match[3] +'?title=0&amp;byline=0&amp;portrait=0';
14480						if(settings.autoplay) movie += "&autoplay=1;";
14481				
14482						vimeo_width = pp_dimensions['width'] + '/embed/?moog_width='+ pp_dimensions['width'];
14483				
14484						toInject = settings.iframe_markup.replace(/{width}/g,vimeo_width).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,movie);
14485					break;
14486				
14487					case 'quicktime':
14488						pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport
14489						pp_dimensions['height']+=15; pp_dimensions['contentHeight']+=15; pp_dimensions['containerHeight']+=15; // Add space for the control bar
14490				
14491						toInject = settings.quicktime_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,pp_images[set_position]).replace(/{autoplay}/g,settings.autoplay);
14492					break;
14493				
14494					case 'flash':
14495						pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport
14496					
14497						flash_vars = pp_images[set_position];
14498						flash_vars = flash_vars.substring(pp_images[set_position].indexOf('flashvars') + 10,pp_images[set_position].length);
14499
14500						filename = pp_images[set_position];
14501						filename = filename.substring(0,filename.indexOf('?'));
14502					
14503						toInject =  settings.flash_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{wmode}/g,settings.wmode).replace(/{path}/g,filename+'?'+flash_vars);
14504					break;
14505				
14506					case 'iframe':
14507						pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport
14508				
14509						frame_url = pp_images[set_position];
14510						frame_url = frame_url.substr(0,frame_url.indexOf('iframe')-1);
14511
14512						toInject = settings.iframe_markup.replace(/{width}/g,pp_dimensions['width']).replace(/{height}/g,pp_dimensions['height']).replace(/{path}/g,frame_url);
14513					break;
14514					
14515					case 'ajax':
14516						doresize = false; // Make sure the dimensions are not resized.
14517						pp_dimensions = _fitToViewport(movie_width,movie_height);
14518						doresize = true; // Reset the dimensions
14519					
14520						skipInjection = true;
14521						$.get(pp_images[set_position],function(responseHTML){
14522							toInject = settings.inline_markup.replace(/{content}/g,responseHTML);
14523							$pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject;
14524							_showContent();
14525						});
14526						
14527					break;
14528					
14529					case 'custom':
14530						pp_dimensions = _fitToViewport(movie_width,movie_height); // Fit item to viewport
14531					
14532						toInject = settings.custom_markup;
14533					break;
14534				
14535					case 'inline':
14536						// to get the item height clone it, apply default width, wrap it in the prettyPhoto containers , then delete
14537						myClone = $(pp_images[set_position]).clone().append('<br clear="all" />').css({'width':settings.default_width}).wrapInner('<div id="pp_full_res"><div class="pp_inline"></div></div>').appendTo($('body')).show();
14538						doresize = false; // Make sure the dimensions are not resized.
14539						pp_dimensions = _fitToViewport($(myClone).width(),$(myClone).height());
14540						doresize = true; // Reset the dimensions
14541						$(myClone).remove();
14542						toInject = settings.inline_markup.replace(/{content}/g,$(pp_images[set_position]).html());
14543					break;
14544				};
14545
14546				if(!imgPreloader && !skipInjection){
14547					$pp_pic_holder.find('#pp_full_res')[0].innerHTML = toInject;
14548				
14549					// Show content
14550					_showContent();
14551				};
14552			});
14553
14554			return false;
14555		};
14556
14557	
14558		/**
14559		* Change page in the prettyPhoto modal box
14560		* @param direction {String} Direction of the paging, previous or next.
14561		*/
14562		$.prettyPhoto.changePage = function(direction){
14563			currentGalleryPage = 0;
14564			
14565			if(direction == 'previous') {
14566				set_position--;
14567				if (set_position < 0) set_position = $(pp_images).size()-1;
14568			}else if(direction == 'next'){
14569				set_position++;
14570				if(set_position > $(pp_images).size()-1) set_position = 0;
14571			}else{
14572				set_position=direction;
14573			};
14574			
14575			rel_index = set_position;
14576
14577			if(!doresize) doresize = true; // Allow the resizing of the images
14578			if(settings.allow_expand) {
14579				$('.pp_contract').removeClass('pp_contract').addClass('pp_expand');
14580			}
14581
14582			_hideContent(function(){ $.prettyPhoto.open(); });
14583		};
14584
14585
14586		/**
14587		* Change gallery page in the prettyPhoto modal box
14588		* @param direction {String} Direction of the paging, previous or next.
14589		*/
14590		$.prettyPhoto.changeGalleryPage = function(direction){
14591			if(direction=='next'){
14592				currentGalleryPage ++;
14593
14594				if(currentGalleryPage > totalPage) currentGalleryPage = 0;
14595			}else if(direction=='previous'){
14596				currentGalleryPage --;
14597
14598				if(currentGalleryPage < 0) currentGalleryPage = totalPage;
14599			}else{
14600				currentGalleryPage = direction;
14601			};
14602			
14603			slide_speed = (direction == 'next' || direction == 'previous') ? settings.animation_speed : 0;
14604
14605			slide_to = currentGalleryPage * (itemsPerPage * itemWidth);
14606
14607			$pp_gallery.find('ul').animate({left:-slide_to},slide_speed);
14608		};
14609
14610
14611		/**
14612		* Start the slideshow...
14613		*/
14614		$.prettyPhoto.startSlideshow = function(){
14615			if(typeof pp_slideshow == 'undefined'){
14616				$pp_pic_holder.find('.pp_play').unbind('click').removeClass('pp_play').addClass('pp_pause').click(function(){
14617					$.prettyPhoto.stopSlideshow();
14618					return false;
14619				});
14620				pp_slideshow = setInterval($.prettyPhoto.startSlideshow,settings.slideshow);
14621			}else{
14622				$.prettyPhoto.changePage('next');	
14623			};
14624		}
14625
14626
14627		/**
14628		* Stop the slideshow...
14629		*/
14630		$.prettyPhoto.stopSlideshow = function(){
14631			$pp_pic_holder.find('.pp_pause').unbind('click').removeClass('pp_pause').addClass('pp_play').click(function(){
14632				$.prettyPhoto.startSlideshow();
14633				return false;
14634			});
14635			clearInterval(pp_slideshow);
14636			pp_slideshow=undefined;
14637		}
14638
14639
14640		/**
14641		* Closes prettyPhoto.
14642		*/
14643		$.prettyPhoto.close = function(){
14644			if($pp_overlay.is(":animated")) return;
14645			
14646			$.prettyPhoto.stopSlideshow();
14647			
14648			$pp_pic_holder.stop().find('object,embed').css('visibility','hidden');
14649			
14650			$('div.pp_pic_holder,div.ppt,.pp_fade').fadeOut(settings.animation_speed,function(){ $(this).remove(); });
14651			
14652			$pp_overlay.fadeOut(settings.animation_speed, function(){
14653				
14654				if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','visible'); // Show the flash
14655				
14656				$(this).remove(); // No more need for the prettyPhoto markup
14657				
14658				$(window).unbind('scroll.prettyphoto');
14659				
14660				clearHashtag();
14661				
14662				settings.callback();
14663				
14664				doresize = true;
14665				
14666				pp_open = false;
14667				
14668				delete settings;
14669			});
14670		};
14671	
14672		/**
14673		* Set the proper sizes on the containers and animate the content in.
14674		*/
14675		function _showContent(){
14676			$('.pp_loaderIcon').hide();
14677
14678			// Calculate the opened top position of the pic holder
14679			projectedTop = scroll_pos['scrollTop'] + ((windowHeight/2) - (pp_dimensions['containerHeight']/2));
14680			if(projectedTop < 0) projectedTop = 0;
14681
14682			$ppt.fadeTo(settings.animation_speed,1);
14683
14684			// Resize the content holder
14685			$pp_pic_holder.find('.pp_content')
14686				.animate({
14687					height:pp_dimensions['contentHeight'],
14688					width:pp_dimensions['contentWidth']
14689				},settings.animation_speed);
14690			
14691			// Resize picture the holder
14692			$pp_pic_holder.animate({
14693				'top': projectedTop,
14694				'left': ((windowWidth/2) - (pp_dimensions['containerWidth']/2) < 0) ? 0 : (windowWidth/2) - (pp_dimensions['containerWidth']/2),
14695				width:pp_dimensions['containerWidth']
14696			},settings.animation_speed,function(){
14697				$pp_pic_holder.find('.pp_hoverContainer,#fullResImage').height(pp_dimensions['height']).width(pp_dimensions['width']);
14698
14699				$pp_pic_holder.find('.pp_fade').fadeIn(settings.animation_speed); // Fade the new content
14700
14701				// Show the nav
14702				if(isSet && _getFileType(pp_images[set_position])=="image") { $pp_pic_holder.find('.pp_hoverContainer').show(); }else{ $pp_pic_holder.find('.pp_hoverContainer').hide(); }
14703			
14704				if(settings.allow_expand) {
14705					if(pp_dimensions['resized']){ // Fade the resizing link if the image is resized
14706						$('a.pp_expand,a.pp_contract').show();
14707					}else{
14708						$('a.pp_expand').hide();
14709					}
14710				}
14711				
14712				if(settings.autoplay_slideshow && !pp_slideshow && !pp_open) $.prettyPhoto.startSlideshow();
14713				
14714				settings.changepicturecallback(); // Callback!
14715				
14716				pp_open = true;
14717			});
14718			
14719			_insert_gallery();
14720			pp_settings.ajaxcallback();
14721		};
14722		
14723		/**
14724		* Hide the content...DUH!
14725		*/
14726		function _hideContent(callback){
14727			// Fade out the current picture
14728			$pp_pic_holder.find('#pp_full_res object,#pp_full_res embed').css('visibility','hidden');
14729			$pp_pic_holder.find('.pp_fade').fadeOut(settings.animation_speed,function(){
14730				$('.pp_loaderIcon').show();
14731				
14732				callback();
14733			});
14734		};
14735	
14736		/**
14737		* Check the item position in the gallery array, hide or show the navigation links
14738		* @param setCount {integer} The total number of items in the set
14739		*/
14740		function _checkPosition(setCount){
14741			(setCount > 1) ? $('.pp_nav').show() : $('.pp_nav').hide(); // Hide the bottom nav if it's not a set.
14742		};
14743	
14744		/**
14745		* Resize the item dimensions if it's bigger than the viewport
14746		* @param width {integer} Width of the item to be opened
14747		* @param height {integer} Height of the item to be opened
14748		* @return An array containin the "fitted" dimensions
14749		*/
14750		function _fitToViewport(width,height){
14751			resized = false;
14752
14753			_getDimensions(width,height);
14754			
14755			// Define them in case there's no resize needed
14756			imageWidth = width, imageHeight = height;
14757
14758			if( ((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)) && doresize && settings.allow_resize && !percentBased) {
14759				resized = true, fitting = false;
14760			
14761				while (!fitting){
14762					if((pp_containerWidth > windowWidth)){
14763						imageWidth = (windowWidth - 200);
14764						imageHeight = (height/width) * imageWidth;
14765					}else if((pp_containerHeight > windowHeight)){
14766						imageHeight = (windowHeight - 200);
14767						imageWidth = (width/height) * imageHeight;
14768					}else{
14769						fitting = true;
14770					};
14771
14772					pp_containerHeight = imageHeight, pp_containerWidth = imageWidth;
14773				};
14774			
14775
14776				
14777				if((pp_containerWidth > windowWidth) || (pp_containerHeight > windowHeight)){
14778					_fitToViewport(pp_containerWidth,pp_containerHeight)
14779				};
14780				
14781				_getDimensions(imageWidth,imageHeight);
14782			};
14783			
14784			return {
14785				width:Math.floor(imageWidth),
14786				height:Math.floor(imageHeight),
14787				containerHeight:Math.floor(pp_containerHeight),
14788				containerWidth:Math.floor(pp_containerWidth) + (settings.horizontal_padding * 2),
14789				contentHeight:Math.floor(pp_contentHeight),
14790				contentWidth:Math.floor(pp_contentWidth),
14791				resized:resized
14792			};
14793		};
14794		
14795		/**
14796		* Get the containers dimensions according to the item size
14797		* @param width {integer} Width of the item to be opened
14798		* @param height {integer} Height of the item to be opened
14799		*/
14800		function _getDimensions(width,height){
14801			width = parseFloat(width);
14802			height = parseFloat(height);
14803			
14804			// Get the details height, to do so, I need to clone it since it's invisible
14805			$pp_details = $pp_pic_holder.find('.pp_details');
14806			$pp_details.width(width);
14807			detailsHeight = parseFloat($pp_details.css('marginTop')) + parseFloat($pp_details.css('marginBottom'));
14808			
14809			$pp_details = $pp_details.clone().addClass(settings.theme).width(width).appendTo($('body')).css({
14810				'position':'absolute',
14811				'top':-10000
14812			});
14813			detailsHeight += $pp_details.height();
14814			detailsHeight = (detailsHeight <= 34) ? 36 : detailsHeight; // Min-height for the details
14815			$pp_details.remove();
14816			
14817			// Get the titles height, to do so, I need to clone it since it's invisible
14818			$pp_title = $pp_pic_holder.find('.ppt');
14819			$pp_title.width(width);
14820			titleHeight = parseFloat($pp_title.css('marginTop')) + parseFloat($pp_title.css('marginBottom'));
14821			$pp_title = $pp_title.clone().appendTo($('body')).css({
14822				'position':'absolute',
14823				'top':-10000
14824			});
14825			titleHeight += $pp_title.height();
14826			$pp_title.remove();
14827			
14828			// Get the container size, to resize the holder to the right dimensions
14829			pp_contentHeight = height + detailsHeight;
14830			pp_contentWidth = width;
14831			pp_containerHeight = pp_contentHeight + titleHeight + $pp_pic_holder.find('.pp_top').height() + $pp_pic_holder.find('.pp_bottom').height();
14832			pp_containerWidth = width;
14833		}
14834	
14835		function _getFileType(itemSrc){
14836			if (itemSrc.match(/youtube\.com\/watch/i) || itemSrc.match(/youtu\.be/i)) {
14837				return 'youtube';
14838			}else if (itemSrc.match(/vimeo\.com/i)) {
14839				return 'vimeo';
14840			}else if(itemSrc.match(/\b.mov\b/i)){ 
14841				return 'quicktime';
14842			}else if(itemSrc.match(/\b.swf\b/i)){
14843				return 'flash';
14844			}else if(itemSrc.match(/\biframe=true\b/i)){
14845				return 'iframe';
14846			}else if(itemSrc.match(/\bajax=true\b/i)){
14847				return 'ajax';
14848			}else if(itemSrc.match(/\bcustom=true\b/i)){
14849				return 'custom';
14850			}else if(itemSrc.substr(0,1) == '#'){
14851				return 'inline';
14852			}else{
14853				return 'image';
14854			};
14855		};
14856	
14857		function _center_overlay(){
14858			if(doresize && typeof $pp_pic_holder != 'undefined') {
14859				scroll_pos = _get_scroll();
14860				contentHeight = $pp_pic_holder.height(), contentwidth = $pp_pic_holder.width();
14861
14862				projectedTop = (windowHeight/2) + scroll_pos['scrollTop'] - (contentHeight/2);
14863				if(projectedTop < 0) projectedTop = 0;
14864				
14865				if(contentHeight > windowHeight)
14866					return;
14867
14868				$pp_pic_holder.css({
14869					'top': projectedTop,
14870					'left': (windowWidth/2) + scroll_pos['scrollLeft'] - (contentwidth/2)
14871				});
14872			};
14873		};
14874	
14875		function _get_scroll(){
14876			if (self.pageYOffset) {
14877				return {scrollTop:self.pageYOffset,scrollLeft:self.pageXOffset};
14878			} else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
14879				return {scrollTop:document.documentElement.scrollTop,scrollLeft:document.documentElement.scrollLeft};
14880			} else if (document.body) {// all other Explorers
14881				return {scrollTop:document.body.scrollTop,scrollLeft:document.body.scrollLeft};
14882			};
14883		};
14884	
14885		function _resize_overlay() {
14886			windowHeight = $(window).height(), windowWidth = $(window).width();
14887			
14888			if(typeof $pp_overlay != "undefined") $pp_overlay.height($(document).height()).width(windowWidth);
14889		};
14890	
14891		function _insert_gallery(){
14892			if(isSet && settings.overlay_gallery && _getFileType(pp_images[set_position])=="image") {
14893				itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin.
14894				navWidth = (settings.theme == "facebook" || settings.theme == "pp_default") ? 50 : 30; // Define the arrow width depending on the theme
14895				
14896				itemsPerPage = Math.floor((pp_dimensions['containerWidth'] - 100 - navWidth) / itemWidth);
14897				itemsPerPage = (itemsPerPage < pp_images.length) ? itemsPerPage : pp_images.length;
14898				totalPage = Math.ceil(pp_images.length / itemsPerPage) - 1;
14899
14900				// Hide the nav in the case there's no need for links
14901				if(totalPage == 0){
14902					navWidth = 0; // No nav means no width!
14903					$pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').hide();
14904				}else{
14905					$pp_gallery.find('.pp_arrow_next,.pp_arrow_previous').show();
14906				};
14907
14908				galleryWidth = itemsPerPage * itemWidth;
14909				fullGalleryWidth = pp_images.length * itemWidth;
14910				
14911				// Set the proper width to the gallery items
14912				$pp_gallery
14913					.css('margin-left',-((galleryWidth/2) + (navWidth/2)))
14914					.find('div:first').width(galleryWidth+5)
14915					.find('ul').width(fullGalleryWidth)
14916					.find('li.selected').removeClass('selected');
14917				
14918				goToPage = (Math.floor(set_position/itemsPerPage) < totalPage) ? Math.floor(set_position/itemsPerPage) : totalPage;
14919
14920				$.prettyPhoto.changeGalleryPage(goToPage);
14921				
14922				$pp_gallery_li.filter(':eq('+set_position+')').addClass('selected');
14923			}else{
14924				$pp_pic_holder.find('.pp_content').unbind('mouseenter mouseleave');
14925				// $pp_gallery.hide();
14926			}
14927		}
14928	
14929		function _build_overlay(caller){
14930			// Inject Social Tool markup into General markup
14931			if(settings.social_tools)
14932				facebook_like_link = settings.social_tools.replace('{location_href}', encodeURIComponent(location.href)); 
14933
14934			settings.markup = settings.markup.replace('{pp_social}',''); 
14935			
14936			$('body').append(settings.markup); // Inject the markup
14937			
14938			$pp_pic_holder = $('.pp_pic_holder') , $ppt = $('.ppt'), $pp_overlay 
14938= $('div.pp_overlay'); // Set my global selectors
14939			
14940			// Inject the inline gallery!
14941			if(isSet && settings.overlay_gallery) {
14942				currentGalleryPage = 0;
14943				toInject = "";
14944				for (var i=0; i < pp_images.length; i++) {
14945					if(!pp_images[i].match(/\b(jpg|jpeg|png|gif)\b/gi)){
14946						classname = 'default';
14947						img_src = '';
14948					}else{
14949						classname = '';
14950						img_src = pp_images[i];
14951					}
14952					toInject += "<li class='"+classname+"'><a href='#'><img src='" + img_src + "' width='50' alt='' /></a></li>";
14953				};
14954				
14955				toInject = settings.gallery_markup.replace(/{gallery}/g,toInject);
14956				
14957				$pp_pic_holder.find('#pp_full_res').after(toInject);
14958				
14959				$pp_gallery = $('.pp_pic_holder .pp_gallery'), $pp_gallery_li = $pp_gallery.find('li'); // Set the gallery selectors
14960				
14961				$pp_gallery.find('.pp_arrow_next').click(function(){
14962					$.prettyPhoto.changeGalleryPage('next');
14963					$.prettyPhoto.stopSlideshow();
14964					return false;
14965				});
14966				
14967				$pp_gallery.find('.pp_arrow_previous').click(function(){
14968					$.prettyPhoto.changeGalleryPage('previous');
14969					$.prettyPhoto.stopSlideshow();
14970					return false;
14971				});
14972				
14973				$pp_pic_holder.find('.pp_content').hover(
14974					function(){
14975						$pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeIn();
14976					},
14977					function(){
14978						$pp_pic_holder.find('.pp_gallery:not(.disabled)').fadeOut();
14979					});
14980
14981				itemWidth = 52+5; // 52 beign the thumb width, 5 being the right margin.
14982				$pp_gallery_li.each(function(i){
14983					$(this)
14984						.find('a')
14985						.click(function(){
14986							$.prettyPhoto.changePage(i);
14987							$.prettyPhoto.stopSlideshow();
14988							return false;
14989						});
14990				});
14991			};
14992			
14993			
14994			// Inject the play/pause if it's a slideshow
14995			if(settings.slideshow){
14996				$pp_pic_holder.find('.pp_nav').prepend('<a href="#" class="pp_play">Play</a>')
14997				$pp_pic_holder.find('.pp_nav .pp_play').click(function(){
14998					$.prettyPhoto.startSlideshow();
14999					return false;
15000				});
15001			}
15002			
15003			$pp_pic_holder.attr('class','pp_pic_holder ' + settings.theme); // Set the proper theme
15004			
15005			$pp_overlay
15006				.css({
15007					'opacity':0,
15008					'height':$(document).height(),
15009					'width':$(window).width()
15010					})
15011				.bind('click',function(){
15012					if(!settings.modal) $.prettyPhoto.close();
15013				});
15014
15015			$('a.pp_close').bind('click',function(){ $.prettyPhoto.close(); return false; });
15016
15017
15018			if(settings.allow_expand) {
15019				$('a.pp_expand').bind('click',function(e){
15020					// Expand the image
15021					if($(this).hasClass('pp_expand')){
15022						$(this).removeClass('pp_expand').addClass('pp_contract');
15023						doresize = false;
15024					}else{
15025						$(this).removeClass('pp_contract').addClass('pp_expand');
15026						doresize = true;
15027					};
15028				
15029					_hideContent(function(){ $.prettyPhoto.open(); });
15030			
15031					return false;
15032				});
15033			}
15034		
15035			$pp_pic_holder.find('.pp_previous, .pp_nav .pp_arrow_previous').bind('click',function(){
15036				$.prettyPhoto.changePage('previous');
15037				$.prettyPhoto.stopSlideshow();
15038				return false;
15039			});
15040		
15041			$pp_pic_holder.find('.pp_next, .pp_nav .pp_arrow_next').bind('click',function(){
15042				$.prettyPhoto.changePage('next');
15043				$.prettyPhoto.stopSlideshow();
15044				return false;
15045			});
15046			
15047			_center_overlay(); // Center it
15048		};
15049
15050		if(!pp_alreadyInitialized && getHashtag()){
15051			pp_alreadyInitialized = true;
15052			
15053			// Grab the rel index to trigger the click on the correct element
15054			hashIndex = getHashtag();
15055			hashRel = hashIndex;
15056			hashIndex = hashIndex.substring(hashIndex.indexOf('/')+1,hashIndex.length-1);
15057			hashRel = hashRel.substring(0,hashRel.indexOf('/'));
15058
15059			// Little timeout to make sure all the prettyPhoto initialize scripts has been run.
15060			// Useful in the event the page contain several init scripts.
15061			setTimeout(function(){ $("a["+pp_settings.hook+"^='"+hashRel+"']:eq("+hashIndex+")").trigger('click'); },50);
15062		}
15063		
15064		return this.unbind('click.prettyphoto').bind('click.prettyphoto',$.prettyPhoto.initialize); // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once
15065	};
15066	
15067	function getHashtag(){
15068		var url = location.href;
15069		hashtag = (url.indexOf('#prettyPhoto') !== -1) ? decodeURI(url.substring(url.indexOf('#prettyPhoto')+1,url.length)) : false;
15070		if(hashtag){  hashtag = hashtag.replace(/<|>/g,''); }
15071		return hashtag;
15072	};
15073	
15074	function setHashtag(){
15075		if(typeof theRel == 'undefined') return; // theRel is set on normal calls, it's impossible to deeplink using the API
15076		location.hash = theRel + '/'+rel_index+'/';
15077	};
15078	
15079	function clearHashtag(){
15080		if ( location.href.indexOf('#prettyPhoto') !== -1 ) location.hash = "prettyPhoto";
15081	}
15082	
15083	function getParam(name,url){
15084	  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
15085	  var regexS = "[\\?&]"+name+"=([^&#]*)";
15086	  var regex = new RegExp( regexS );
15087	  var results = regex.exec( url );
15088	  return ( results == null ) ? "" : results[1];
15089	}
15090	
15091})(jQuery);
15092
15093var pp_alreadyInitialized = false; // Used for the deep linking to make sure not to call the same function several times.
15094
15095(function (factory) {
15096    if (typeof define === 'function' && define.amd) {
15097        // AMD
15098        define(['jquery'], factory);
15099    } else if (typeof exports === 'object') {
15100        // CommonJS
15101        factory(require('jquery'));
15102    } else {
15103        // Browser globals
15104        factory(jQuery);
15105    }
15106}(function ($) {
15107  var CountTo = function (element, options) {
15108    this.$element = $(element);
15109    this.options  = $.extend({}, CountTo.DEFAULTS, this.dataOptions(), options);
15110    this.init();
15111  };
15112
15113  CountTo.DEFAULTS = {
15114    from: 0,               // the number the element should start at
15115    to: 0,                 // the number the element should end at
15116    speed: 1000,           // how long it should take to count between the target numbers
15117    refreshInterval: 100,  // how often the element should be updated
15118    decimals: 0,           // the number of decimal places to show
15119    formatter: formatter,  // handler for formatting the value before rendering
15120    onUpdate: null,        // callback method for every time the element is updated
15121    onComplete: null       // callback method for when the element finishes updating
15122  };
15123
15124  CountTo.prototype.init = function () {
15125    this.value     = this.options.from;
15126    this.loops     = Math.ceil(this.options.speed / this.options.refreshInterval);
15127    this.loopCount = 0;
15128    this.increment = (this.options.to - this.options.from) / this.loops;
15129  };
15130
15131  CountTo.prototype.dataOptions = function () {
15132    var options = {
15133      from:            this.$element.data('from'),
15134      to:              this.$element.data('to'),
15135      speed:           this.$element.data('speed'),
15136      refreshInterval: this.$element.data('refresh-interval'),
15137      decimals:        this.$element.data('decimals')
15138    };
15139
15140    var keys = Object.keys(options);
15141
15142    for (var i in keys) {
15143      var key = keys[i];
15144
15145      if (typeof(options[key]) === 'undefined') {
15146        delete options[key];
15147      }
15148    }
15149
15150    return options;
15151  };
15152
15153  CountTo.prototype.update = function () {
15154    this.value += this.increment;
15155    this.loopCount++;
15156
15157    this.render();
15158
15159    if (typeof(this.options.onUpdate) == 'function') {
15160      this.options.onUpdate.call(this.$element, this.value);
15161    }
15162
15163    if (this.loopCount >= this.loops) {
15164      clearInterval(this.interval);
15165      this.value = this.options.to;
15166
15167      if (typeof(this.options.onComplete) == 'function') {
15168        this.options.onComplete.call(this.$element, this.value);
15169      }
15170    }
15171  };
15172
15173  CountTo.prototype.render = function () {
15174    var formattedValue = this.options.formatter.call(this.$element, this.value, this.options);
15175    this.$element.text(formattedValue);
15176  };
15177
15178  CountTo.prototype.restart = function () {
15179    this.stop();
15180    this.init();
15181    this.start();
15182  };
15183
15184  CountTo.prototype.start = function () {
15185    this.stop();
15186    this.render();
15187    this.interval = setInterval(this.update.bind(this), this.options.refreshInterval);
15188  };
15189
15190  CountTo.prototype.stop = function () {
15191    if (this.interval) {
15192      clearInterval(this.interval);
15193    }
15194  };
15195
15196  CountTo.prototype.toggle = function () {
15197    if (this.interval) {
15198      this.stop();
15199    } else {
15200      this.start();
15201    }
15202  };
15203
15204  function formatter(value, options) {
15205    return value.toFixed(options.decimals);
15206  }
15207
15208  $.fn.countTo = function (option) {
15209    return this.each(function () {
15210      var $this   = $(this);
15211      var data    = $this.data('countTo');
15212      var init    = !data || typeof(option) === 'object';
15213      var options = typeof(option) === 'object' ? option : {};
15214      var method  = typeof(option) === 'string' ? option : 'start';
15215
15216      if (init) {
15217        if (data) data.stop();
15218        $this.data('countTo', data = new CountTo(this, options));
15219      }
15220
15221      data[method].call(data);
15222    });
15223  };
15224}));

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.