PageSourceSearch

https://dalmen.com/wp-content/themes/uncode/library/js/plugins.js?ver=1151873507

js dalmen.com collected 2026-10-04 02:26:35 UTC 794,182 bytes, 24,446 lines download raw bytes

1/* ----------------------------------------------------------
2 * Plugins
3 * ---------------------------------------------------------- */
4
5(function(window, $) {
6  'use strict';
7  var counter = 0,
8    $headCache = $('head'),
9    oldBigText = window.BigText,
10    oldjQueryMethod = $.fn.bigtext,
11    BigText = {
12      DEBUG_MODE: false,
13      DEFAULT_MIN_FONT_SIZE_PX: null,
14      DEFAULT_MAX_FONT_SIZE_PX: 528,
15      GLOBAL_STYLE_ID: 'bigtext-style',
16      STYLE_ID: 'bigtext-id',
17      LINE_CLASS_PREFIX: 'bigtext-line',
18      EXEMPT_CLASS: 'bigtext-exempt',
19      noConflict: function(restore)
20      {
21        if(restore) {
22          $.fn.bigtext = oldjQueryMethod;
23          window.BigText = oldBigText;
24        }
25        return BigText;
26      },
27      supports: {
28        wholeNumberFontSizeOnly: (function() {
29          if( !( 'getComputedStyle' in window ) ) {
30            return true;
31          }
32          var test = $('<div/>').css({
33              position: 'absolute',
34              'font-size': '14.1px'
35            }).insertBefore( $('script').eq(0) ),
36            computedStyle = window.getComputedStyle( test[0], null );
37
38          var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px';
39          test.remove();
40          return ret;
41        })()
42      },
43      init: function() {
44        if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
45          $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }',
46                                          '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
47        }
48      },
49      bindResize: function(eventName, resizeFunction) {
50        var timeoutId;
51        $(window).unbind(eventName).bind(eventName, function() {
52          if( timeoutId ) {
53            clearTimeout( timeoutId );
54          }
55          timeoutId = setTimeout( resizeFunction, 300 );
56        });
57      },
58      getStyleId: function(id)
59      {
60        return BigText.STYLE_ID + '-' + id;
61      },
62      generateStyleTag: function(id, css)
63      {
64        return $('<style>' + css.join('\n') + '</style>').attr('id', id);
65      },
66      clearCss: function(id)
67      {
68        var styleId = BigText.getStyleId(id);
69        $('#' + styleId).remove();
70      },
71      generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
72      {
73        var css = [];
74
75        BigText.clearCss(id);
76
77        for(var j=0, k=linesFontSizes.length; j<k; j++) {
78          css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
79            (minFontSizes[j] ? ' white-space: normal;' : '') +
80            (linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
81            (lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
82            '}');
83        }
84
85        return BigText.generateStyleTag(BigText.getStyleId(id), css);
86      },
87      jQueryMethod: function(options)
88      {
89        BigText.init();
90
91        options = $.extend({
92          minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
93          maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
94          childSelector: '',
95          resize: true
96        }, options || {});
97
98        this.each(function()
99        {
100          var $t = $(this).addClass('bigtext'),
101            maxWidth = $t.width(),
102            id = $t.attr('id'),
103            $children = options.childSelector ? $t.find( options.childSelector ) : $t.children();
104
105          if(!id) {
106            id = 'bigtext-id' + (counter++);
107            $t.attr('id', id);
108          }
109
110          if(options.resize) {
111            BigText.bindResize('resize.bigtext-event-' + id, function()
112            {
113              // TODO only call this if the width has changed.
114              BigText.jQueryMethod.call($('#' + id), options);
115            });
116          }
117
118          BigText.clearCss(id);
119
120          $children.addClass(function(lineNumber, className)
121          {
122            // remove existing line classes.
123            return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
124                BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
125          });
126
127          var sizes = calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize);
128          $headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));
129        });
130
131        return this.trigger('bigtext:complete');
132      }
133    };
134
135  function testLineDimensions($line, maxWidth, property, size, interval, units, previousWidth)
136  {
137    var width;
138    previousWidth = typeof previousWidth === 'number' ? previousWidth : 0;
139    $line.css(property, size + units);
140
141    width = $line.width();
142
143    if(width >= maxWidth) {
144
145      $line.css(property, '');
146
147      if(width === maxWidth) {
148        return {
149          match: 'exact',
150          size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
151        };
152      }
153
154      // Since this is an estimate, we calculate how far over the width we went with the new value.
155      // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value.
156      // Otherwise, we revert to the underestimate.
157      var under = maxWidth - previousWidth,
158        over = width - maxWidth;
159
160      return {
161        match: 'estimate',
162        size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3))
163      };
164    }
165
166    return width;
167  }
168
169  function calculateSizes($t, $children, maxWidth, maxFontSize, minFontSize)
170  {
171    var $c = $t.clone(true)
172      .addClass('bigtext-cloned')
173      .css({
174        fontFamily: $t.css('font-family'),
175        textTransform: $t.css('text-transform'),
176        wordSpacing: $t.css('word-spacing'),
177        letterSpacing: $t.css('letter-spacing'),
178        position: 'absolute',
179        left: BigText.DEBUG_MODE ? 0 : -9999,
180        top: BigText.DEBUG_MODE ? 0 : -9999
181      })
182      .appendTo(document.body);
183
184    // font-size isn't the only thing we can modify, we can also mess with:
185    // word-spacing and letter-spacing. WebKit does not respect subpixel
186    // letter-spacing, word-spacing, or font-size.
187    // TODO try -webkit-transform: scale() as a workaround.
188    var fontSizes = [],
189      wordSpacings = [],
190      minFontSizes = [],
191      ratios = [];
192
193    $children.css('float', 'left').each(function() {
194      var $line = $(this),
195        // TODO replace 8, 4 with a proportional size to the calculated font-size.
196        intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1],
197        lineMax,
198        newFontSize;
199
200      if($line.hasClass(BigText.EXEMPT_CLASS)) {
201        fontSizes.push(null);
202        ratios.push(null);
203        minFontSizes.push(false);
204        return;
205      }
206
207      // TODO we can cache this ratio?
208      var autoGuessSubtraction = 32, // font size in px
209        currentFontSize = parseFloat($line.css('font-size')),
210        ratio = ( $line.width() / currentFontSize ).toFixed(6);
211
212      newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction;
213
214      outer: for(var m=0, n=intervals.length; m<n; m++) {
215        inner: for(var j=1, k=10; j<=k; j++) {
216          if(newFontSize + j*intervals[m] > maxFontSize) {
217            newFontSize = maxFontSize;
218            break outer;
219          }
220
221          lineMax = testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax);
222          if(typeof lineMax !== 'number') {
223            newFontSize = lineMax.size;
224
225            if(lineMax.match === 'exact') {
226              break outer;
227            }
228            break inner;
229          }
230        }
231      }
232
233      ratios.push(maxWidth / newFontSize);
234
235      if(newFontSize > maxFontSize) {
236        fontSizes.push(maxFontSize);
237        minFontSizes.push(false);
238      } else if(!!minFontSize && newFontSize < minFontSize) {
239        fontSizes.push(minFontSize);
240        minFontSizes.push(true);
241      } else {
242        fontSizes.push(newFontSize);
243        minFontSizes.push(false);
244      }
245    }).each(function(lineNumber) {
246      var $line = $(this),
247        wordSpacing = 0,
248        interval = 1,
249        maxWordSpacing;
250
251      if($line.hasClass(BigText.EXEMPT_CLASS)) {
252        wordSpacings.push(null);
253        return;
254      }
255
256      // must re-use font-size, even though it was removed above.
257      $line.css('font-size', fontSizes[lineNumber] + 'px');
258
259      for(var m=1, n=3; m<n; m+=interval) {
260        maxWordSpacing = testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing);
261        if(typeof maxWordSpacing !== 'number') {
262          wordSpacing = maxWordSpacing.size;
263          break;
264        }
265      }
266
267      $line.css('font-size', '');
268      wordSpacings.push(wordSpacing);
269    }).removeAttr('style');
270
271    if( !BigText.DEBUG_MODE ) {
272      $c.remove();
273    } else {
274      $c.css({
275        'background-color': 'rgba(255,255,255,.4)'
276      });
277    }
278
279    return {
280      fontSizes: fontSizes,
281      wordSpacings: wordSpacings,
282      ratios: ratios,
283      minFontSizes: minFontSizes
284    };
285  }
286
287  $.fn.bigtext = BigText.jQueryMethod;
288  window.BigText = BigText;
289
290})(this, jQuery);
291/*!
292 * Isotope PACKAGED v3.0.6
293 *
294 * Licensed GPLv3 for open source use
295 * or Isotope Commercial License for commercial use
296 *
297 * https://isotope.metafizzy.co
298 * Copyright 2010-2018 Metafizzy
vendor: 15,902 bytes, lines 298-948
298
299 */
300
301/**
302 * Bridget makes jQuery widgets
303 * v2.0.1
304 * MIT license
305 */
306
307/* jshint browser: true, strict: true, undef: true, unused: true */
308
309( function( window, factory ) {
310  // universal module definition
311  /*jshint strict: false */ /* globals define, module, require */
312  if ( typeof define == 'function' && define.amd ) {
313    // AMD
314    define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
315      return factory( window, jQuery );
316    });
317  } else if ( typeof module == 'object' && module.exports ) {
318    // CommonJS
319    module.exports = factory(
320      window,
321      require('jquery')
322    );
323  } else {
324    // browser global
325    window.jQueryBridget = factory(
326      window,
327      window.jQuery
328    );
329  }
330
331}( window, function factory( window, jQuery ) {
332'use strict';
333
334// ----- utils ----- //
335
336var arraySlice = Array.prototype.slice;
337
338// helper function for logging errors
339// $.error breaks jQuery chaining
340var console = window.console;
341var logError = typeof console == 'undefined' ? function() {} :
342  function( message ) {
343    console.error( message );
344  };
345
346// ----- jQueryBridget ----- //
347
348function jQueryBridget( namespace, PluginClass, $ ) {
349  $ = $ || jQuery || window.jQuery;
350  if ( !$ ) {
351    return;
352  }
353
354  // add option method -> $().plugin('option', {...})
355  if ( !PluginClass.prototype.option ) {
356    // option setter
357    PluginClass.prototype.option = function( opts ) {
358      // bail out if not an object
359      if ( !$.isPlainObject( opts ) ){
360        return;
361      }
362      this.options = $.extend( true, this.options, opts );
363    };
364  }
365
366  // make jQuery plugin
367  $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
368    if ( typeof arg0 == 'string' ) {
369      // method call $().plugin( 'methodName', { options } )
370      // shift arguments by 1
371      var args = arraySlice.call( arguments, 1 );
372      return methodCall( this, arg0, args );
373    }
374    // just $().plugin({ options })
375    plainCall( this, arg0 );
376    return this;
377  };
378
379  // $().plugin('methodName')
380  function methodCall( $elems, methodName, args ) {
381    var returnValue;
382    var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
383
384    $elems.each( function( i, elem ) {
385      // get instance
386      var instance = $.data( elem, namespace );
387      if ( !instance ) {
388        logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
389          pluginMethodStr );
390        return;
391      }
392
393      var method = instance[ methodName ];
394      if ( !method || methodName.charAt(0) == '_' ) {
395        logError( pluginMethodStr + ' is not a valid method' );
396        return;
397      }
398
399      // apply method, get return value
400      var value = method.apply( instance, args );
401      // set return value if value is returned, use only first value
402      returnValue = returnValue === undefined ? value : returnValue;
403    });
404
405    return returnValue !== undefined ? returnValue : $elems;
406  }
407
408  function plainCall( $elems, options ) {
409    $elems.each( function( i, elem ) {
410      var instance = $.data( elem, namespace );
411      if ( instance ) {
412        // set options & init
413        instance.option( options );
414        instance._init();
415      } else {
416        // initialize new instance
417        instance = new PluginClass( elem, options );
418        $.data( elem, namespace, instance );
419      }
420    });
421  }
422
423  updateJQuery( $ );
424
425}
426
427// ----- updateJQuery ----- //
428
429// set $.bridget for v1 backwards compatibility
430function updateJQuery( $ ) {
431  if ( !$ || ( $ && $.bridget ) ) {
432    return;
433  }
434  $.bridget = jQueryBridget;
435}
436
437updateJQuery( jQuery || window.jQuery );
438
439// -----  ----- //
440
441return jQueryBridget;
442
443}));
444
445/**
446 * EvEmitter v1.1.0
447 * Lil' event emitter
448 * MIT License
449 */
450
451/* jshint unused: true, undef: true, strict: true */
452
453( function( global, factory ) {
454  // universal module definition
455  /* jshint strict: false */ /* globals define, module, window */
456  if ( typeof define == 'function' && define.amd ) {
457    // AMD - RequireJS
458    define( 'ev-emitter/ev-emitter',factory );
459  } else if ( typeof module == 'object' && module.exports ) {
460    // CommonJS - Browserify, Webpack
461    module.exports = factory();
462  } else {
463    // Browser globals
464    global.EvEmitter = factory();
465  }
466
467}( typeof window != 'undefined' ? window : this, function() {
468
469
470
471function EvEmitter() {}
472
473var proto = EvEmitter.prototype;
474
475proto.on = function( eventName, listener ) {
476  if ( !eventName || !listener ) {
477    return;
478  }
479  // set events hash
480  var events = this._events = this._events || {};
481  // set listeners array
482  var listeners = events[ eventName ] = events[ eventName ] || [];
483  // only add once
484  if ( listeners.indexOf( listener ) == -1 ) {
485    listeners.push( listener );
486  }
487
488  return this;
489};
490
491proto.once = function( eventName, listener ) {
492  if ( !eventName || !listener ) {
493    return;
494  }
495  // add event
496  this.on( eventName, listener );
497  // set once flag
498  // set onceEvents hash
499  var onceEvents = this._onceEvents = this._onceEvents || {};
500  // set onceListeners object
501  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
502  // set flag
503  onceListeners[ listener ] = true;
504
505  return this;
506};
507
508proto.off = function( eventName, listener ) {
509  var listeners = this._events && this._events[ eventName ];
510  if ( !listeners || !listeners.length ) {
511    return;
512  }
513  var index = listeners.indexOf( listener );
514  if ( index != -1 ) {
515    listeners.splice( index, 1 );
516  }
517
518  return this;
519};
520
521proto.emitEvent = function( eventName, args ) {
522  var listeners = this._events && this._events[ eventName ];
523  if ( !listeners || !listeners.length ) {
524    return;
525  }
526  // copy over to avoid interference if .off() in listener
527  listeners = listeners.slice(0);
528  args = args || [];
529  // once stuff
530  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
531
532  for ( var i=0; i < listeners.length; i++ ) {
533    var listener = listeners[i]
534    var isOnce = onceListeners && onceListeners[ listener ];
535    if ( isOnce ) {
536      // remove listener
537      // remove before trigger to prevent recursion
538      this.off( eventName, listener );
539      // unset once flag
540      delete onceListeners[ listener ];
541    }
542    // trigger listener
543    listener.apply( this, args );
544  }
545
546  return this;
547};
548
549proto.allOff = function() {
550  delete this._events;
551  delete this._onceEvents;
552};
553
554return EvEmitter;
555
556}));
557
558/*!
559 * getSize v2.0.3
560 * measure size of elements
561 * MIT license
562 */
563
564/* jshint browser: true, strict: true, undef: true, unused: true */
565/* globals console: false */
566
567( function( window, factory ) {
568  /* jshint strict: false */ /* globals define, module */
569  if ( typeof define == 'function' && define.amd ) {
570    // AMD
571    define( 'get-size/get-size',factory );
572  } else if ( typeof module == 'object' && module.exports ) {
573    // CommonJS
574    module.exports = factory();
575  } else {
576    // browser global
577    window.getSize = factory();
578  }
579
580})( window, function factory() {
581'use strict';
582
583// -------------------------- helpers -------------------------- //
584
585// get a number from a string, not a percentage
586function getStyleSize( value ) {
587  var num = parseFloat( value );
588  // not a percent like '100%', and a number
589  var isValid = value.indexOf('%') == -1 && !isNaN( num );
590  return isValid && num;
591}
592
593function noop() {}
594
595var logError = typeof console == 'undefined' ? noop :
596  function( message ) {
597    console.error( message );
598  };
599
600// -------------------------- measurements -------------------------- //
601
602var measurements = [
603  'paddingLeft',
604  'paddingRight',
605  'paddingTop',
606  'paddingBottom',
607  'marginLeft',
608  'marginRight',
609  'marginTop',
610  'marginBottom',
611  'borderLeftWidth',
612  'borderRightWidth',
613  'borderTopWidth',
614  'borderBottomWidth'
615];
616
617var measurementsLength = measurements.length;
618
619function getZeroSize() {
620  var size = {
621    width: 0,
622    height: 0,
623    innerWidth: 0,
624    innerHeight: 0,
625    outerWidth: 0,
626    outerHeight: 0
627  };
628  for ( var i=0; i < measurementsLength; i++ ) {
629    var measurement = measurements[i];
630    size[ measurement ] = 0;
631  }
632  return size;
633}
634
635// -------------------------- getStyle -------------------------- //
636
637/**
638 * getStyle, get style of element, check for Firefox bug
639 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
640 */
641function getStyle( elem ) {
642  var style = getComputedStyle( elem );
643  if ( !style ) {
644    logError( 'Style returned ' + style +
645      '. Are you running this code in a hidden iframe on Firefox? ' +
646      'See https://bit.ly/getsizebug1' );
647  }
648  return style;
649}
650
651// -------------------------- setup -------------------------- //
652
653var isSetup = false;
654
655var isBoxSizeOuter;
656
657/**
658 * setup
659 * check isBoxSizerOuter
660 * do on first getSize() rather than on page load for Firefox bug
661 */
662function setup() {
663  // setup once
664  if ( isSetup ) {
665    return;
666  }
667  isSetup = true;
668
669  // -------------------------- box sizing -------------------------- //
670
671  /**
672   * Chrome & Safari measure the outer-width on style.width on border-box elems
673   * IE11 & Firefox<29 measures the inner-width
674   */
675  var div = document.createElement('div');
676  div.style.width = '200px';
677  div.style.padding = '1px 2px 3px 4px';
678  div.style.borderStyle = 'solid';
679  div.style.borderWidth = '1px 2px 3px 4px';
680  div.style.boxSizing = 'border-box';
681
682  var body = document.body || document.documentElement;
683  body.appendChild( div );
684  var style = getStyle( div );
685  // round value for browser zoom. desandro/masonry#928
686  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
687  getSize.isBoxSizeOuter = isBoxSizeOuter;
688
689  body.removeChild( div );
690}
691
692// -------------------------- getSize -------------------------- //
693
694function getSize( elem ) {
695  setup();
696
697  // use querySeletor if elem is string
698  if ( typeof elem == 'string' ) {
699    elem = document.querySelector( elem );
700  }
701
702  // do not proceed on non-objects
703  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
704    return;
705  }
706
707  var style = getStyle( elem );
708
709  // if hidden, everything is 0
710  if ( style.display == 'none' ) {
711    return getZeroSize();
712  }
713
714  var size = {};
715  size.width = elem.offsetWidth;
716  size.height = elem.offsetHeight;
717
718  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
719
720  // get all measurements
721  for ( var i=0; i < measurementsLength; i++ ) {
722    var measurement = measurements[i];
723    var value = style[ measurement ];
724    var num = parseFloat( value );
725    // any 'auto', 'medium' value will be 0
726    size[ measurement ] = !isNaN( num ) ? num : 0;
727  }
728
729  var paddingWidth = size.paddingLeft + size.paddingRight;
730  var paddingHeight = size.paddingTop + size.paddingBottom;
731  var marginWidth = size.marginLeft + size.marginRight;
732  var marginHeight = size.marginTop + size.marginBottom;
733  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
734  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
735
736  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
737
738  // overwrite width and height if we can get it from style
739  var styleWidth = getStyleSize( style.width );
740  if ( styleWidth !== false ) {
741    size.width = styleWidth +
742      // add padding and border unless it's already including it
743      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
744  }
745
746  var styleHeight = getStyleSize( style.height );
747  if ( styleHeight !== false ) {
748    size.height = styleHeight +
749      // add padding and border unless it's already including it
750      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
751  }
752
753  size.innerWidth = size.width - ( paddingWidth + borderWidth );
754  size.innerHeight = size.height - ( paddingHeight + borderHeight );
755
756  size.outerWidth = size.width + marginWidth;
757  size.outerHeight = size.height + marginHeight;
758
759  return size;
760}
761
762return getSize;
763
764});
765
766/**
767 * matchesSelector v2.0.2
768 * matchesSelector( element, '.selector' )
769 * MIT license
770 */
771
772/*jshint browser: true, strict: true, undef: true, unused: true */
773
774( function( window, factory ) {
775  /*global define: false, module: false */
776  'use strict';
777  // universal module definition
778  if ( typeof define == 'function' && define.amd ) {
779    // AMD
780    define( 'desandro-matches-selector/matches-selector',factory );
781  } else if ( typeof module == 'object' && module.exports ) {
782    // CommonJS
783    module.exports = factory();
784  } else {
785    // browser global
786    window.matchesSelector = factory();
787  }
788
789}( window, function factory() {
790  'use strict';
791
792  var matchesMethod = ( function() {
793    var ElemProto = window.Element.prototype;
794    // check for the standard method name first
795    if ( ElemProto.matches ) {
796      return 'matches';
797    }
798    // check un-prefixed
799    if ( ElemProto.matchesSelector ) {
800      return 'matchesSelector';
801    }
802    // check vendor prefixes
803    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
804
805    for ( var i=0; i < prefixes.length; i++ ) {
806      var prefix = prefixes[i];
807      var method = prefix + 'MatchesSelector';
808      if ( ElemProto[ method ] ) {
809        return method;
810      }
811    }
812  })();
813
814  return function matchesSelector( elem, selector ) {
815    return elem[ matchesMethod ]( selector );
816  };
817
818}));
819
820/**
821 * Fizzy UI utils v2.0.7
822 * MIT license
823 */
824
825/*jshint browser: true, undef: true, unused: true, strict: true */
826
827( function( window, factory ) {
828  // universal module definition
829  /*jshint strict: false */ /*globals define, module, require */
830
831  if ( typeof define == 'function' && define.amd ) {
832    // AMD
833    define( 'fizzy-ui-utils/utils',[
834      'desandro-matches-selector/matches-selector'
835    ], function( matchesSelector ) {
836      return factory( window, matchesSelector );
837    });
838  } else if ( typeof module == 'object' && module.exports ) {
839    // CommonJS
840    module.exports = factory(
841      window,
842      require('desandro-matches-selector')
843    );
844  } else {
845    // browser global
846    window.fizzyUIUtils = factory(
847      window,
848      window.matchesSelector
849    );
850  }
851
852}( window, function factory( window, matchesSelector ) {
853
854
855
856var utils = {};
857
858// ----- extend ----- //
859
860// extends objects
861utils.extend = function( a, b ) {
862  for ( var prop in b ) {
863    a[ prop ] = b[ prop ];
864  }
865  return a;
866};
867
868// ----- modulo ----- //
869
870utils.modulo = function( num, div ) {
871  return ( ( num % div ) + div ) % div;
872};
873
874// ----- makeArray ----- //
875
876var arraySlice = Array.prototype.slice;
877
878// turn element or nodeList into an array
879utils.makeArray = function( obj ) {
880  if ( Array.isArray( obj ) ) {
881    // use object if already an array
882    return obj;
883  }
884  // return empty array if undefined or null. #6
885  if ( obj === null || obj === undefined ) {
886    return [];
887  }
888
889  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
890  if ( isArrayLike ) {
891    // convert nodeList to array
892    return arraySlice.call( obj );
893  }
894
895  // array of single index
896  return [ obj ];
897};
898
899// ----- removeFrom ----- //
900
901utils.removeFrom = function( ary, obj ) {
902  var index = ary.indexOf( obj );
903  if ( index != -1 ) {
904    ary.splice( index, 1 );
905  }
906};
907
908// ----- getParent ----- //
909
910utils.getParent = function( elem, selector ) {
911  while ( elem.parentNode && elem != document.body ) {
912    elem = elem.parentNode;
913    if ( matchesSelector( elem, selector ) ) {
914      return elem;
915    }
916  }
917};
918
919// ----- getQueryElement ----- //
920
921// use element as selector string
922utils.getQueryElement = function( elem ) {
923  if ( typeof elem == 'string' ) {
924    return document.querySelector( elem );
925  }
926  return elem;
927};
928
929// ----- handleEvent ----- //
930
931// enable .ontype to trigger from .addEventListener( elem, 'type' )
932utils.handleEvent = function( event ) {
933  var method = 'on' + event.type;
934  if ( this[ method ] ) {
935    this[ method ]( event );
936  }
937};
938
939// ----- filterFindElements ----- //
940
941utils.filterFindElements = function( elems, selector ) {
942  // make array of elems
943  elems = utils.makeArray( elems );
944  var ffElems = [];
945
946  elems.forEach( function( elem ) {
947    // check that elem is an actual element
948    
948// START UNCODE EDIT
949    // if ( !( elem instanceof HTMLElement ) ) {
950    if ( !( elem instanceof HTMLElement ) && !SiteParameters.is_frontend_editor ) {
951    // END UNCODE EDIT
vendor: 23,480 bytes, lines 951-1863
951
952      return;
953    }
954    // add elem if no selector
955    if ( !selector ) {
956      ffElems.push( elem );
957      return;
958    }
959    // filter & find items if we have a selector
960    // filter
961    if ( matchesSelector( elem, selector ) ) {
962      ffElems.push( elem );
963    }
964    // find children
965    var childElems = elem.querySelectorAll( selector );
966    // concat childElems to filterFound array
967    for ( var i=0; i < childElems.length; i++ ) {
968      ffElems.push( childElems[i] );
969    }
970  });
971
972  return ffElems;
973};
974
975// ----- debounceMethod ----- //
976
977utils.debounceMethod = function( _class, methodName, threshold ) {
978  threshold = threshold || 100;
979  // original method
980  var method = _class.prototype[ methodName ];
981  var timeoutName = methodName + 'Timeout';
982
983  _class.prototype[ methodName ] = function() {
984    var timeout = this[ timeoutName ];
985    clearTimeout( timeout );
986
987    var args = arguments;
988    var _this = this;
989    this[ timeoutName ] = setTimeout( function() {
990      method.apply( _this, args );
991      delete _this[ timeoutName ];
992    }, threshold );
993  };
994};
995
996// ----- docReady ----- //
997
998utils.docReady = function( callback ) {
999  var readyState = document.readyState;
1000  if ( readyState == 'complete' || readyState == 'interactive' ) {
1001    // do async to allow for other scripts to run. metafizzy/flickity#441
1002    setTimeout( callback );
1003  } else {
1004    document.addEventListener( 'DOMContentLoaded', callback );
1005  }
1006};
1007
1008// ----- htmlInit ----- //
1009
1010// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1011utils.toDashed = function( str ) {
1012  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1013    return $1 + '-' + $2;
1014  }).toLowerCase();
1015};
1016
1017var console = window.console;
1018/**
1019 * allow user to initialize classes via [data-namespace] or .js-namespace class
1020 * htmlInit( Widget, 'widgetName' )
1021 * options are parsed from data-namespace-options
1022 */
1023utils.htmlInit = function( WidgetClass, namespace ) {
1024  utils.docReady( function() {
1025    var dashedNamespace = utils.toDashed( namespace );
1026    var dataAttr = 'data-' + dashedNamespace;
1027    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
1028    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
1029    var elems = utils.makeArray( dataAttrElems )
1030      .concat( utils.makeArray( jsDashElems ) );
1031    var dataOptionsAttr = dataAttr + '-options';
1032    var jQuery = window.jQuery;
1033
1034    elems.forEach( function( elem ) {
1035      var attr = elem.getAttribute( dataAttr ) ||
1036        elem.getAttribute( dataOptionsAttr );
1037      var options;
1038      try {
1039        options = attr && JSON.parse( attr );
1040      } catch ( error ) {
1041        // log error, do not initialize
1042        if ( console ) {
1043          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
1044          ': ' + error );
1045        }
1046        return;
1047      }
1048      // initialize
1049      var instance = new WidgetClass( elem, options );
1050      // make available via $().data('namespace')
1051      if ( jQuery ) {
1052        jQuery.data( elem, namespace, instance );
1053      }
1054    });
1055
1056  });
1057};
1058
1059// -----  ----- //
1060
1061return utils;
1062
1063}));
1064
1065/**
1066 * Outlayer Item
1067 */
1068
1069( function( window, factory ) {
1070  // universal module definition
1071  /* jshint strict: false */ /* globals define, module, require */
1072  if ( typeof define == 'function' && define.amd ) {
1073    // AMD - RequireJS
1074    define( 'outlayer/item',[
1075        'ev-emitter/ev-emitter',
1076        'get-size/get-size'
1077      ],
1078      factory
1079    );
1080  } else if ( typeof module == 'object' && module.exports ) {
1081    // CommonJS - Browserify, Webpack
1082    module.exports = factory(
1083      require('ev-emitter'),
1084      require('get-size')
1085    );
1086  } else {
1087    // browser global
1088    window.Outlayer = {};
1089    window.Outlayer.Item = factory(
1090      window.EvEmitter,
1091      window.getSize
1092    );
1093  }
1094
1095}( window, function factory( EvEmitter, getSize ) {
1096'use strict';
1097
1098// ----- helpers ----- //
1099
1100function isEmptyObj( obj ) {
1101  for ( var prop in obj ) {
1102    return false;
1103  }
1104  prop = null;
1105  return true;
1106}
1107
1108// -------------------------- CSS3 support -------------------------- //
1109
1110
1111var docElemStyle = document.documentElement.style;
1112
1113var transitionProperty = typeof docElemStyle.transition == 'string' ?
1114  'transition' : 'WebkitTransition';
1115var transformProperty = typeof docElemStyle.transform == 'string' ?
1116  'transform' : 'WebkitTransform';
1117
1118var transitionEndEvent = {
1119  WebkitTransition: 'webkitTransitionEnd',
1120  transition: 'transitionend'
1121}[ transitionProperty ];
1122
1123// cache all vendor properties that could have vendor prefix
1124var vendorProperties = {
1125  transform: transformProperty,
1126  transition: transitionProperty,
1127  transitionDuration: transitionProperty + 'Duration',
1128  transitionProperty: transitionProperty + 'Property',
1129  transitionDelay: transitionProperty + 'Delay'
1130};
1131
1132// -------------------------- Item -------------------------- //
1133
1134function Item( element, layout ) {
1135  if ( !element ) {
1136    return;
1137  }
1138
1139  this.element = element;
1140  // parent layout class, i.e. Masonry, Isotope, or Packery
1141  this.layout = layout;
1142  this.position = {
1143    x: 0,
1144    y: 0
1145  };
1146
1147  this._create();
1148}
1149
1150// inherit EvEmitter
1151var proto = Item.prototype = Object.create( EvEmitter.prototype );
1152proto.constructor = Item;
1153
1154proto._create = function() {
1155  // transition objects
1156  this._transn = {
1157    ingProperties: {},
1158    clean: {},
1159    onEnd: {}
1160  };
1161
1162  this.css({
1163    position: 'absolute'
1164  });
1165};
1166
1167// trigger specified handler for event type
1168proto.handleEvent = function( event ) {
1169  var method = 'on' + event.type;
1170  if ( this[ method ] ) {
1171    this[ method ]( event );
1172  }
1173};
1174
1175proto.getSize = function() {
1176  this.size = getSize( this.element );
1177};
1178
1179/**
1180 * apply CSS styles to element
1181 * @param {Object} style
1182 */
1183proto.css = function( style ) {
1184  var elemStyle = this.element.style;
1185
1186  for ( var prop in style ) {
1187    // use vendor property if available
1188    var supportedProp = vendorProperties[ prop ] || prop;
1189    elemStyle[ supportedProp ] = style[ prop ];
1190  }
1191};
1192
1193 // measure position, and sets it
1194proto.getPosition = function() {
1195  var style = getComputedStyle( this.element );
1196  var isOriginLeft = this.layout._getOption('originLeft');
1197  var isOriginTop = this.layout._getOption('originTop');
1198  var xValue = style[ isOriginLeft ? 'left' : 'right' ];
1199  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
1200  var x = parseFloat( xValue );
1201  var y = parseFloat( yValue );
1202  // convert percent to pixels
1203  var layoutSize = this.layout.size;
1204  if ( xValue.indexOf('%') != -1 ) {
1205    x = ( x / 100 ) * layoutSize.width;
1206  }
1207  if ( yValue.indexOf('%') != -1 ) {
1208    y = ( y / 100 ) * layoutSize.height;
1209  }
1210  // clean up 'auto' or other non-integer values
1211  x = isNaN( x ) ? 0 : x;
1212  y = isNaN( y ) ? 0 : y;
1213  // remove padding from measurement
1214  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1215  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1216
1217  this.position.x = x;
1218  this.position.y = y;
1219};
1220
1221// set settled position, apply padding
1222proto.layoutPosition = function() {
1223  var layoutSize = this.layout.size;
1224  var style = {};
1225  var isOriginLeft = this.layout._getOption('originLeft');
1226  var isOriginTop = this.layout._getOption('originTop');
1227
1228  // x
1229  var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
1230  var xProperty = isOriginLeft ? 'left' : 'right';
1231  var xResetProperty = isOriginLeft ? 'right' : 'left';
1232
1233  var x = this.position.x + layoutSize[ xPadding ];
1234  // set in percentage or pixels
1235  style[ xProperty ] = this.getXValue( x );
1236  // reset other property
1237  style[ xResetProperty ] = '';
1238
1239  // y
1240  var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
1241  var yProperty = isOriginTop ? 'top' : 'bottom';
1242  var yResetProperty = isOriginTop ? 'bottom' : 'top';
1243
1244  var y = this.position.y + layoutSize[ yPadding ];
1245  // set in percentage or pixels
1246  style[ yProperty ] = this.getYValue( y );
1247  // reset other property
1248  style[ yResetProperty ] = '';
1249
1250  this.css( style );
1251  this.emitEvent( 'layout', [ this ] );
1252};
1253
1254proto.getXValue = function( x ) {
1255  var isHorizontal = this.layout._getOption('horizontal');
1256  return this.layout.options.percentPosition && !isHorizontal ?
1257    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
1258};
1259
1260proto.getYValue = function( y ) {
1261  var isHorizontal = this.layout._getOption('horizontal');
1262  return this.layout.options.percentPosition && isHorizontal ?
1263    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
1264};
1265
1266proto._transitionTo = function( x, y ) {
1267  this.getPosition();
1268  // get current x & y from top/left
1269  var curX = this.position.x;
1270  var curY = this.position.y;
1271
1272  var didNotMove = x == this.position.x && y == this.position.y;
1273
1274  // save end position
1275  this.setPosition( x, y );
1276
1277  // if did not move and not transitioning, just go to layout
1278  if ( didNotMove && !this.isTransitioning ) {
1279    this.layoutPosition();
1280    return;
1281  }
1282
1283  var transX = x - curX;
1284  var transY = y - curY;
1285  var transitionStyle = {};
1286  transitionStyle.transform = this.getTranslate( transX, transY );
1287
1288  this.transition({
1289    to: transitionStyle,
1290    onTransitionEnd: {
1291      transform: this.layoutPosition
1292    },
1293    isCleaning: true
1294  });
1295};
1296
1297proto.getTranslate = function( x, y ) {
1298  // flip cooridinates if origin on right or bottom
1299  var isOriginLeft = this.layout._getOption('originLeft');
1300  var isOriginTop = this.layout._getOption('originTop');
1301  x = isOriginLeft ? x : -x;
1302  y = isOriginTop ? y : -y;
1303  return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1304};
1305
1306// non transition + transform support
1307proto.goTo = function( x, y ) {
1308  this.setPosition( x, y );
1309  this.layoutPosition();
1310};
1311
1312proto.moveTo = proto._transitionTo;
1313
1314proto.setPosition = function( x, y ) {
1315  this.position.x = parseFloat( x );
1316  this.position.y = parseFloat( y );
1317};
1318
1319// ----- transition ----- //
1320
1321/**
1322 * @param {Object} style - CSS
1323 * @param {Function} onTransitionEnd
1324 */
1325
1326// non transition, just trigger callback
1327proto._nonTransition = function( args ) {
1328  this.css( args.to );
1329  if ( args.isCleaning ) {
1330    this._removeStyles( args.to );
1331  }
1332  for ( var prop in args.onTransitionEnd ) {
1333    args.onTransitionEnd[ prop ].call( this );
1334  }
1335};
1336
1337/**
1338 * proper transition
1339 * @param {Object} args - arguments
1340 *   @param {Object} to - style to transition to
1341 *   @param {Object} from - style to start transition from
1342 *   @param {Boolean} isCleaning - removes transition styles after transition
1343 *   @param {Function} onTransitionEnd - callback
1344 */
1345proto.transition = function( args ) {
1346  // redirect to nonTransition if no transition duration
1347  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1348    this._nonTransition( args );
1349    return;
1350  }
1351
1352  var _transition = this._transn;
1353  // keep track of onTransitionEnd callback by css property
1354  for ( var prop in args.onTransitionEnd ) {
1355    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1356  }
1357  // keep track of properties that are transitioning
1358  for ( prop in args.to ) {
1359    _transition.ingProperties[ prop ] = true;
1360    // keep track of properties to clean up when transition is done
1361    if ( args.isCleaning ) {
1362      _transition.clean[ prop ] = true;
1363    }
1364  }
1365
1366  // set from styles
1367  if ( args.from ) {
1368    this.css( args.from );
1369    // force redraw. http://blog.alexmaccaw.com/css-transitions
1370    var h = this.element.offsetHeight;
1371    // hack for JSHint to hush about unused var
1372    h = null;
1373  }
1374  // enable transition
1375  this.enableTransition( args.to );
1376  // set styles that are transitioning
1377  this.css( args.to );
1378
1379  this.isTransitioning = true;
1380
1381};
1382
1383// dash before all cap letters, including first for
1384// WebkitTransform => -webkit-transform
1385function toDashedAll( str ) {
1386  return str.replace( /([A-Z])/g, function( $1 ) {
1387    return '-' + $1.toLowerCase();
1388  });
1389}
1390
1391var transitionProps = 'opacity,' + toDashedAll( transformProperty );
1392
1393proto.enableTransition = function(/* style */) {
1394  // HACK changing transitionProperty during a transition
1395  // will cause transition to jump
1396  if ( this.isTransitioning ) {
1397    return;
1398  }
1399
1400  // make `transition: foo, bar, baz` from style object
1401  // HACK un-comment this when enableTransition can work
1402  // while a transition is happening
1403  // var transitionValues = [];
1404  // for ( var prop in style ) {
1405  //   // dash-ify camelCased properties like WebkitTransition
1406  //   prop = vendorProperties[ prop ] || prop;
1407  //   transitionValues.push( toDashedAll( prop ) );
1408  // }
1409  // munge number to millisecond, to match stagger
1410  var duration = this.layout.options.transitionDuration;
1411  duration = typeof duration == 'number' ? duration + 'ms' : duration;
1412  // enable transition styles
1413  this.css({
1414    transitionProperty: transitionProps,
1415    transitionDuration: duration,
1416    transitionDelay: this.staggerDelay || 0
1417  });
1418  // listen for transition end event
1419  this.element.addEventListener( transitionEndEvent, this, false );
1420};
1421
1422// ----- events ----- //
1423
1424proto.onwebkitTransitionEnd = function( event ) {
1425  this.ontransitionend( event );
1426};
1427
1428proto.onotransitionend = function( event ) {
1429  this.ontransitionend( event );
1430};
1431
1432// properties that I munge to make my life easier
1433var dashedVendorProperties = {
1434  '-webkit-transform': 'transform'
1435};
1436
1437proto.ontransitionend = function( event ) {
1438  // disregard bubbled events from children
1439  if ( event.target !== this.element ) {
1440    return;
1441  }
1442  var _transition = this._transn;
1443  // get property name of transitioned property, convert to prefix-free
1444  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1445
1446  // remove property that has completed transitioning
1447  delete _transition.ingProperties[ propertyName ];
1448  // check if any properties are still transitioning
1449  if ( isEmptyObj( _transition.ingProperties ) ) {
1450    // all properties have completed transitioning
1451    this.disableTransition();
1452  }
1453  // clean style
1454  if ( propertyName in _transition.clean ) {
1455    // clean up style
1456    this.element.style[ event.propertyName ] = '';
1457    delete _transition.clean[ propertyName ];
1458  }
1459  // trigger onTransitionEnd callback
1460  if ( propertyName in _transition.onEnd ) {
1461    var onTransitionEnd = _transition.onEnd[ propertyName ];
1462    onTransitionEnd.call( this );
1463    delete _transition.onEnd[ propertyName ];
1464  }
1465
1466  this.emitEvent( 'transitionEnd', [ this ] );
1467};
1468
1469proto.disableTransition = function() {
1470  this.removeTransitionStyles();
1471  this.element.removeEventListener( transitionEndEvent, this, false );
1472  this.isTransitioning = false;
1473};
1474
1475/**
1476 * removes style property from element
1477 * @param {Object} style
1478**/
1479proto._removeStyles = function( style ) {
1480  // clean up transition styles
1481  var cleanStyle = {};
1482  for ( var prop in style ) {
1483    cleanStyle[ prop ] = '';
1484  }
1485  this.css( cleanStyle );
1486};
1487
1488var cleanTransitionStyle = {
1489  transitionProperty: '',
1490  transitionDuration: '',
1491  transitionDelay: ''
1492};
1493
1494proto.removeTransitionStyles = function() {
1495  // remove transition
1496  this.css( cleanTransitionStyle );
1497};
1498
1499// ----- stagger ----- //
1500
1501proto.stagger = function( delay ) {
1502  delay = isNaN( delay ) ? 0 : delay;
1503  this.staggerDelay = delay + 'ms';
1504};
1505
1506// ----- show/hide/remove ----- //
1507
1508// remove element from DOM
1509proto.removeElem = function() {
1510  this.element.parentNode.removeChild( this.element );
1511  // remove display: none
1512  this.css({ display: '' });
1513  this.emitEvent( 'remove', [ this ] );
1514};
1515
1516proto.remove = function() {
1517  // just remove element if no transition support or no transition
1518  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1519    this.removeElem();
1520    return;
1521  }
1522
1523  // start transition
1524  this.once( 'transitionEnd', function() {
1525    this.removeElem();
1526  });
1527  this.hide();
1528};
1529
1530proto.reveal = function() {
1531  delete this.isHidden;
1532  // remove display: none
1533  this.css({ display: '' });
1534
1535  var options = this.layout.options;
1536
1537  var onTransitionEnd = {};
1538  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
1539  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
1540
1541  this.transition({
1542    from: options.hiddenStyle,
1543    to: options.visibleStyle,
1544    isCleaning: true,
1545    onTransitionEnd: onTransitionEnd
1546  });
1547};
1548
1549proto.onRevealTransitionEnd = function() {
1550  // check if still visible
1551  // during transition, item may have been hidden
1552  if ( !this.isHidden ) {
1553    this.emitEvent('reveal');
1554  }
1555};
1556
1557/**
1558 * get style property use for hide/reveal transition end
1559 * @param {String} styleProperty - hiddenStyle/visibleStyle
1560 * @returns {String}
1561 */
1562proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
1563  var optionStyle = this.layout.options[ styleProperty ];
1564  // use opacity
1565  if ( optionStyle.opacity ) {
1566    return 'opacity';
1567  }
1568  // get first property
1569  for ( var prop in optionStyle ) {
1570    return prop;
1571  }
1572};
1573
1574proto.hide = function() {
1575  // set flag
1576  this.isHidden = true;
1577  // remove display: none
1578  this.css({ display: '' });
1579
1580  var options = this.layout.options;
1581
1582  var onTransitionEnd = {};
1583  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
1584  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
1585
1586  this.transition({
1587    from: options.visibleStyle,
1588    to: options.hiddenStyle,
1589    // keep hidden stuff hidden
1590    isCleaning: true,
1591    onTransitionEnd: onTransitionEnd
1592  });
1593};
1594
1595proto.onHideTransitionEnd = function() {
1596  // check if still hidden
1597  // during transition, item may have been un-hidden
1598  if ( this.isHidden ) {
1599    this.css({ display: 'none' });
1600    this.emitEvent('hide');
1601  }
1602};
1603
1604proto.destroy = function() {
1605  this.css({
1606    position: '',
1607    left: '',
1608    right: '',
1609    top: '',
1610    bottom: '',
1611    transition: '',
1612    transform: ''
1613  });
1614};
1615
1616return Item;
1617
1618}));
1619
1620/*!
1621 * Outlayer v2.1.1
1622 * the brains and guts of a layout library
1623 * MIT license
1624 */
1625
1626( function( window, factory ) {
1627  'use strict';
1628  // universal module definition
1629  /* jshint strict: false */ /* globals define, module, require */
1630  if ( typeof define == 'function' && define.amd ) {
1631    // AMD - RequireJS
1632    define( 'outlayer/outlayer',[
1633        'ev-emitter/ev-emitter',
1634        'get-size/get-size',
1635        'fizzy-ui-utils/utils',
1636        './item'
1637      ],
1638      function( EvEmitter, getSize, utils, Item ) {
1639        return factory( window, EvEmitter, getSize, utils, Item);
1640      }
1641    );
1642  } else if ( typeof module == 'object' && module.exports ) {
1643    // CommonJS - Browserify, Webpack
1644    module.exports = factory(
1645      window,
1646      require('ev-emitter'),
1647      require('get-size'),
1648      require('fizzy-ui-utils'),
1649      require('./item')
1650    );
1651  } else {
1652    // browser global
1653    window.Outlayer = factory(
1654      window,
1655      window.EvEmitter,
1656      window.getSize,
1657      window.fizzyUIUtils,
1658      window.Outlayer.Item
1659    );
1660  }
1661
1662}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
1663'use strict';
1664
1665// ----- vars ----- //
1666
1667var console = window.console;
1668var jQuery = window.jQuery;
1669var noop = function() {};
1670
1671// -------------------------- Outlayer -------------------------- //
1672
1673// globally unique identifiers
1674var GUID = 0;
1675// internal store of all Outlayer intances
1676var instances = {};
1677
1678
1679/**
1680 * @param {Element, String} element
1681 * @param {Object} options
1682 * @constructor
1683 */
1684function Outlayer( element, options ) {
1685  var queryElement = utils.getQueryElement( element );
1686  if ( !queryElement ) {
1687    if ( console ) {
1688      console.error( 'Bad element for ' + this.constructor.namespace +
1689        ': ' + ( queryElement || element ) );
1690    }
1691    return;
1692  }
1693  this.element = queryElement;
1694  // add jQuery
1695  if ( jQuery ) {
1696    this.$element = jQuery( this.element );
1697  }
1698
1699  // options
1700  this.options = utils.extend( {}, this.constructor.defaults );
1701  this.option( options );
1702
1703  // add id for Outlayer.getFromElement
1704  var id = ++GUID;
1705  this.element.outlayerGUID = id; // expando
1706  instances[ id ] = this; // associate via id
1707
1708  // kick it off
1709  this._create();
1710
1711  var isInitLayout = this._getOption('initLayout');
1712  if ( isInitLayout ) {
1713    this.layout();
1714  }
1715}
1716
1717// settings are for internal use only
1718Outlayer.namespace = 'outlayer';
1719Outlayer.Item = Item;
1720
1721// default options
1722Outlayer.defaults = {
1723  containerStyle: {
1724    position: 'relative'
1725  },
1726  initLayout: true,
1727  originLeft: true,
1728  originTop: true,
1729  resize: true,
1730  resizeContainer: true,
1731  // item options
1732  transitionDuration: '0.4s',
1733  hiddenStyle: {
1734    opacity: 0,
1735    transform: 'scale(0.001)'
1736  },
1737  visibleStyle: {
1738    opacity: 1,
1739    transform: 'scale(1)'
1740  }
1741};
1742
1743var proto = Outlayer.prototype;
1744// inherit EvEmitter
1745utils.extend( proto, EvEmitter.prototype );
1746
1747/**
1748 * set options
1749 * @param {Object} opts
1750 */
1751proto.option = function( opts ) {
1752  utils.extend( this.options, opts );
1753};
1754
1755/**
1756 * get backwards compatible option value, check old name
1757 */
1758proto._getOption = function( option ) {
1759  var oldOption = this.constructor.compatOptions[ option ];
1760  return oldOption && this.options[ oldOption ] !== undefined ?
1761    this.options[ oldOption ] : this.options[ option ];
1762};
1763
1764Outlayer.compatOptions = {
1765  // currentName: oldName
1766  initLayout: 'isInitLayout',
1767  horizontal: 'isHorizontal',
1768  layoutInstant: 'isLayoutInstant',
1769  originLeft: 'isOriginLeft',
1770  originTop: 'isOriginTop',
1771  resize: 'isResizeBound',
1772  resizeContainer: 'isResizingContainer'
1773};
1774
1775proto._create = function() {
1776  // get items from children
1777  this.reloadItems();
1778  // elements that affect layout, but are not laid out
1779  this.stamps = [];
1780  this.stamp( this.options.stamp );
1781  // set container style
1782  utils.extend( this.element.style, this.options.containerStyle );
1783
1784  // bind resize method
1785  var canBindResize = this._getOption('resize');
1786  if ( canBindResize ) {
1787    this.bindResize();
1788  }
1789};
1790
1791// goes through all children again and gets bricks in proper order
1792proto.reloadItems = function() {
1793  // collection of item elements
1794  this.items = this._itemize( this.element.children );
1795};
1796
1797
1798/**
1799 * turn elements into Outlayer.Items to be used in layout
1800 * @param {Array or NodeList or HTMLElement} elems
1801 * @returns {Array} items - collection of new Outlayer Items
1802 */
1803proto._itemize = function( elems ) {
1804
1805  var itemElems = this._filterFindItemElements( elems );
1806  var Item = this.constructor.Item;
1807
1808  // create new Outlayer Items for collection
1809  var items = [];
1810  for ( var i=0; i < itemElems.length; i++ ) {
1811    var elem = itemElems[i];
1812    var item = new Item( elem, this );
1813    items.push( item );
1814  }
1815
1816  return items;
1817};
1818
1819/**
1820 * get item elements to be used in layout
1821 * @param {Array or NodeList or HTMLElement} elems
1822 * @returns {Array} items - item elements
1823 */
1824proto._filterFindItemElements = function( elems ) {
1825  return utils.filterFindElements( elems, this.options.itemSelector );
1826};
1827
1828/**
1829 * getter method for getting item elements
1830 * @returns {Array} elems - collection of item elements
1831 */
1832proto.getItemElements = function() {
1833  return this.items.map( function( item ) {
1834    return item.element;
1835  });
1836};
1837
1838// ----- init & layout ----- //
1839
1840/**
1841 * lays out all items
1842 */
1843proto.layout = function() {
1844  this._resetLayout();
1845  this._manageStamps();
1846
1847  // don't animate first layout
1848  var layoutInstant = this._getOption('layoutInstant');
1849  var isInstant = layoutInstant !== undefined ?
1850    layoutInstant : !this._isLayoutInited;
1851  this.layoutItems( this.items, isInstant );
1852
1853  // flag for initalized
1854  this._isLayoutInited = true;
1855};
1856
1857// _init is alias for layout
1858proto._init = proto.layout;
1859
1860/**
1861 * logic before any new layout
1862 */
1863proto._resetLayout = function() {
vendor: 13,499 bytes, lines 1864-2432
1864  this.getSize();
1865};
1866
1867
1868proto.getSize = function() {
1869  this.size = getSize( this.element );
1870};
1871
1872/**
1873 * get measurement from option, for columnWidth, rowHeight, gutter
1874 * if option is String -> get element from selector string, & get size of element
1875 * if option is Element -> get size of element
1876 * else use option as a number
1877 *
1878 * @param {String} measurement
1879 * @param {String} size - width or height
1880 * @private
1881 */
1882proto._getMeasurement = function( measurement, size ) {
1883  var option = this.options[ measurement ];
1884  var elem;
1885  if ( !option ) {
1886    // default to 0
1887    this[ measurement ] = 0;
1888  } else {
1889    // use option as an element
1890    if ( typeof option == 'string' ) {
1891      elem = this.element.querySelector( option );
1892    } else if ( option instanceof HTMLElement ) {
1893      elem = option;
1894    }
1895    // use size of element, if element
1896    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
1897  }
1898};
1899
1900/**
1901 * layout a collection of item elements
1902 * @api public
1903 */
1904proto.layoutItems = function( items, isInstant ) {
1905  items = this._getItemsForLayout( items );
1906
1907  this._layoutItems( items, isInstant );
1908
1909  this._postLayout();
1910};
1911
1912/**
1913 * get the items to be laid out
1914 * you may want to skip over some items
1915 * @param {Array} items
1916 * @returns {Array} items
1917 */
1918proto._getItemsForLayout = function( items ) {
1919  return items.filter( function( item ) {
1920    return !item.isIgnored;
1921  });
1922};
1923
1924/**
1925 * layout items
1926 * @param {Array} items
1927 * @param {Boolean} isInstant
1928 */
1929proto._layoutItems = function( items, isInstant ) {
1930  this._emitCompleteOnItems( 'layout', items );
1931
1932  if ( !items || !items.length ) {
1933    // no items, emit event with empty array
1934    return;
1935  }
1936
1937  var queue = [];
1938
1939  items.forEach( function( item ) {
1940    // get x/y object from method
1941    var position = this._getItemLayoutPosition( item );
1942    // enqueue
1943    position.item = item;
1944    position.isInstant = isInstant || item.isLayoutInstant;
1945    queue.push( position );
1946  }, this );
1947
1948  this._processLayoutQueue( queue );
1949};
1950
1951/**
1952 * get item layout position
1953 * @param {Outlayer.Item} item
1954 * @returns {Object} x and y position
1955 */
1956proto._getItemLayoutPosition = function( /* item */ ) {
1957  return {
1958    x: 0,
1959    y: 0
1960  };
1961};
1962
1963/**
1964 * iterate over array and position each item
1965 * Reason being - separating this logic prevents 'layout invalidation'
1966 * thx @paul_irish
1967 * @param {Array} queue
1968 */
1969proto._processLayoutQueue = function( queue ) {
1970  this.updateStagger();
1971  queue.forEach( function( obj, i ) {
1972    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
1973  }, this );
1974};
1975
1976// set stagger from option in milliseconds number
1977proto.updateStagger = function() {
1978  var stagger = this.options.stagger;
1979  if ( stagger === null || stagger === undefined ) {
1980    this.stagger = 0;
1981    return;
1982  }
1983  this.stagger = getMilliseconds( stagger );
1984  return this.stagger;
1985};
1986
1987/**
1988 * Sets position of item in DOM
1989 * @param {Outlayer.Item} item
1990 * @param {Number} x - horizontal position
1991 * @param {Number} y - vertical position
1992 * @param {Boolean} isInstant - disables transitions
1993 */
1994proto._positionItem = function( item, x, y, isInstant, i ) {
1995  if ( isInstant ) {
1996    // if not transition, just set CSS
1997    item.goTo( x, y );
1998  } else {
1999    item.stagger( i * this.stagger );
2000    item.moveTo( x, y );
2001  }
2002};
2003
2004/**
2005 * Any logic you want to do after each layout,
2006 * i.e. size the container
2007 */
2008proto._postLayout = function() {
2009  this.resizeContainer();
2010};
2011
2012proto.resizeContainer = function() {
2013  var isResizingContainer = this._getOption('resizeContainer');
2014  if ( !isResizingContainer ) {
2015    return;
2016  }
2017  var size = this._getContainerSize();
2018  if ( size ) {
2019    this._setContainerMeasure( size.width, true );
2020    this._setContainerMeasure( size.height, false );
2021  }
2022};
2023
2024/**
2025 * Sets width or height of container if returned
2026 * @returns {Object} size
2027 *   @param {Number} width
2028 *   @param {Number} height
2029 */
2030proto._getContainerSize = noop;
2031
2032/**
2033 * @param {Number} measure - size of width or height
2034 * @param {Boolean} isWidth
2035 */
2036proto._setContainerMeasure = function( measure, isWidth ) {
2037  if ( measure === undefined ) {
2038    return;
2039  }
2040
2041  var elemSize = this.size;
2042  // add padding and border width if border box
2043  if ( elemSize.isBorderBox ) {
2044    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2045      elemSize.borderLeftWidth + elemSize.borderRightWidth :
2046      elemSize.paddingBottom + elemSize.paddingTop +
2047      elemSize.borderTopWidth + elemSize.borderBottomWidth;
2048  }
2049
2050  measure = Math.max( measure, 0 );
2051  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2052};
2053
2054/**
2055 * emit eventComplete on a collection of items events
2056 * @param {String} eventName
2057 * @param {Array} items - Outlayer.Items
2058 */
2059proto._emitCompleteOnItems = function( eventName, items ) {
2060  var _this = this;
2061  function onComplete() {
2062    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
2063  }
2064
2065  var count = items.length;
2066  if ( !items || !count ) {
2067    onComplete();
2068    return;
2069  }
2070
2071  var doneCount = 0;
2072  function tick() {
2073    doneCount++;
2074    if ( doneCount == count ) {
2075      onComplete();
2076    }
2077  }
2078
2079  // bind callback
2080  items.forEach( function( item ) {
2081    item.once( eventName, tick );
2082  });
2083};
2084
2085/**
2086 * emits events via EvEmitter and jQuery events
2087 * @param {String} type - name of event
2088 * @param {Event} event - original event
2089 * @param {Array} args - extra arguments
2090 */
2091proto.dispatchEvent = function( type, event, args ) {
2092  // add original event to arguments
2093  var emitArgs = event ? [ event ].concat( args ) : args;
2094  this.emitEvent( type, emitArgs );
2095
2096  if ( jQuery ) {
2097    // set this.$element
2098    this.$element = this.$element || jQuery( this.element );
2099    if ( event ) {
2100      // create jQuery event
2101      var $event = jQuery.Event( event );
2102      $event.type = type;
2103      this.$element.trigger( $event, args );
2104    } else {
2105      // just trigger with type if no event available
2106      this.$element.trigger( type, args );
2107    }
2108  }
2109};
2110
2111// -------------------------- ignore & stamps -------------------------- //
2112
2113
2114/**
2115 * keep item in collection, but do not lay it out
2116 * ignored items do not get skipped in layout
2117 * @param {Element} elem
2118 */
2119proto.ignore = function( elem ) {
2120  var item = this.getItem( elem );
2121  if ( item ) {
2122    item.isIgnored = true;
2123  }
2124};
2125
2126/**
2127 * return item to layout collection
2128 * @param {Element} elem
2129 */
2130proto.unignore = function( elem ) {
2131  var item = this.getItem( elem );
2132  if ( item ) {
2133    delete item.isIgnored;
2134  }
2135};
2136
2137/**
2138 * adds elements to stamps
2139 * @param {NodeList, Array, Element, or String} elems
2140 */
2141proto.stamp = function( elems ) {
2142  elems = this._find( elems );
2143  if ( !elems ) {
2144    return;
2145  }
2146
2147  this.stamps = this.stamps.concat( elems );
2148  // ignore
2149  elems.forEach( this.ignore, this );
2150};
2151
2152/**
2153 * removes elements to stamps
2154 * @param {NodeList, Array, or Element} elems
2155 */
2156proto.unstamp = function( elems ) {
2157  elems = this._find( elems );
2158  if ( !elems ){
2159    return;
2160  }
2161
2162  elems.forEach( function( elem ) {
2163    // filter out removed stamp elements
2164    utils.removeFrom( this.stamps, elem );
2165    this.unignore( elem );
2166  }, this );
2167};
2168
2169/**
2170 * finds child elements
2171 * @param {NodeList, Array, Element, or String} elems
2172 * @returns {Array} elems
2173 */
2174proto._find = function( elems ) {
2175  if ( !elems ) {
2176    return;
2177  }
2178  // if string, use argument as selector string
2179  if ( typeof elems == 'string' ) {
2180    elems = this.element.querySelectorAll( elems );
2181  }
2182  elems = utils.makeArray( elems );
2183  return elems;
2184};
2185
2186proto._manageStamps = function() {
2187  if ( !this.stamps || !this.stamps.length ) {
2188    return;
2189  }
2190
2191  this._getBoundingRect();
2192
2193  this.stamps.forEach( this._manageStamp, this );
2194};
2195
2196// update boundingLeft / Top
2197proto._getBoundingRect = function() {
2198  // get bounding rect for container element
2199  var boundingRect = this.element.getBoundingClientRect();
2200  var size = this.size;
2201  this._boundingRect = {
2202    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2203    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2204    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2205    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2206  };
2207};
2208
2209/**
2210 * @param {Element} stamp
2211**/
2212proto._manageStamp = noop;
2213
2214/**
2215 * get x/y position of element relative to container element
2216 * @param {Element} elem
2217 * @returns {Object} offset - has left, top, right, bottom
2218 */
2219proto._getElementOffset = function( elem ) {
2220  var boundingRect = elem.getBoundingClientRect();
2221  var thisRect = this._boundingRect;
2222  var size = getSize( elem );
2223  var offset = {
2224    left: boundingRect.left - thisRect.left - size.marginLeft,
2225    top: boundingRect.top - thisRect.top - size.marginTop,
2226    right: thisRect.right - boundingRect.right - size.marginRight,
2227    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2228  };
2229  return offset;
2230};
2231
2232// -------------------------- resize -------------------------- //
2233
2234// enable event handlers for listeners
2235// i.e. resize -> onresize
2236proto.handleEvent = utils.handleEvent;
2237
2238/**
2239 * Bind layout to window resizing
2240 */
2241proto.bindResize = function() {
2242  window.addEventListener( 'resize', this );
2243  this.isResizeBound = true;
2244};
2245
2246/**
2247 * Unbind layout to window resizing
2248 */
2249proto.unbindResize = function() {
2250  window.removeEventListener( 'resize', this );
2251  this.isResizeBound = false;
2252};
2253
2254proto.onresize = function() {
2255  this.resize();
2256};
2257
2258utils.debounceMethod( Outlayer, 'onresize', 100 );
2259
2260proto.resize = function() {
2261  // don't trigger if size did not change
2262  // or if resize was unbound. See #9
2263  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
2264    return;
2265  }
2266
2267  this.layout();
2268};
2269
2270/**
2271 * check if layout is needed post layout
2272 * @returns Boolean
2273 */
2274proto.needsResizeLayout = function() {
2275  var size = getSize( this.element );
2276  // check that this.size and size are there
2277  // IE8 triggers resize on body size change, so they might not be
2278  var hasSizes = this.size && size;
2279  return hasSizes && size.innerWidth !== this.size.innerWidth;
2280};
2281
2282// -------------------------- methods -------------------------- //
2283
2284/**
2285 * add items to Outlayer instance
2286 * @param {Array or NodeList or Element} elems
2287 * @returns {Array} items - Outlayer.Items
2288**/
2289proto.addItems = function( elems ) {
2290  var items = this._itemize( elems );
2291  // add items to collection
2292  if ( items.length ) {
2293    this.items = this.items.concat( items );
2294  }
2295  return items;
2296};
2297
2298/**
2299 * Layout newly-appended item elements
2300 * @param {Array or NodeList or Element} elems
2301 */
2302proto.appended = function( elems ) {
2303  var items = this.addItems( elems );
2304  if ( !items.length ) {
2305    return;
2306  }
2307  // layout and reveal just the new items
2308  this.layoutItems( items, true );
2309  this.reveal( items );
2310};
2311
2312/**
2313 * Layout prepended elements
2314 * @param {Array or NodeList or Element} elems
2315 */
2316proto.prepended = function( elems ) {
2317  var items = this._itemize( elems );
2318  if ( !items.length ) {
2319    return;
2320  }
2321  // add items to beginning of collection
2322  var previousItems = this.items.slice(0);
2323  this.items = items.concat( previousItems );
2324  // start new layout
2325  this._resetLayout();
2326  this._manageStamps();
2327  // layout new stuff without transition
2328  this.layoutItems( items, true );
2329  this.reveal( items );
2330  // layout previous items
2331  this.layoutItems( previousItems );
2332};
2333
2334/**
2335 * reveal a collection of items
2336 * @param {Array of Outlayer.Items} items
2337 */
2338proto.reveal = function( items ) {
2339  this._emitCompleteOnItems( 'reveal', items );
2340  if ( !items || !items.length ) {
2341    return;
2342  }
2343  var stagger = this.updateStagger();
2344  items.forEach( function( item, i ) {
2345    item.stagger( i * stagger );
2346    item.reveal();
2347  });
2348};
2349
2350/**
2351 * hide a collection of items
2352 * @param {Array of Outlayer.Items} items
2353 */
2354proto.hide = function( items ) {
2355  this._emitCompleteOnItems( 'hide', items );
2356  if ( !items || !items.length ) {
2357    return;
2358  }
2359  var stagger = this.updateStagger();
2360  items.forEach( function( item, i ) {
2361    item.stagger( i * stagger );
2362    item.hide();
2363  });
2364};
2365
2366/**
2367 * reveal item elements
2368 * @param {Array}, {Element}, {NodeList} items
2369 */
2370proto.revealItemElements = function( elems ) {
2371  var items = this.getItems( elems );
2372  this.reveal( items );
2373};
2374
2375/**
2376 * hide item elements
2377 * @param {Array}, {Element}, {NodeList} items
2378 */
2379proto.hideItemElements = function( elems ) {
2380  var items = this.getItems( elems );
2381  this.hide( items );
2382};
2383
2384/**
2385 * get Outlayer.Item, given an Element
2386 * @param {Element} elem
2387 * @param {Function} callback
2388 * @returns {Outlayer.Item} item
2389 */
2390proto.getItem = function( elem ) {
2391  // loop through items to get the one that matches
2392  for ( var i=0; i < this.items.length; i++ ) {
2393    var item = this.items[i];
2394    if ( item.element == elem ) {
2395      // return item
2396      return item;
2397    }
2398  }
2399};
2400
2401/**
2402 * get collection of Outlayer.Items, given Elements
2403 * @param {Array} elems
2404 * @returns {Array} items - Outlayer.Items
2405 */
2406proto.getItems = function( elems ) {
2407  elems = utils.makeArray( elems );
2408  var items = [];
2409  elems.forEach( function( elem ) {
2410    var item = this.getItem( elem );
2411    if ( item ) {
2412      items.push( item );
2413    }
2414  }, this );
2415
2416  return items;
2417};
2418
2419/**
2420 * remove element(s) from instance and DOM
2421 * @param {Array or NodeList or Element} elems
2422 */
2423proto.remove = function( elems ) {
2424  var removeItems = this.getItems( elems );
2425
2426  this._emitCompleteOnItems( 'remove', removeItems );
2427
2428  // bail if no items to remove
2429  if ( !removeItems || !removeItems.length ) {
2430    return;
2431  }
2432
vendor: 38,285 bytes, lines 2433-3856
2433  removeItems.forEach( function( item ) {
2434    item.remove();
2435    // remove item from collection
2436    utils.removeFrom( this.items, item );
2437  }, this );
2438};
2439
2440// ----- destroy ----- //
2441
2442// remove and disable Outlayer instance
2443proto.destroy = function() {
2444  // clean up dynamic styles
2445  var style = this.element.style;
2446  style.height = '';
2447  style.position = '';
2448  style.width = '';
2449  // destroy items
2450  this.items.forEach( function( item ) {
2451    item.destroy();
2452  });
2453
2454  this.unbindResize();
2455
2456  var id = this.element.outlayerGUID;
2457  delete instances[ id ]; // remove reference to instance by id
2458  delete this.element.outlayerGUID;
2459  // remove data for jQuery
2460  if ( jQuery ) {
2461    jQuery.removeData( this.element, this.constructor.namespace );
2462  }
2463
2464};
2465
2466// -------------------------- data -------------------------- //
2467
2468/**
2469 * get Outlayer instance from element
2470 * @param {Element} elem
2471 * @returns {Outlayer}
2472 */
2473Outlayer.data = function( elem ) {
2474  elem = utils.getQueryElement( elem );
2475  var id = elem && elem.outlayerGUID;
2476  return id && instances[ id ];
2477};
2478
2479
2480// -------------------------- create Outlayer class -------------------------- //
2481
2482/**
2483 * create a layout class
2484 * @param {String} namespace
2485 */
2486Outlayer.create = function( namespace, options ) {
2487  // sub-class Outlayer
2488  var Layout = subclass( Outlayer );
2489  // apply new options and compatOptions
2490  Layout.defaults = utils.extend( {}, Outlayer.defaults );
2491  utils.extend( Layout.defaults, options );
2492  Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );
2493
2494  Layout.namespace = namespace;
2495
2496  Layout.data = Outlayer.data;
2497
2498  // sub-class Item
2499  Layout.Item = subclass( Item );
2500
2501  // -------------------------- declarative -------------------------- //
2502
2503  utils.htmlInit( Layout, namespace );
2504
2505  // -------------------------- jQuery bridge -------------------------- //
2506
2507  // make into jQuery plugin
2508  if ( jQuery && jQuery.bridget ) {
2509    jQuery.bridget( namespace, Layout );
2510  }
2511
2512  return Layout;
2513};
2514
2515function subclass( Parent ) {
2516  function SubClass() {
2517    Parent.apply( this, arguments );
2518  }
2519
2520  SubClass.prototype = Object.create( Parent.prototype );
2521  SubClass.prototype.constructor = SubClass;
2522
2523  return SubClass;
2524}
2525
2526// ----- helpers ----- //
2527
2528// how many milliseconds are in each unit
2529var msUnits = {
2530  ms: 1,
2531  s: 1000
2532};
2533
2534// munge time-like parameter into millisecond number
2535// '0.4s' -> 40
2536function getMilliseconds( time ) {
2537  if ( typeof time == 'number' ) {
2538    return time;
2539  }
2540  var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
2541  var num = matches && matches[1];
2542  var unit = matches && matches[2];
2543  if ( !num.length ) {
2544    return 0;
2545  }
2546  num = parseFloat( num );
2547  var mult = msUnits[ unit ] || 1;
2548  return num * mult;
2549}
2550
2551// ----- fin ----- //
2552
2553// back in global
2554Outlayer.Item = Item;
2555
2556return Outlayer;
2557
2558}));
2559
2560/**
2561 * Isotope Item
2562**/
2563
2564( function( window, factory ) {
2565  // universal module definition
2566  /* jshint strict: false */ /*globals define, module, require */
2567  if ( typeof define == 'function' && define.amd ) {
2568    // AMD
2569    define( 'isotope-layout/js/item',[
2570        'outlayer/outlayer'
2571      ],
2572      factory );
2573  } else if ( typeof module == 'object' && module.exports ) {
2574    // CommonJS
2575    module.exports = factory(
2576      require('outlayer')
2577    );
2578  } else {
2579    // browser global
2580    window.Isotope = window.Isotope || {};
2581    window.Isotope.Item = factory(
2582      window.Outlayer
2583    );
2584  }
2585
2586}( window, function factory( Outlayer ) {
2587'use strict';
2588
2589// -------------------------- Item -------------------------- //
2590
2591// sub-class Outlayer Item
2592function Item() {
2593  Outlayer.Item.apply( this, arguments );
2594}
2595
2596var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
2597
2598var _create = proto._create;
2599proto._create = function() {
2600  // assign id, used for original-order sorting
2601  this.id = this.layout.itemGUID++;
2602  _create.call( this );
2603  this.sortData = {};
2604};
2605
2606proto.updateSortData = function() {
2607  if ( this.isIgnored ) {
2608    return;
2609  }
2610  // default sorters
2611  this.sortData.id = this.id;
2612  // for backward compatibility
2613  this.sortData['original-order'] = this.id;
2614  this.sortData.random = Math.random();
2615  // go thru getSortData obj and apply the sorters
2616  var getSortData = this.layout.options.getSortData;
2617  var sorters = this.layout._sorters;
2618  for ( var key in getSortData ) {
2619    var sorter = sorters[ key ];
2620    this.sortData[ key ] = sorter( this.element, this );
2621  }
2622};
2623
2624var _destroy = proto.destroy;
2625proto.destroy = function() {
2626  // call super
2627  _destroy.apply( this, arguments );
2628  // reset display, #741
2629  this.css({
2630    display: ''
2631  });
2632};
2633
2634return Item;
2635
2636}));
2637
2638/**
2639 * Isotope LayoutMode
2640 */
2641
2642( function( window, factory ) {
2643  // universal module definition
2644  /* jshint strict: false */ /*globals define, module, require */
2645  if ( typeof define == 'function' && define.amd ) {
2646    // AMD
2647    define( 'isotope-layout/js/layout-mode',[
2648        'get-size/get-size',
2649        'outlayer/outlayer'
2650      ],
2651      factory );
2652  } else if ( typeof module == 'object' && module.exports ) {
2653    // CommonJS
2654    module.exports = factory(
2655      require('get-size'),
2656      require('outlayer')
2657    );
2658  } else {
2659    // browser global
2660    window.Isotope = window.Isotope || {};
2661    window.Isotope.LayoutMode = factory(
2662      window.getSize,
2663      window.Outlayer
2664    );
2665  }
2666
2667}( window, function factory( getSize, Outlayer ) {
2668  'use strict';
2669
2670  // layout mode class
2671  function LayoutMode( isotope ) {
2672    this.isotope = isotope;
2673    // link properties
2674    if ( isotope ) {
2675      this.options = isotope.options[ this.namespace ];
2676      this.element = isotope.element;
2677      this.items = isotope.filteredItems;
2678      this.size = isotope.size;
2679    }
2680  }
2681
2682  var proto = LayoutMode.prototype;
2683
2684  /**
2685   * some methods should just defer to default Outlayer method
2686   * and reference the Isotope instance as `this`
2687  **/
2688  var facadeMethods = [
2689    '_resetLayout',
2690    '_getItemLayoutPosition',
2691    '_manageStamp',
2692    '_getContainerSize',
2693    '_getElementOffset',
2694    'needsResizeLayout',
2695    '_getOption'
2696  ];
2697
2698  facadeMethods.forEach( function( methodName ) {
2699    proto[ methodName ] = function() {
2700      return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
2701    };
2702  });
2703
2704  // -----  ----- //
2705
2706  // for horizontal layout modes, check vertical size
2707  proto.needsVerticalResizeLayout = function() {
2708    // don't trigger if size did not change
2709    var size = getSize( this.isotope.element );
2710    // check that this.size and size are there
2711    // IE8 triggers resize on body size change, so they might not be
2712    var hasSizes = this.isotope.size && size;
2713    return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
2714  };
2715
2716  // ----- measurements ----- //
2717
2718  proto._getMeasurement = function() {
2719    this.isotope._getMeasurement.apply( this, arguments );
2720  };
2721
2722  proto.getColumnWidth = function() {
2723    this.getSegmentSize( 'column', 'Width' );
2724  };
2725
2726  proto.getRowHeight = function() {
2727    this.getSegmentSize( 'row', 'Height' );
2728  };
2729
2730  /**
2731   * get columnWidth or rowHeight
2732   * segment: 'column' or 'row'
2733   * size 'Width' or 'Height'
2734  **/
2735  proto.getSegmentSize = function( segment, size ) {
2736    var segmentName = segment + size;
2737    var outerSize = 'outer' + size;
2738    // columnWidth / outerWidth // rowHeight / outerHeight
2739    this._getMeasurement( segmentName, outerSize );
2740    // got rowHeight or columnWidth, we can chill
2741    if ( this[ segmentName ] ) {
2742      return;
2743    }
2744    // fall back to item of first element
2745    var firstItemSize = this.getFirstItemSize();
2746    this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
2747      // or size of container
2748      this.isotope.size[ 'inner' + size ];
2749  };
2750
2751  proto.getFirstItemSize = function() {
2752    var firstItem = this.isotope.filteredItems[0];
2753    return firstItem && firstItem.element && getSize( firstItem.element );
2754  };
2755
2756  // ----- methods that should reference isotope ----- //
2757
2758  proto.layout = function() {
2759    this.isotope.layout.apply( this.isotope, arguments );
2760  };
2761
2762  proto.getSize = function() {
2763    this.isotope.getSize();
2764    this.size = this.isotope.size;
2765  };
2766
2767  // -------------------------- create -------------------------- //
2768
2769  LayoutMode.modes = {};
2770
2771  LayoutMode.create = function( namespace, options ) {
2772
2773    function Mode() {
2774      LayoutMode.apply( this, arguments );
2775    }
2776
2777    Mode.prototype = Object.create( proto );
2778    Mode.prototype.constructor = Mode;
2779
2780    // default options
2781    if ( options ) {
2782      Mode.options = options;
2783    }
2784
2785    Mode.prototype.namespace = namespace;
2786    // register in Isotope
2787    LayoutMode.modes[ namespace ] = Mode;
2788
2789    return Mode;
2790  };
2791
2792  return LayoutMode;
2793
2794}));
2795
2796/*!
2797 * Masonry v4.2.1
2798 * Cascading grid layout library
2799 * https://masonry.desandro.com
2800 * MIT License
2801 * by David DeSandro
2802 */
2803
2804( function( window, factory ) {
2805  // universal module definition
2806  /* jshint strict: false */ /*globals define, module, require */
2807  if ( typeof define == 'function' && define.amd ) {
2808    // AMD
2809    define( 'masonry-layout/masonry',[
2810        'outlayer/outlayer',
2811        'get-size/get-size'
2812      ],
2813      factory );
2814  } else if ( typeof module == 'object' && module.exports ) {
2815    // CommonJS
2816    module.exports = factory(
2817      require('outlayer'),
2818      require('get-size')
2819    );
2820  } else {
2821    // browser global
2822    window.Masonry = factory(
2823      window.Outlayer,
2824      window.getSize
2825    );
2826  }
2827
2828}( window, function factory( Outlayer, getSize ) {
2829
2830
2831
2832// -------------------------- masonryDefinition -------------------------- //
2833
2834  // create an Outlayer layout class
2835  var Masonry = Outlayer.create('masonry');
2836  // isFitWidth -> fitWidth
2837  Masonry.compatOptions.fitWidth = 'isFitWidth';
2838
2839  var proto = Masonry.prototype;
2840
2841  proto._resetLayout = function() {
2842    this.getSize();
2843    this._getMeasurement( 'columnWidth', 'outerWidth' );
2844    this._getMeasurement( 'gutter', 'outerWidth' );
2845    this.measureColumns();
2846
2847    // reset column Y
2848    this.colYs = [];
2849    for ( var i=0; i < this.cols; i++ ) {
2850      this.colYs.push( 0 );
2851    }
2852
2853    this.maxY = 0;
2854    this.horizontalColIndex = 0;
2855  };
2856
2857  proto.measureColumns = function() {
2858    this.getContainerWidth();
2859    // if columnWidth is 0, default to outerWidth of first item
2860    if ( !this.columnWidth ) {
2861      var firstItem = this.items[0];
2862      var firstItemElem = firstItem && firstItem.element;
2863      // columnWidth fall back to item of first element
2864      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
2865        // if first elem has no width, default to size of container
2866        this.containerWidth;
2867    }
2868
2869    var columnWidth = this.columnWidth += this.gutter;
2870
2871    // calculate columns
2872    var containerWidth = this.containerWidth + this.gutter;
2873    var cols = containerWidth / columnWidth;
2874    // fix rounding errors, typically with gutters
2875    var excess = columnWidth - containerWidth % columnWidth;
2876    // if overshoot is less than a pixel, round up, otherwise floor it
2877    var mathMethod = excess && excess < 1 ? 'round' : 'floor';
2878    cols = Math[ mathMethod ]( cols );
2879    this.cols = Math.max( cols, 1 );
2880  };
2881
2882  proto.getContainerWidth = function() {
2883    // container is parent if fit width
2884    var isFitWidth = this._getOption('fitWidth');
2885    var container = isFitWidth ? this.element.parentNode : this.element;
2886    // check that this.size and size are there
2887    // IE8 triggers resize on body size change, so they might not be
2888    var size = getSize( container );
2889    this.containerWidth = size && size.innerWidth;
2890  };
2891
2892  proto._getItemLayoutPosition = function( item ) {
2893    item.getSize();
2894    // how many columns does this brick span
2895    var remainder = item.size.outerWidth % this.columnWidth;
2896    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
2897    // round if off by 1 pixel, otherwise use ceil
2898    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
2899    colSpan = Math.min( colSpan, this.cols );
2900    // use horizontal or top column position
2901    var colPosMethod = this.options.horizontalOrder ?
2902      '_getHorizontalColPosition' : '_getTopColPosition';
2903    var colPosition = this[ colPosMethod ]( colSpan, item );
2904    // position the brick
2905    var position = {
2906      x: this.columnWidth * colPosition.col,
2907      y: colPosition.y
2908    };
2909    // apply setHeight to necessary columns
2910    var setHeight = colPosition.y + item.size.outerHeight;
2911    var setMax = colSpan + colPosition.col;
2912    for ( var i = colPosition.col; i < setMax; i++ ) {
2913      this.colYs[i] = setHeight;
2914    }
2915
2916    return position;
2917  };
2918
2919  proto._getTopColPosition = function( colSpan ) {
2920    var colGroup = this._getTopColGroup( colSpan );
2921    // get the minimum Y value from the columns
2922    var minimumY = Math.min.apply( Math, colGroup );
2923
2924    return {
2925      col: colGroup.indexOf( minimumY ),
2926      y: minimumY,
2927    };
2928  };
2929
2930  /**
2931   * @param {Number} colSpan - number of columns the element spans
2932   * @returns {Array} colGroup
2933   */
2934  proto._getTopColGroup = function( colSpan ) {
2935    if ( colSpan < 2 ) {
2936      // if brick spans only one column, use all the column Ys
2937      return this.colYs;
2938    }
2939
2940    var colGroup = [];
2941    // how many different places could this brick fit horizontally
2942    var groupCount = this.cols + 1 - colSpan;
2943    // for each group potential horizontal position
2944    for ( var i = 0; i < groupCount; i++ ) {
2945      colGroup[i] = this._getColGroupY( i, colSpan );
2946    }
2947    return colGroup;
2948  };
2949
2950  proto._getColGroupY = function( col, colSpan ) {
2951    if ( colSpan < 2 ) {
2952      return this.colYs[ col ];
2953    }
2954    // make an array of colY values for that one group
2955    var groupColYs = this.colYs.slice( col, col + colSpan );
2956    // and get the max value of the array
2957    return Math.max.apply( Math, groupColYs );
2958  };
2959
2960  // get column position based on horizontal index. #873
2961  proto._getHorizontalColPosition = function( colSpan, item ) {
2962    var col = this.horizontalColIndex % this.cols;
2963    var isOver = colSpan > 1 && col + colSpan > this.cols;
2964    // shift to next row if item can't fit on current row
2965    col = isOver ? 0 : col;
2966    // don't let zero-size items take up space
2967    var hasSize = item.size.outerWidth && item.size.outerHeight;
2968    this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
2969
2970    return {
2971      col: col,
2972      y: this._getColGroupY( col, colSpan ),
2973    };
2974  };
2975
2976  proto._manageStamp = function( stamp ) {
2977    var stampSize = getSize( stamp );
2978    var offset = this._getElementOffset( stamp );
2979    // get the columns that this stamp affects
2980    var isOriginLeft = this._getOption('originLeft');
2981    var firstX = isOriginLeft ? offset.left : offset.right;
2982    var lastX = firstX + stampSize.outerWidth;
2983    var firstCol = Math.floor( firstX / this.columnWidth );
2984    firstCol = Math.max( 0, firstCol );
2985    var lastCol = Math.floor( lastX / this.columnWidth );
2986    // lastCol should not go over if multiple of columnWidth #425
2987    lastCol -= lastX % this.columnWidth ? 0 : 1;
2988    lastCol = Math.min( this.cols - 1, lastCol );
2989    // set colYs to bottom of the stamp
2990
2991    var isOriginTop = this._getOption('originTop');
2992    var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
2993      stampSize.outerHeight;
2994    for ( var i = firstCol; i <= lastCol; i++ ) {
2995      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
2996    }
2997  };
2998
2999  proto._getContainerSize = function() {
3000    this.maxY = Math.max.apply( Math, this.colYs );
3001    var size = {
3002      height: this.maxY
3003    };
3004
3005    if ( this._getOption('fitWidth') ) {
3006      size.width = this._getContainerFitWidth();
3007    }
3008
3009    return size;
3010  };
3011
3012  proto._getContainerFitWidth = function() {
3013    var unusedCols = 0;
3014    // count unused columns
3015    var i = this.cols;
3016    while ( --i ) {
3017      if ( this.colYs[i] !== 0 ) {
3018        break;
3019      }
3020      unusedCols++;
3021    }
3022    // fit container to columns that have been used
3023    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
3024  };
3025
3026  proto.needsResizeLayout = function() {
3027    var previousWidth = this.containerWidth;
3028    this.getContainerWidth();
3029    return previousWidth != this.containerWidth;
3030  };
3031
3032  return Masonry;
3033
3034}));
3035
3036/*!
3037 * Masonry layout mode
3038 * sub-classes Masonry
3039 * https://masonry.desandro.com
3040 */
3041
3042( function( window, factory ) {
3043  // universal module definition
3044  /* jshint strict: false */ /*globals define, module, require */
3045  if ( typeof define == 'function' && define.amd ) {
3046    // AMD
3047    define( 'isotope-layout/js/layout-modes/masonry',[
3048        '../layout-mode',
3049        'masonry-layout/masonry'
3050      ],
3051      factory );
3052  } else if ( typeof module == 'object' && module.exports ) {
3053    // CommonJS
3054    module.exports = factory(
3055      require('../layout-mode'),
3056      require('masonry-layout')
3057    );
3058  } else {
3059    // browser global
3060    factory(
3061      window.Isotope.LayoutMode,
3062      window.Masonry
3063    );
3064  }
3065
3066}( window, function factory( LayoutMode, Masonry ) {
3067'use strict';
3068
3069// -------------------------- masonryDefinition -------------------------- //
3070
3071  // create an Outlayer layout class
3072  var MasonryMode = LayoutMode.create('masonry');
3073
3074  var proto = MasonryMode.prototype;
3075
3076  var keepModeMethods = {
3077    _getElementOffset: true,
3078    layout: true,
3079    _getMeasurement: true
3080  };
3081
3082  // inherit Masonry prototype
3083  for ( var method in Masonry.prototype ) {
3084    // do not inherit mode methods
3085    if ( !keepModeMethods[ method ] ) {
3086      proto[ method ] = Masonry.prototype[ method ];
3087    }
3088  }
3089
3090  var measureColumns = proto.measureColumns;
3091  proto.measureColumns = function() {
3092    // set items, used if measuring first item
3093    this.items = this.isotope.filteredItems;
3094    measureColumns.call( this );
3095  };
3096
3097  // point to mode options for fitWidth
3098  var _getOption = proto._getOption;
3099  proto._getOption = function( option ) {
3100    if ( option == 'fitWidth' ) {
3101      return this.options.isFitWidth !== undefined ?
3102        this.options.isFitWidth : this.options.fitWidth;
3103    }
3104    return _getOption.apply( this.isotope, arguments );
3105  };
3106
3107  return MasonryMode;
3108
3109}));
3110
3111/**
3112 * fitRows layout mode
3113 */
3114
3115( function( window, factory ) {
3116  // universal module definition
3117  /* jshint strict: false */ /*globals define, module, require */
3118  if ( typeof define == 'function' && define.amd ) {
3119    // AMD
3120    define( 'isotope-layout/js/layout-modes/fit-rows',[
3121        '../layout-mode'
3122      ],
3123      factory );
3124  } else if ( typeof exports == 'object' ) {
3125    // CommonJS
3126    module.exports = factory(
3127      require('../layout-mode')
3128    );
3129  } else {
3130    // browser global
3131    factory(
3132      window.Isotope.LayoutMode
3133    );
3134  }
3135
3136}( window, function factory( LayoutMode ) {
3137'use strict';
3138
3139var FitRows = LayoutMode.create('fitRows');
3140
3141var proto = FitRows.prototype;
3142
3143proto._resetLayout = function() {
3144  this.x = 0;
3145  this.y = 0;
3146  this.maxY = 0;
3147  this._getMeasurement( 'gutter', 'outerWidth' );
3148};
3149
3150proto._getItemLayoutPosition = function( item ) {
3151  item.getSize();
3152
3153  var itemWidth = item.size.outerWidth + this.gutter;
3154  // if this element cannot fit in the current row
3155  var containerWidth = this.isotope.size.innerWidth + this.gutter;
3156  if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
3157    this.x = 0;
3158    this.y = this.maxY;
3159  }
3160
3161  var position = {
3162    x: this.x,
3163    y: this.y
3164  };
3165
3166  this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
3167  this.x += itemWidth;
3168
3169  return position;
3170};
3171
3172proto._getContainerSize = function() {
3173  return { height: this.maxY };
3174};
3175
3176return FitRows;
3177
3178}));
3179
3180/**
3181 * vertical layout mode
3182 */
3183
3184( function( window, factory ) {
3185  // universal module definition
3186  /* jshint strict: false */ /*globals define, module, require */
3187  if ( typeof define == 'function' && define.amd ) {
3188    // AMD
3189    define( 'isotope-layout/js/layout-modes/vertical',[
3190        '../layout-mode'
3191      ],
3192      factory );
3193  } else if ( typeof module == 'object' && module.exports ) {
3194    // CommonJS
3195    module.exports = factory(
3196      require('../layout-mode')
3197    );
3198  } else {
3199    // browser global
3200    factory(
3201      window.Isotope.LayoutMode
3202    );
3203  }
3204
3205}( window, function factory( LayoutMode ) {
3206'use strict';
3207
3208var Vertical = LayoutMode.create( 'vertical', {
3209  horizontalAlignment: 0
3210});
3211
3212var proto = Vertical.prototype;
3213
3214proto._resetLayout = function() {
3215  this.y = 0;
3216};
3217
3218proto._getItemLayoutPosition = function( item ) {
3219  item.getSize();
3220  var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
3221    this.options.horizontalAlignment;
3222  var y = this.y;
3223  this.y += item.size.outerHeight;
3224  return { x: x, y: y };
3225};
3226
3227proto._getContainerSize = function() {
3228  return { height: this.y };
3229};
3230
3231return Vertical;
3232
3233}));
3234
3235/*!
3236 * Isotope v3.0.6
3237 *
3238 * Licensed GPLv3 for open source use
3239 * or Isotope Commercial License for commercial use
3240 *
3241 * https://isotope.metafizzy.co
3242 * Copyright 2010-2018 Metafizzy
3243 */
3244
3245( function( window, factory ) {
3246  // universal module definition
3247  /* jshint strict: false */ /*globals define, module, require */
3248  if ( typeof define == 'function' && define.amd ) {
3249    // AMD
3250    define( [
3251        'outlayer/outlayer',
3252        'get-size/get-size',
3253        'desandro-matches-selector/matches-selector',
3254        'fizzy-ui-utils/utils',
3255        'isotope-layout/js/item',
3256        'isotope-layout/js/layout-mode',
3257        // include default layout modes
3258        'isotope-layout/js/layout-modes/masonry',
3259        'isotope-layout/js/layout-modes/fit-rows',
3260        'isotope-layout/js/layout-modes/vertical'
3261      ],
3262      function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
3263        return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
3264      });
3265  } else if ( typeof module == 'object' && module.exports ) {
3266    // CommonJS
3267    module.exports = factory(
3268      window,
3269      require('outlayer'),
3270      require('get-size'),
3271      require('desandro-matches-selector'),
3272      require('fizzy-ui-utils'),
3273      require('isotope-layout/js/item'),
3274      require('isotope-layout/js/layout-mode'),
3275      // include default layout modes
3276      require('isotope-layout/js/layout-modes/masonry'),
3277      require('isotope-layout/js/layout-modes/fit-rows'),
3278      require('isotope-layout/js/layout-modes/vertical')
3279    );
3280  } else {
3281    // browser global
3282    window.Isotope = factory(
3283      window,
3284      window.Outlayer,
3285      window.getSize,
3286      window.matchesSelector,
3287      window.fizzyUIUtils,
3288      window.Isotope.Item,
3289      window.Isotope.LayoutMode
3290    );
3291  }
3292
3293}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
3294  Item, LayoutMode ) {
3295
3296
3297
3298// -------------------------- vars -------------------------- //
3299
3300var jQuery = window.jQuery;
3301
3302// -------------------------- helpers -------------------------- //
3303
3304var trim = String.prototype.trim ?
3305  function( str ) {
3306    return str.trim();
3307  } :
3308  function( str ) {
3309    return str.replace( /^\s+|\s+$/g, '' );
3310  };
3311
3312// -------------------------- isotopeDefinition -------------------------- //
3313
3314  // create an Outlayer layout class
3315  var Isotope = Outlayer.create( 'isotope', {
3316    layoutMode: 'masonry',
3317    isJQueryFiltering: true,
3318    sortAscending: true
3319  });
3320
3321  Isotope.Item = Item;
3322  Isotope.LayoutMode = LayoutMode;
3323
3324  var proto = Isotope.prototype;
3325
3326  proto._create = function() {
3327    this.itemGUID = 0;
3328    // functions that sort items
3329    this._sorters = {};
3330    this._getSorters();
3331    // call super
3332    Outlayer.prototype._create.call( this );
3333
3334    // create layout modes
3335    this.modes = {};
3336    // start filteredItems with all items
3337    this.filteredItems = this.items;
3338    // keep of track of sortBys
3339    this.sortHistory = [ 'original-order' ];
3340    // create from registered layout modes
3341    for ( var name in LayoutMode.modes ) {
3342      this._initLayoutMode( name );
3343    }
3344  };
3345
3346  proto.reloadItems = function() {
3347    // reset item ID counter
3348    this.itemGUID = 0;
3349    // call super
3350    Outlayer.prototype.reloadItems.call( this );
3351  };
3352
3353  proto._itemize = function() {
3354    var items = Outlayer.prototype._itemize.apply( this, arguments );
3355    // assign ID for original-order
3356    for ( var i=0; i < items.length; i++ ) {
3357      var item = items[i];
3358      item.id = this.itemGUID++;
3359    }
3360    this._updateItemsSortData( items );
3361    return items;
3362  };
3363
3364
3365  // -------------------------- layout -------------------------- //
3366
3367  proto._initLayoutMode = function( name ) {
3368    var Mode = LayoutMode.modes[ name ];
3369    // set mode options
3370    // HACK extend initial options, back-fill in default options
3371    var initialOpts = this.options[ name ] || {};
3372    this.options[ name ] = Mode.options ?
3373      utils.extend( Mode.options, initialOpts ) : initialOpts;
3374    // init layout mode instance
3375    this.modes[ name ] = new Mode( this );
3376  };
3377
3378
3379  proto.layout = function() {
3380    // if first time doing layout, do all magic
3381    if ( !this._isLayoutInited && this._getOption('initLayout') ) {
3382      this.arrange();
3383      return;
3384    }
3385    this._layout();
3386  };
3387
3388  // private method to be used in layout() & magic()
3389  proto._layout = function() {
3390    // don't animate first layout
3391    var isInstant = this._getIsInstant();
3392    // layout flow
3393    this._resetLayout();
3394    this._manageStamps();
3395    this.layoutItems( this.filteredItems, isInstant );
3396
3397    // flag for initalized
3398    this._isLayoutInited = true;
3399  };
3400
3401  // filter + sort + layout
3402  proto.arrange = function( opts ) {
3403    // set any options pass
3404    this.option( opts );
3405    this._getIsInstant();
3406    // filter, sort, and layout
3407
3408    // filter
3409    var filtered = this._filter( this.items );
3410    this.filteredItems = filtered.matches;
3411
3412    this._bindArrangeComplete();
3413
3414    if ( this._isInstant ) {
3415      this._noTransition( this._hideReveal, [ filtered ] );
3416    } else {
3417      this._hideReveal( filtered );
3418    }
3419
3420    this._sort();
3421    this._layout();
3422  };
3423  // alias to _init for main plugin method
3424  proto._init = proto.arrange;
3425
3426  proto._hideReveal = function( filtered ) {
3427    this.reveal( filtered.needReveal );
3428    this.hide( filtered.needHide );
3429  };
3430
3431  // HACK
3432  // Don't animate/transition first layout
3433  // Or don't animate/transition other layouts
3434  proto._getIsInstant = function() {
3435    var isLayoutInstant = this._getOption('layoutInstant');
3436    var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
3437      !this._isLayoutInited;
3438    this._isInstant = isInstant;
3439    return isInstant;
3440  };
3441
3442  // listen for layoutComplete, hideComplete and revealComplete
3443  // to trigger arrangeComplete
3444  proto._bindArrangeComplete = function() {
3445    // listen for 3 events to trigger arrangeComplete
3446    var isLayoutComplete, isHideComplete, isRevealComplete;
3447    var _this = this;
3448    function arrangeParallelCallback() {
3449      if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
3450        _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
3451      }
3452    }
3453    this.once( 'layoutComplete', function() {
3454      isLayoutComplete = true;
3455      arrangeParallelCallback();
3456    });
3457    this.once( 'hideComplete', function() {
3458      isHideComplete = true;
3459      arrangeParallelCallback();
3460    });
3461    this.once( 'revealComplete', function() {
3462      isRevealComplete = true;
3463      arrangeParallelCallback();
3464    });
3465  };
3466
3467  // -------------------------- filter -------------------------- //
3468
3469  proto._filter = function( items ) {
3470    var filter = this.options.filter;
3471    filter = filter || '*';
3472    var matches = [];
3473    var hiddenMatched = [];
3474    var visibleUnmatched = [];
3475
3476    var test = this._getFilterTest( filter );
3477
3478    // test each item
3479    for ( var i=0; i < items.length; i++ ) {
3480      var item = items[i];
3481      if ( item.isIgnored ) {
3482        continue;
3483      }
3484      // add item to either matched or unmatched group
3485      var isMatched = test( item );
3486      // item.isFilterMatched = isMatched;
3487      // add to matches if its a match
3488      if ( isMatched ) {
3489        matches.push( item );
3490      }
3491      // add to additional group if item needs to be hidden or revealed
3492      if ( isMatched && item.isHidden ) {
3493        hiddenMatched.push( item );
3494      } else if ( !isMatched && !item.isHidden ) {
3495        visibleUnmatched.push( item );
3496      }
3497    }
3498
3499    // return collections of items to be manipulated
3500    return {
3501      matches: matches,
3502      needReveal: hiddenMatched,
3503      needHide: visibleUnmatched
3504    };
3505  };
3506
3507  // get a jQuery, function, or a matchesSelector test given the filter
3508  proto._getFilterTest = function( filter ) {
3509    if ( jQuery && this.options.isJQueryFiltering ) {
3510      // use jQuery
3511      return function( item ) {
3512        return jQuery( item.element ).is( filter );
3513      };
3514    }
3515    if ( typeof filter == 'function' ) {
3516      // use filter as function
3517      return function( item ) {
3518        return filter( item.element );
3519      };
3520    }
3521    // default, use filter as selector string
3522    return function( item ) {
3523      return matchesSelector( item.element, filter );
3524    };
3525  };
3526
3527  // -------------------------- sorting -------------------------- //
3528
3529  /**
3530   * @params {Array} elems
3531   * @public
3532   */
3533  proto.updateSortData = function( elems ) {
3534    // get items
3535    var items;
3536    if ( elems ) {
3537      elems = utils.makeArray( elems );
3538      items = this.getItems( elems );
3539    } else {
3540      // update all items if no elems provided
3541      items = this.items;
3542    }
3543
3544    this._getSorters();
3545    this._updateItemsSortData( items );
3546  };
3547
3548  proto._getSorters = function() {
3549    var getSortData = this.options.getSortData;
3550    for ( var key in getSortData ) {
3551      var sorter = getSortData[ key ];
3552      this._sorters[ key ] = mungeSorter( sorter );
3553    }
3554  };
3555
3556  /**
3557   * @params {Array} items - of Isotope.Items
3558   * @private
3559   */
3560  proto._updateItemsSortData = function( items ) {
3561    // do not update if no items
3562    var len = items && items.length;
3563
3564    for ( var i=0; len && i < len; i++ ) {
3565      var item = items[i];
3566      item.updateSortData();
3567    }
3568  };
3569
3570  // ----- munge sorter ----- //
3571
3572  // encapsulate this, as we just need mungeSorter
3573  // other functions in here are just for munging
3574  var mungeSorter = ( function() {
3575    // add a magic layer to sorters for convienent shorthands
3576    // `.foo-bar` will use the text of .foo-bar querySelector
3577    // `[foo-bar]` will use attribute
3578    // you can also add parser
3579    // `.foo-bar parseInt` will parse that as a number
3580    function mungeSorter( sorter ) {
3581      // if not a string, return function or whatever it is
3582      if ( typeof sorter != 'string' ) {
3583        return sorter;
3584      }
3585      // parse the sorter string
3586      var args = trim( sorter ).split(' ');
3587      var query = args[0];
3588      // check if query looks like [an-attribute]
3589      var attrMatch = query.match( /^\[(.+)\]$/ );
3590      var attr = attrMatch && attrMatch[1];
3591      var getValue = getValueGetter( attr, query );
3592      // use second argument as a parser
3593      var parser = Isotope.sortDataParsers[ args[1] ];
3594      // parse the value, if there was a parser
3595      sorter = parser ? function( elem ) {
3596        return elem && parser( getValue( elem ) );
3597      } :
3598      // otherwise just return value
3599      function( elem ) {
3600        return elem && getValue( elem );
3601      };
3602
3603      return sorter;
3604    }
3605
3606    // get an attribute getter, or get text of the querySelector
3607    function getValueGetter( attr, query ) {
3608      // if query looks like [foo-bar], get attribute
3609      if ( attr ) {
3610        return function getAttribute( elem ) {
3611          return elem.getAttribute( attr );
3612        };
3613      }
3614
3615      // otherwise, assume its a querySelector, and get its text
3616      return function getChildText( elem ) {
3617        var child = elem.querySelector( query );
3618        return child && child.textContent;
3619      };
3620    }
3621
3622    return mungeSorter;
3623  })();
3624
3625  // parsers used in getSortData shortcut strings
3626  Isotope.sortDataParsers = {
3627    'parseInt': function( val ) {
3628      return parseInt( val, 10 );
3629    },
3630    'parseFloat': function( val ) {
3631      return parseFloat( val );
3632    }
3633  };
3634
3635  // ----- sort method ----- //
3636
3637  // sort filteredItem order
3638  proto._sort = function() {
3639    if ( !this.options.sortBy ) {
3640      return;
3641    }
3642    // keep track of sortBy History
3643    var sortBys = utils.makeArray( this.options.sortBy );
3644    if ( !this._getIsSameSortBy( sortBys ) ) {
3645      // concat all sortBy and sortHistory, add to front, oldest goes in last
3646      this.sortHistory = sortBys.concat( this.sortHistory );
3647    }
3648    // sort magic
3649    var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending );
3650    this.filteredItems.sort( itemSorter );
3651  };
3652
3653  // check if sortBys is same as start of sortHistory
3654  proto._getIsSameSortBy = function( sortBys ) {
3655    for ( var i=0; i < sortBys.length; i++ ) {
3656      if ( sortBys[i] != this.sortHistory[i] ) {
3657        return false;
3658      }
3659    }
3660    return true;
3661  };
3662
3663  // returns a function used for sorting
3664  function getItemSorter( sortBys, sortAsc ) {
3665    return function sorter( itemA, itemB ) {
3666      // cycle through all sortKeys
3667      for ( var i = 0; i < sortBys.length; i++ ) {
3668        var sortBy = sortBys[i];
3669        var a = itemA.sortData[ sortBy ];
3670        var b = itemB.sortData[ sortBy ];
3671        if ( a > b || a < b ) {
3672          // if sortAsc is an object, use the value given the sortBy key
3673          var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
3674          var direction = isAscending ? 1 : -1;
3675          return ( a > b ? 1 : -1 ) * direction;
3676        }
3677      }
3678      return 0;
3679    };
3680  }
3681
3682  // -------------------------- methods -------------------------- //
3683
3684  // get layout mode
3685  proto._mode = function() {
3686    var layoutMode = this.options.layoutMode;
3687    var mode = this.modes[ layoutMode ];
3688    if ( !mode ) {
3689      // TODO console.error
3690      throw new Error( 'No layout mode: ' + layoutMode );
3691    }
3692    // HACK sync mode's options
3693    // any options set after init for layout mode need to be synced
3694    mode.options = this.options[ layoutMode ];
3695    return mode;
3696  };
3697
3698  proto._resetLayout = function() {
3699    // trigger original reset layout
3700    Outlayer.prototype._resetLayout.call( this );
3701    this._mode()._resetLayout();
3702  };
3703
3704  proto._getItemLayoutPosition = function( item  ) {
3705    return this._mode()._getItemLayoutPosition( item );
3706  };
3707
3708  proto._manageStamp = function( stamp ) {
3709    this._mode()._manageStamp( stamp );
3710  };
3711
3712  proto._getContainerSize = function() {
3713    return this._mode()._getContainerSize();
3714  };
3715
3716  proto.needsResizeLayout = function() {
3717    return this._mode().needsResizeLayout();
3718  };
3719
3720  // -------------------------- adding & removing -------------------------- //
3721
3722  // HEADS UP overwrites default Outlayer appended
3723  proto.appended = function( elems ) {
3724    var items = this.addItems( elems );
3725    if ( !items.length ) {
3726      return;
3727    }
3728    // filter, layout, reveal new items
3729    var filteredItems = this._filterRevealAdded( items );
3730    // add to filteredItems
3731    this.filteredItems = this.filteredItems.concat( filteredItems );
3732  };
3733
3734  // HEADS UP overwrites default Outlayer prepended
3735  proto.prepended = function( elems ) {
3736    var items = this._itemize( elems );
3737    if ( !items.length ) {
3738      return;
3739    }
3740    // start new layout
3741    this._resetLayout();
3742    this._manageStamps();
3743    // filter, layout, reveal new items
3744    var filteredItems = this._filterRevealAdded( items );
3745    // layout previous items
3746    this.layoutItems( this.filteredItems );
3747    // add to items and filteredItems
3748    this.filteredItems = filteredItems.concat( this.filteredItems );
3749    this.items = items.concat( this.items );
3750  };
3751
3752  proto._filterRevealAdded = function( items ) {
3753    var filtered = this._filter( items );
3754    this.hide( filtered.needHide );
3755    // reveal all new items
3756    this.reveal( filtered.matches );
3757    // layout new items, no transition
3758    this.layoutItems( filtered.matches, true );
3759    return filtered.matches;
3760  };
3761
3762  /**
3763   * Filter, sort, and layout newly-appended item elements
3764   * @param {Array or NodeList or Element} elems
3765   */
3766  proto.insert = function( elems ) {
3767    var items = this.addItems( elems );
3768    if ( !items.length ) {
3769      return;
3770    }
3771    // append item elements
3772    var i, item;
3773    var len = items.length;
3774    for ( i=0; i < len; i++ ) {
3775      item = items[i];
3776      this.element.appendChild( item.element );
3777    }
3778    // filter new stuff
3779    var filteredInsertItems = this._filter( items ).matches;
3780    // set flag
3781    for ( i=0; i < len; i++ ) {
3782      items[i].isLayoutInstant = true;
3783    }
3784    this.arrange();
3785    // reset flag
3786    for ( i=0; i < len; i++ ) {
3787      delete items[i].isLayoutInstant;
3788    }
3789    this.reveal( filteredInsertItems );
3790  };
3791
3792  var _remove = proto.remove;
3793  proto.remove = function( elems ) {
3794    elems = utils.makeArray( elems );
3795    var removeItems = this.getItems( elems );
3796    // do regular thing
3797    _remove.call( this, elems );
3798    // bail if no items to remove
3799    var len = removeItems && removeItems.length;
3800    // remove elems from filteredItems
3801    for ( var i=0; len && i < len; i++ ) {
3802      var item = removeItems[i];
3803      // remove item from collection
3804      utils.removeFrom( this.filteredItems, item );
3805    }
3806  };
3807
3808  proto.shuffle = function() {
3809    // update random sortData
3810    for ( var i=0; i < this.items.length; i++ ) {
3811      var item = this.items[i];
3812      item.sortData.random = Math.random();
3813    }
3814    this.options.sortBy = 'random';
3815    this._sort();
3816    this._layout();
3817  };
3818
3819  /**
3820   * trigger fn without transition
3821   * kind of hacky to have this in the first place
3822   * @param {Function} fn
3823   * @param {Array} args
3824   * @returns ret
3825   * @private
3826   */
3827  proto._noTransition = function( fn, args ) {
3828    // save transitionDuration before disabling
3829    var transitionDuration = this.options.transitionDuration;
3830    // disable transition
3831    this.options.transitionDuration = 0;
3832    // do it
3833    var returnValue = fn.apply( this, args );
3834    // re-enable transition for reveal
3835    this.options.transitionDuration = transitionDuration;
3836    return returnValue;
3837  };
3838
3839  // ----- helper methods ----- //
3840
3841  /**
3842   * getter method for getting filtered item elements
3843   * @returns {Array} elems - collection of item elements
3844   */
3845  proto.getFilteredItemElements = function() {
3846    return this.filteredItems.map( function( item ) {
3847      return item.element;
3848    });
3849  };
3850
3851  // -----  ----- //
3852
3853  return Isotope;
3854
3855}));
3856
vendor: 29,252 bytes, lines 3857-5013
3857/*!
3858 * Packery layout mode PACKAGED v2.0.1
3859 * sub-classes Packery
3860 */
3861
3862/**
3863 * Rect
3864 * low-level utility class for basic geometry
3865 */
3866
3867( function( window, factory ) {
3868  // universal module definition
3869  /* jshint strict: false */ /* globals define, module */
3870  if ( typeof define == 'function' && define.amd ) {
3871    // AMD
3872    define( 'packery/js/rect',factory );
3873  } else if ( typeof module == 'object' && module.exports ) {
3874    // CommonJS
3875    module.exports = factory();
3876  } else {
3877    // browser global
3878    window.Packery = window.Packery || {};
3879    window.Packery.Rect = factory();
3880  }
3881
3882}( window, function factory() {
3883
3884
3885// -------------------------- Rect -------------------------- //
3886
3887function Rect( props ) {
3888  // extend properties from defaults
3889  for ( var prop in Rect.defaults ) {
3890    this[ prop ] = Rect.defaults[ prop ];
3891  }
3892
3893  for ( prop in props ) {
3894    this[ prop ] = props[ prop ];
3895  }
3896
3897}
3898
3899Rect.defaults = {
3900  x: 0,
3901  y: 0,
3902  width: 0,
3903  height: 0
3904};
3905
3906var proto = Rect.prototype;
3907
3908/**
3909 * Determines whether or not this rectangle wholly encloses another rectangle or point.
3910 * @param {Rect} rect
3911 * @returns {Boolean}
3912**/
3913proto.contains = function( rect ) {
3914  // points don't have width or height
3915  var otherWidth = rect.width || 0;
3916  var otherHeight = rect.height || 0;
3917  return this.x <= rect.x &&
3918    this.y <= rect.y &&
3919    this.x + this.width >= rect.x + otherWidth &&
3920    this.y + this.height >= rect.y + otherHeight;
3921};
3922
3923/**
3924 * Determines whether or not the rectangle intersects with another.
3925 * @param {Rect} rect
3926 * @returns {Boolean}
3927**/
3928proto.overlaps = function( rect ) {
3929  var thisRight = this.x + this.width;
3930  var thisBottom = this.y + this.height;
3931  var rectRight = rect.x + rect.width;
3932  var rectBottom = rect.y + rect.height;
3933
3934  // http://stackoverflow.com/a/306332
3935  return this.x < rectRight &&
3936    thisRight > rect.x &&
3937    this.y < rectBottom &&
3938    thisBottom > rect.y;
3939};
3940
3941/**
3942 * @param {Rect} rect - the overlapping rect
3943 * @returns {Array} freeRects - rects representing the area around the rect
3944**/
3945proto.getMaximalFreeRects = function( rect ) {
3946
3947  // if no intersection, return false
3948  if ( !this.overlaps( rect ) ) {
3949    return false;
3950  }
3951
3952  var freeRects = [];
3953  var freeRect;
3954
3955  var thisRight = this.x + this.width;
3956  var thisBottom = this.y + this.height;
3957  var rectRight = rect.x + rect.width;
3958  var rectBottom = rect.y + rect.height;
3959
3960  // top
3961  if ( this.y < rect.y ) {
3962    freeRect = new Rect({
3963      x: this.x,
3964      y: this.y,
3965      width: this.width,
3966      height: rect.y - this.y
3967    });
3968    freeRects.push( freeRect );
3969  }
3970
3971  // right
3972  if ( thisRight > rectRight ) {
3973    freeRect = new Rect({
3974      x: rectRight,
3975      y: this.y,
3976      width: thisRight - rectRight,
3977      height: this.height
3978    });
3979    freeRects.push( freeRect );
3980  }
3981
3982  // bottom
3983  if ( thisBottom > rectBottom ) {
3984    freeRect = new Rect({
3985      x: this.x,
3986      y: rectBottom,
3987      width: this.width,
3988      height: thisBottom - rectBottom
3989    });
3990    freeRects.push( freeRect );
3991  }
3992
3993  // left
3994  if ( this.x < rect.x ) {
3995    freeRect = new Rect({
3996      x: this.x,
3997      y: this.y,
3998      width: rect.x - this.x,
3999      height: this.height
4000    });
4001    freeRects.push( freeRect );
4002  }
4003
4004  return freeRects;
4005};
4006
4007proto.canFit = function( rect ) {
4008  return this.width >= rect.width && this.height >= rect.height;
4009};
4010
4011return Rect;
4012
4013}));
4014
4015/**
4016 * Packer
4017 * bin-packing algorithm
4018 */
4019
4020( function( window, factory ) {
4021  // universal module definition
4022  /* jshint strict: false */ /* globals define, module, require */
4023  if ( typeof define == 'function' && define.amd ) {
4024    // AMD
4025    define( 'packery/js/packer',[ './rect' ], factory );
4026  } else if ( typeof module == 'object' && module.exports ) {
4027    // CommonJS
4028    module.exports = factory(
4029      require('./rect')
4030    );
4031  } else {
4032    // browser global
4033    var Packery = window.Packery = window.Packery || {};
4034    Packery.Packer = factory( Packery.Rect );
4035  }
4036
4037}( window, function factory( Rect ) {
4038
4039
4040// -------------------------- Packer -------------------------- //
4041
4042/**
4043 * @param {Number} width
4044 * @param {Number} height
4045 * @param {String} sortDirection
4046 *   topLeft for vertical, leftTop for horizontal
4047 */
4048function Packer( width, height, sortDirection ) {
4049  this.width = width || 0;
4050  this.height = height || 0;
4051  this.sortDirection = sortDirection || 'downwardLeftToRight';
4052
4053  this.reset();
4054}
4055
4056var proto = Packer.prototype;
4057
4058proto.reset = function() {
4059  this.spaces = [];
4060
4061  var initialSpace = new Rect({
4062    x: 0,
4063    y: 0,
4064    width: this.width,
4065    height: this.height
4066  });
4067
4068  this.spaces.push( initialSpace );
4069  // set sorter
4070  this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
4071};
4072
4073// change x and y of rect to fit with in Packer's available spaces
4074proto.pack = function( rect ) {
4075  for ( var i=0; i < this.spaces.length; i++ ) {
4076    var space = this.spaces[i];
4077    if ( space.canFit( rect ) ) {
4078      this.placeInSpace( rect, space );
4079      break;
4080    }
4081  }
4082};
4083
4084proto.columnPack = function( rect ) {
4085  for ( var i=0; i < this.spaces.length; i++ ) {
4086    var space = this.spaces[i];
4087    var canFitInSpaceColumn = space.x <= rect.x &&
4088      space.x + space.width >= rect.x + rect.width &&
4089      space.height >= rect.height - 0.01; // fudge number for rounding error
4090    if ( canFitInSpaceColumn ) {
4091      rect.y = space.y;
4092      this.placed( rect );
4093      break;
4094    }
4095  }
4096};
4097
4098proto.rowPack = function( rect ) {
4099  for ( var i=0; i < this.spaces.length; i++ ) {
4100    var space = this.spaces[i];
4101    var canFitInSpaceRow = space.y <= rect.y &&
4102      space.y + space.height >= rect.y + rect.height &&
4103      space.width >= rect.width - 0.01; // fudge number for rounding error
4104    if ( canFitInSpaceRow ) {
4105      rect.x = space.x;
4106      this.placed( rect );
4107      break;
4108    }
4109  }
4110};
4111
4112proto.placeInSpace = function( rect, space ) {
4113  // place rect in space
4114  rect.x = space.x;
4115  rect.y = space.y;
4116
4117  this.placed( rect );
4118};
4119
4120// update spaces with placed rect
4121proto.placed = function( rect ) {
4122  // update spaces
4123  var revisedSpaces = [];
4124  for ( var i=0; i < this.spaces.length; i++ ) {
4125    var space = this.spaces[i];
4126    var newSpaces = space.getMaximalFreeRects( rect );
4127    // add either the original space or the new spaces to the revised spaces
4128    if ( newSpaces ) {
4129      revisedSpaces.push.apply( revisedSpaces, newSpaces );
4130    } else {
4131      revisedSpaces.push( space );
4132    }
4133  }
4134
4135  this.spaces = revisedSpaces;
4136
4137  this.mergeSortSpaces();
4138};
4139
4140proto.mergeSortSpaces = function() {
4141  // remove redundant spaces
4142  Packer.mergeRects( this.spaces );
4143  this.spaces.sort( this.sorter );
4144};
4145
4146// add a space back
4147proto.addSpace = function( rect ) {
4148  this.spaces.push( rect );
4149  this.mergeSortSpaces();
4150};
4151
4152// -------------------------- utility functions -------------------------- //
4153
4154/**
4155 * Remove redundant rectangle from array of rectangles
4156 * @param {Array} rects: an array of Rects
4157 * @returns {Array} rects: an array of Rects
4158**/
4159Packer.mergeRects = function( rects ) {
4160  var i = 0;
4161  var rect = rects[i];
4162
4163  rectLoop:
4164  while ( rect ) {
4165    var j = 0;
4166    var compareRect = rects[ i + j ];
4167
4168    while ( compareRect ) {
4169      if  ( compareRect == rect ) {
4170        j++; // next
4171      } else if ( compareRect.contains( rect ) ) {
4172        // remove rect
4173        rects.splice( i, 1 );
4174        rect = rects[i]; // set next rect
4175        continue rectLoop; // bail on compareLoop
4176      } else if ( rect.contains( compareRect ) ) {
4177        // remove compareRect
4178        rects.splice( i + j, 1 );
4179      } else {
4180        j++;
4181      }
4182      compareRect = rects[ i + j ]; // set next compareRect
4183    }
4184    i++;
4185    rect = rects[i];
4186  }
4187
4188  return rects;
4189};
4190
4191
4192// -------------------------- sorters -------------------------- //
4193
4194// functions for sorting rects in order
4195var sorters = {
4196  // top down, then left to right
4197  downwardLeftToRight: function( a, b ) {
4198    return a.y - b.y || a.x - b.x;
4199  },
4200  // left to right, then top down
4201  rightwardTopToBottom: function( a, b ) {
4202    return a.x - b.x || a.y - b.y;
4203  }
4204};
4205
4206
4207// --------------------------  -------------------------- //
4208
4209return Packer;
4210
4211}));
4212
4213/**
4214 * Packery Item Element
4215**/
4216
4217( function( window, factory ) {
4218  // universal module definition
4219  /* jshint strict: false */ /* globals define, module, require */
4220  if ( typeof define == 'function' && define.amd ) {
4221    // AMD
4222    define( 'packery/js/item',[
4223        'outlayer/outlayer',
4224        './rect'
4225      ],
4226      factory );
4227  } else if ( typeof module == 'object' && module.exports ) {
4228    // CommonJS
4229    module.exports = factory(
4230      require('outlayer'),
4231      require('./rect')
4232    );
4233  } else {
4234    // browser global
4235    window.Packery.Item = factory(
4236      window.Outlayer,
4237      window.Packery.Rect
4238    );
4239  }
4240
4241}( window, function factory( Outlayer, Rect ) {
4242
4243
4244// -------------------------- Item -------------------------- //
4245
4246var docElemStyle = document.documentElement.style;
4247
4248var transformProperty = typeof docElemStyle.transform == 'string' ?
4249  'transform' : 'WebkitTransform';
4250
4251// sub-class Item
4252var Item = function PackeryItem() {
4253  Outlayer.Item.apply( this, arguments );
4254};
4255
4256var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
4257
4258var __create = proto._create;
4259proto._create = function() {
4260  // call default _create logic
4261  __create.call( this );
4262  this.rect = new Rect();
4263};
4264
4265var _moveTo = proto.moveTo;
4266proto.moveTo = function( x, y ) {
4267  // don't shift 1px while dragging
4268  var dx = Math.abs( this.position.x - x );
4269  var dy = Math.abs( this.position.y - y );
4270
4271  var canHackGoTo = this.layout.dragItemCount && !this.isPlacing &&
4272    !this.isTransitioning && dx < 1 && dy < 1;
4273  if ( canHackGoTo ) {
4274    this.goTo( x, y );
4275    return;
4276  }
4277  _moveTo.apply( this, arguments );
4278};
4279
4280// -------------------------- placing -------------------------- //
4281
4282proto.enablePlacing = function() {
4283  this.removeTransitionStyles();
4284  // remove transform property from transition
4285  if ( this.isTransitioning && transformProperty ) {
4286    this.element.style[ transformProperty ] = 'none';
4287  }
4288  this.isTransitioning = false;
4289  this.getSize();
4290  this.layout._setRectSize( this.element, this.rect );
4291  this.isPlacing = true;
4292};
4293
4294proto.disablePlacing = function() {
4295  this.isPlacing = false;
4296};
4297
4298// -----  ----- //
4299
4300// remove element from DOM
4301proto.removeElem = function() {
4302  this.element.parentNode.removeChild( this.element );
4303  // add space back to packer
4304  this.layout.packer.addSpace( this.rect );
4305  this.emitEvent( 'remove', [ this ] );
4306};
4307
4308// ----- dropPlaceholder ----- //
4309
4310proto.showDropPlaceholder = function() {
4311  var dropPlaceholder = this.dropPlaceholder;
4312  if ( !dropPlaceholder ) {
4313    // create dropPlaceholder
4314    dropPlaceholder = this.dropPlaceholder = document.createElement('div');
4315    dropPlaceholder.className = 'packery-drop-placeholder';
4316    dropPlaceholder.style.position = 'absolute';
4317  }
4318
4319  dropPlaceholder.style.width = this.size.width + 'px';
4320  dropPlaceholder.style.height = this.size.height + 'px';
4321  this.positionDropPlaceholder();
4322  this.layout.element.appendChild( dropPlaceholder );
4323};
4324
4325proto.positionDropPlaceholder = function() {
4326  this.dropPlaceholder.style[ transformProperty ] = 'translate(' +
4327    this.rect.x + 'px, ' + this.rect.y + 'px)';
4328};
4329
4330proto.hideDropPlaceholder = function() {
4331  this.layout.element.removeChild( this.dropPlaceholder );
4332};
4333
4334// -----  ----- //
4335
4336return Item;
4337
4338}));
4339
4340/*!
4341 * Packery v2.0.0
4342 * Gapless, draggable grid layouts
4343 *
4344 * Licensed GPLv3 for open source use
4345 * or Packery Commercial License for commercial use
4346 *
4347 * http://packery.metafizzy.co
4348 * Copyright 2016 Metafizzy
4349 */
4350
4351( function( window, factory ) {
4352  // universal module definition
4353  /* jshint strict: false */ /* globals define, module, require */
4354  if ( typeof define == 'function' && define.amd ) {
4355    // AMD
4356    define( 'packery/js/packery',[
4357        'get-size/get-size',
4358        'outlayer/outlayer',
4359        './rect',
4360        './packer',
4361        './item'
4362      ],
4363      factory );
4364  } else if ( typeof module == 'object' && module.exports ) {
4365    // CommonJS
4366    module.exports = factory(
4367      require('get-size'),
4368      require('outlayer'),
4369      require('./rect'),
4370      require('./packer'),
4371      require('./item')
4372    );
4373  } else {
4374    // browser global
4375    window.Packery = factory(
4376      window.getSize,
4377      window.Outlayer,
4378      window.Packery.Rect,
4379      window.Packery.Packer,
4380      window.Packery.Item
4381    );
4382  }
4383
4384}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) {
4385
4386
4387// ----- Rect ----- //
4388
4389// allow for pixel rounding errors IE8-IE11 & Firefox; #227
4390Rect.prototype.canFit = function( rect ) {
4391  return this.width >= rect.width - 1 && this.height >= rect.height - 1;
4392};
4393
4394// -------------------------- Packery -------------------------- //
4395
4396// create an Outlayer layout class
4397var Packery = Outlayer.create('packery');
4398Packery.Item = Item;
4399
4400var proto = Packery.prototype;
4401
4402proto._create = function() {
4403  // call super
4404  Outlayer.prototype._create.call( this );
4405
4406  // initial properties
4407  this.packer = new Packer();
4408  // packer for drop targets
4409  this.shiftPacker = new Packer();
4410  this.isEnabled = true;
4411
4412  this.dragItemCount = 0;
4413
4414  // create drag handlers
4415  var _this = this;
4416  this.handleDraggabilly = {
4417    dragStart: function() {
4418      _this.itemDragStart( this.element );
4419    },
4420    dragMove: function() {
4421      _this.itemDragMove( this.element, this.position.x, this.position.y );
4422    },
4423    dragEnd: function() {
4424      _this.itemDragEnd( this.element );
4425    }
4426  };
4427
4428  this.handleUIDraggable = {
4429    start: function handleUIDraggableStart( event, ui ) {
4430      // HTML5 may trigger dragstart, dismiss HTML5 dragging
4431      if ( !ui ) {
4432        return;
4433      }
4434      _this.itemDragStart( event.currentTarget );
4435    },
4436    drag: function handleUIDraggableDrag( event, ui ) {
4437      if ( !ui ) {
4438        return;
4439      }
4440      _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
4441    },
4442    stop: function handleUIDraggableStop( event, ui ) {
4443      if ( !ui ) {
4444        return;
4445      }
4446      _this.itemDragEnd( event.currentTarget );
4447    }
4448  };
4449
4450};
4451
4452
4453// ----- init & layout ----- //
4454
4455/**
4456 * logic before any new layout
4457 */
4458proto._resetLayout = function() {
4459  this.getSize();
4460
4461  this._getMeasurements();
4462
4463  // reset packer
4464  var width, height, sortDirection;
4465  // packer settings, if horizontal or vertical
4466  if ( this._getOption('horizontal') ) {
4467    width = Infinity;
4468    height = this.size.innerHeight + this.gutter;
4469    sortDirection = 'rightwardTopToBottom';
4470  } else {
4471    width = this.size.innerWidth + this.gutter;
4472    height = Infinity;
4473    sortDirection = 'downwardLeftToRight';
4474  }
4475
4476  this.packer.width = this.shiftPacker.width = width;
4477  this.packer.height = this.shiftPacker.height = height;
4478  this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection;
4479
4480  this.packer.reset();
4481
4482  // layout
4483  this.maxY = 0;
4484  this.maxX = 0;
4485};
4486
4487/**
4488 * update columnWidth, rowHeight, & gutter
4489 * @private
4490 */
4491proto._getMeasurements = function() {
4492  this._getMeasurement( 'columnWidth', 'width' );
4493  this._getMeasurement( 'rowHeight', 'height' );
4494  this._getMeasurement( 'gutter', 'width' );
4495};
4496
4497proto._getItemLayoutPosition = function( item ) {
4498  this._setRectSize( item.element, item.rect );
4499  if ( this.isShifting || this.dragItemCount > 0 ) {
4500    var packMethod = this._getPackMethod();
4501    this.packer[ packMethod ]( item.rect );
4502  } else {
4503    this.packer.pack( item.rect );
4504  }
4505
4506  this._setMaxXY( item.rect );
4507  return item.rect;
4508};
4509
4510proto.shiftLayout = function() {
4511  this.isShifting = true;
4512  this.layout();
4513  delete this.isShifting;
4514};
4515
4516proto._getPackMethod = function() {
4517  return this._getOption('horizontal') ? 'rowPack' : 'columnPack';
4518};
4519
4520
4521/**
4522 * set max X and Y value, for size of container
4523 * @param {Packery.Rect} rect
4524 * @private
4525 */
4526proto._setMaxXY = function( rect ) {
4527  this.maxX = Math.max( rect.x + rect.width, this.maxX );
4528  this.maxY = Math.max( rect.y + rect.height, this.maxY );
4529};
4530
4531/**
4532 * set the width and height of a rect, applying columnWidth and rowHeight
4533 * @param {Element} elem
4534 * @param {Packery.Rect} rect
4535 */
4536proto._setRectSize = function( elem, rect ) {
4537  var size = getSize( elem );
4538  var w = size.outerWidth;
4539  var h = size.outerHeight;
4540  // size for columnWidth and rowHeight, if available
4541  // only check if size is non-zero, #177
4542  if ( w || h ) {
4543    w = this._applyGridGutter( w, this.columnWidth );
4544    h = this._applyGridGutter( h, this.rowHeight );
4545  }
4546  // rect must fit in packer
4547  rect.width = Math.min( w, this.packer.width );
4548  rect.height = Math.min( h, this.packer.height );
4549};
4550
4551/**
4552 * fits item to columnWidth/rowHeight and adds gutter
4553 * @param {Number} measurement - item width or height
4554 * @param {Number} gridSize - columnWidth or rowHeight
4555 * @returns measurement
4556 */
4557proto._applyGridGutter = function( measurement, gridSize ) {
4558  // just add gutter if no gridSize
4559  if ( !gridSize ) {
4560    return measurement + this.gutter;
4561  }
4562  gridSize += this.gutter;
4563  // fit item to columnWidth/rowHeight
4564  var remainder = measurement % gridSize;
4565  var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
4566  measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize;
4567  return measurement;
4568};
4569
4570proto._getContainerSize = function() {
4571  if ( this._getOption('horizontal') ) {
4572    return {
4573      width: this.maxX - this.gutter
4574    };
4575  } else {
4576    return {
4577      height: this.maxY - this.gutter
4578    };
4579  }
4580};
4581
4582
4583// -------------------------- stamp -------------------------- //
4584
4585/**
4586 * makes space for element
4587 * @param {Element} elem
4588 */
4589proto._manageStamp = function( elem ) {
4590
4591  var item = this.getItem( elem );
4592  var rect;
4593  if ( item && item.isPlacing ) {
4594    rect = item.rect;
4595  } else {
4596    var offset = this._getElementOffset( elem );
4597    rect = new Rect({
4598      x: this._getOption('originLeft') ? offset.left : offset.right,
4599      y: this._getOption('originTop') ? offset.top : offset.bottom
4600    });
4601  }
4602
4603  this._setRectSize( elem, rect );
4604  // save its space in the packer
4605  this.packer.placed( rect );
4606  this._setMaxXY( rect );
4607};
4608
4609// -------------------------- methods -------------------------- //
4610
4611function verticalSorter( a, b ) {
4612  return a.position.y - b.position.y || a.position.x - b.position.x;
4613}
4614
4615function horizontalSorter( a, b ) {
4616  return a.position.x - b.position.x || a.position.y - b.position.y;
4617}
4618
4619proto.sortItemsByPosition = function() {
4620  var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter;
4621  this.items.sort( sorter );
4622};
4623
4624/**
4625 * Fit item element in its current position
4626 * Packery will position elements around it
4627 * useful for expanding elements
4628 *
4629 * @param {Element} elem
4630 * @param {Number} x - horizontal destination position, optional
4631 * @param {Number} y - vertical destination position, optional
4632 */
4633proto.fit = function( elem, x, y ) {
4634  var item = this.getItem( elem );
4635  if ( !item ) {
4636    return;
4637  }
4638
4639  // stamp item to get it out of layout
4640  this.stamp( item.element );
4641  // set placing flag
4642  item.enablePlacing();
4643  this.updateShiftTargets( item );
4644  // fall back to current position for fitting
4645  x = x === undefined ? item.rect.x: x;
4646  y = y === undefined ? item.rect.y: y;
4647  // position it best at its destination
4648  this.shift( item, x, y );
4649  this._bindFitEvents( item );
4650  item.moveTo( item.rect.x, item.rect.y );
4651  // layout everything else
4652  this.shiftLayout();
4653  // return back to regularly scheduled programming
4654  this.unstamp( item.element );
4655  this.sortItemsByPosition();
4656  item.disablePlacing();
4657};
4658
4659/**
4660 * emit event when item is fit and other items are laid out
4661 * @param {Packery.Item} item
4662 * @private
4663 */
4664proto._bindFitEvents = function( item ) {
4665  var _this = this;
4666  var ticks = 0;
4667  function onLayout() {
4668    ticks++;
4669    if ( ticks != 2 ) {
4670      return;
4671    }
4672    _this.dispatchEvent( 'fitComplete', null, [ item ] );
4673  }
4674  // when item is laid out
4675  item.once( 'layout', onLayout );
4676  // when all items are laid out
4677  this.once( 'layoutComplete', onLayout );
4678};
4679
4680// -------------------------- resize -------------------------- //
4681
4682// debounced, layout on resize
4683proto.resize = function() {
4684  // don't trigger if size did not change
4685  // or if resize was unbound. See #285, outlayer#9
4686  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
4687    return;
4688  }
4689
4690  if ( this.options.shiftPercentResize ) {
4691    this.resizeShiftPercentLayout();
4692  } else {
4693    this.layout();
4694  }
4695};
4696
4697/**
4698 * check if layout is needed post layout
4699 * @returns Boolean
4700 */
4701proto.needsResizeLayout = function() {
4702  var size = getSize( this.element );
4703  var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth';
4704  return size[ innerSize ] != this.size[ innerSize ];
4705};
4706
4707proto.resizeShiftPercentLayout = function() {
4708  var items = this._getItemsForLayout( this.items );
4709
4710  var isHorizontal = this._getOption('horizontal');
4711  var coord = isHorizontal ? 'y' : 'x';
4712  var measure = isHorizontal ? 'height' : 'width';
4713  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
4714  var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth';
4715
4716  // proportional re-align items
4717  var previousSegment = this[ segmentName ];
4718  previousSegment = previousSegment && previousSegment + this.gutter;
4719
4720  if ( previousSegment ) {
4721    this._getMeasurements();
4722    var currentSegment = this[ segmentName ] + this.gutter;
4723    items.forEach( function( item ) {
4724      var seg = Math.round( item.rect[ coord ] / previousSegment );
4725      item.rect[ coord ] = seg * currentSegment;
4726    });
4727  } else {
4728    var currentSize = getSize( this.element )[ innerSize ] + this.gutter;
4729    var previousSize = this.packer[ measure ];
4730    items.forEach( function( item ) {
4731      item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize;
4732    });
4733  }
4734
4735  this.shiftLayout();
4736};
4737
4738// -------------------------- drag -------------------------- //
4739
4740/**
4741 * handle an item drag start event
4742 * @param {Element} elem
4743 */
4744proto.itemDragStart = function( elem ) {
4745  if ( !this.isEnabled ) {
4746    return;
4747  }
4748  this.stamp( elem );
4749  // this.ignore( elem );
4750  var item = this.getItem( elem );
4751  if ( !item ) {
4752    return;
4753  }
4754
4755  item.enablePlacing();
4756  item.showDropPlaceholder();
4757  this.dragItemCount++;
4758  this.updateShiftTargets( item );
4759};
4760
4761proto.updateShiftTargets = function( dropItem ) {
4762  this.shiftPacker.reset();
4763
4764  // pack stamps
4765  this._getBoundingRect();
4766  var isOriginLeft = this._getOption('originLeft');
4767  var isOriginTop = this._getOption('originTop');
4768  this.stamps.forEach( function( stamp ) {
4769    // ignore dragged item
4770    var item = this.getItem( stamp );
4771    if ( item && item.isPlacing ) {
4772      return;
4773    }
4774    var offset = this._getElementOffset( stamp );
4775    var rect = new Rect({
4776      x: isOriginLeft ? offset.left : offset.right,
4777      y: isOriginTop ? offset.top : offset.bottom
4778    });
4779    this._setRectSize( stamp, rect );
4780    // save its space in the packer
4781    this.shiftPacker.placed( rect );
4782  }, this );
4783
4784  // reset shiftTargets
4785  var isHorizontal = this._getOption('horizontal');
4786  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
4787  var measure = isHorizontal ? 'height' : 'width';
4788
4789  this.shiftTargetKeys = [];
4790  this.shiftTargets = [];
4791  var boundsSize;
4792  var segment = this[ segmentName ];
4793  segment = segment && segment + this.gutter;
4794
4795  if ( segment ) {
4796    var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment );
4797    var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment );
4798    boundsSize = ( segs - segmentSpan ) * segment;
4799    // add targets on top
4800    for ( var i=0; i < segs; i++ ) {
4801      this._addShiftTarget( i * segment, 0, boundsSize );
4802    }
4803  } else {
4804    boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ];
4805    this._addShiftTarget( 0, 0, boundsSize );
4806  }
4807
4808  // pack each item to measure where shiftTargets are
4809  var items = this._getItemsForLayout( this.items );
4810  var packMethod = this._getPackMethod();
4811  items.forEach( function( item ) {
4812    var rect = item.rect;
4813    this._setRectSize( item.element, rect );
4814    this.shiftPacker[ packMethod ]( rect );
4815
4816    // add top left corner
4817    this._addShiftTarget( rect.x, rect.y, boundsSize );
4818    // add bottom left / top right corner
4819    var cornerX = isHorizontal ? rect.x + rect.width : rect.x;
4820    var cornerY = isHorizontal ? rect.y : rect.y + rect.height;
4821    this._addShiftTarget( cornerX, cornerY, boundsSize );
4822
4823    if ( segment ) {
4824      // add targets for each column on bottom / row on right
4825      var segSpan = Math.round( rect[ measure ] / segment );
4826      for ( var i=1; i < segSpan; i++ ) {
4827        var segX = isHorizontal ? cornerX : rect.x + segment * i;
4828        var segY = isHorizontal ? rect.y + segment * i : cornerY;
4829        this._addShiftTarget( segX, segY, boundsSize );
4830      }
4831    }
4832  }, this );
4833
4834};
4835
4836proto._addShiftTarget = function( x, y, boundsSize ) {
4837  var checkCoord = this._getOption('horizontal') ? y : x;
4838  if ( checkCoord !== 0 && checkCoord > boundsSize ) {
4839    return;
4840  }
4841  // create string for a key, easier to keep track of what targets
4842  var key = x + ',' + y;
4843  var hasKey = this.shiftTargetKeys.indexOf( key ) != -1;
4844  if ( hasKey ) {
4845    return;
4846  }
4847  this.shiftTargetKeys.push( key );
4848  this.shiftTargets.push({ x: x, y: y });
4849};
4850
4851// -------------------------- drop -------------------------- //
4852
4853proto.shift = function( item, x, y ) {
4854  var shiftPosition;
4855  var minDistance = Infinity;
4856  var position = { x: x, y: y };
4857  this.shiftTargets.forEach( function( target ) {
4858    var distance = getDistance( target, position );
4859    if ( distance < minDistance ) {
4860      shiftPosition = target;
4861      minDistance = distance;
4862    }
4863  });
4864  item.rect.x = shiftPosition.x;
4865  item.rect.y = shiftPosition.y;
4866};
4867
4868function getDistance( a, b ) {
4869  var dx = b.x - a.x;
4870  var dy = b.y - a.y;
4871  return Math.sqrt( dx * dx + dy * dy );
4872}
4873
4874// -------------------------- drag move -------------------------- //
4875
4876var DRAG_THROTTLE_TIME = 120;
4877
4878/**
4879 * handle an item drag move event
4880 * @param {Element} elem
4881 * @param {Number} x - horizontal change in position
4882 * @param {Number} y - vertical change in position
4883 */
4884proto.itemDragMove = function( elem, x, y ) {
4885  var item = this.isEnabled && this.getItem( elem );
4886  if ( !item ) {
4887    return;
4888  }
4889
4890  x -= this.size.paddingLeft;
4891  y -= this.size.paddingTop;
4892
4893  var _this = this;
4894  function onDrag() {
4895    _this.shift( item, x, y );
4896    item.positionDropPlaceholder();
4897    _this.layout();
4898  }
4899
4900  // throttle
4901  var now = new Date();
4902  if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) {
4903    clearTimeout( this.dragTimeout );
4904    this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME );
4905  } else {
4906    onDrag();
4907    this._itemDragTime = now;
4908  }
4909};
4910
4911// -------------------------- drag end -------------------------- //
4912
4913/**
4914 * handle an item drag end event
4915 * @param {Element} elem
4916 */
4917proto.itemDragEnd = function( elem ) {
4918  var item = this.isEnabled && this.getItem( elem );
4919  if ( !item ) {
4920    return;
4921  }
4922
4923  clearTimeout( this.dragTimeout );
4924  item.element.classList.add('is-positioning-post-drag');
4925
4926  var completeCount = 0;
4927  var _this = this;
4928  function onDragEndLayoutComplete() {
4929    completeCount++;
4930    if ( completeCount != 2 ) {
4931      return;
4932    }
4933    // reset drag item
4934    item.element.classList.remove('is-positioning-post-drag');
4935    item.hideDropPlaceholder();
4936    _this.dispatchEvent( 'dragItemPositioned', null, [ item ] );
4937  }
4938
4939  item.once( 'layout', onDragEndLayoutComplete );
4940  this.once( 'layoutComplete', onDragEndLayoutComplete );
4941  item.moveTo( item.rect.x, item.rect.y );
4942  this.layout();
4943  this.dragItemCount = Math.max( 0, this.dragItemCount - 1 );
4944  this.sortItemsByPosition();
4945  item.disablePlacing();
4946  this.unstamp( item.element );
4947};
4948
4949/**
4950 * binds Draggabilly events
4951 * @param {Draggabilly} draggie
4952 */
4953proto.bindDraggabillyEvents = function( draggie ) {
4954  this._bindDraggabillyEvents( draggie, 'on' );
4955};
4956
4957proto.unbindDraggabillyEvents = function( draggie ) {
4958  this._bindDraggabillyEvents( draggie, 'off' );
4959};
4960
4961proto._bindDraggabillyEvents = function( draggie, method ) {
4962  var handlers = this.handleDraggabilly;
4963  draggie[ method ]( 'dragStart', handlers.dragStart );
4964  draggie[ method ]( 'dragMove', handlers.dragMove );
4965  draggie[ method ]( 'dragEnd', handlers.dragEnd );
4966};
4967
4968/**
4969 * binds jQuery UI Draggable events
4970 * @param {jQuery} $elems
4971 */
4972proto.bindUIDraggableEvents = function( $elems ) {
4973  this._bindUIDraggableEvents( $elems, 'on' );
4974};
4975
4976proto.unbindUIDraggableEvents = function( $elems ) {
4977  this._bindUIDraggableEvents( $elems, 'off' );
4978};
4979
4980proto._bindUIDraggableEvents = function( $elems, method ) {
4981  var handlers = this.handleUIDraggable;
4982  $elems
4983    [ method ]( 'dragstart', handlers.start )
4984    [ method ]( 'drag', handlers.drag )
4985    [ method ]( 'dragstop', handlers.stop );
4986};
4987
4988// ----- destroy ----- //
4989
4990var _destroy = proto.destroy;
4991proto.destroy = function() {
4992  _destroy.apply( this, arguments );
4993  // disable flag; prevent drag events from triggering. #72
4994  this.isEnabled = false;
4995};
4996
4997// -----  ----- //
4998
4999Packery.Rect = Rect;
5000Packery.Packer = Packer;
5001
5002return Packery;
5003
5004}));
5005
5006/*!
5007 * Packery layout mode v2.0.1
5008 * sub-classes Packery
5009 */
5010
5011/*jshint browser: true, strict: true, undef: true, unused: true */
5012
5013( function( window, factory ) {
5014
5015  // universal module definition
5016  if ( typeof define == 'function' && define.amd ) {
5017    // AMD
5018    define( [
5019        'isotope-layout/js/layout-mode',
5020        'packery/js/packery'
5021      ],
5022      factory );
5023  } else if ( typeof module == 'object' && module.exports ) {
5024    // CommonJS
5025    module.exports = factory(
5026      require('isotope-layout/js/layout-mode'),
5027      require('packery')
5028    );
5029  } else {
5030    // browser global
5031    factory(
5032      window.Isotope.LayoutMode,
5033      window.Packery
5034    );
5035  }
5036
5037}( window, function factor( LayoutMode, Packery ) {
5038
5039
5040  // create an Outlayer layout class
5041  var PackeryMode = LayoutMode.create('packery');
5042  var proto = PackeryMode.prototype;
5043
5044  var keepModeMethods = {
5045    _getElementOffset: true,
5046    _getMeasurement: true
5047  };
5048
5049  // inherit Packery prototype
5050  for ( var method in Packery.prototype ) {
5051    // do not inherit mode methods
5052    if ( !keepModeMethods[ method ] ) {
5053      proto[ method ] = Packery.prototype[ method ];
5054    }
5055  }
5056
5057  // set packer in _resetLayout
5058  var _resetLayout = proto._resetLayout;
5059  proto._resetLayout = function() {
5060    this.packer = this.packer || new Packery.Packer();
5061    this.shiftPacker = this.shiftPacker || new Packery.Packer();
5062    _resetLayout.apply( this, arguments );
5063  };
5064
5065  var _getItemLayoutPosition = proto._getItemLayoutPosition;
5066  proto._getItemLayoutPosition = function( item ) {
5067    // set packery rect
5068    item.rect = item.rect || new Packery.Rect();
5069    return _getItemLayoutPosition.call( this, item );
5070  };
5071
5072  // needsResizeLayout for vertical or horizontal
5073  var _needsResizeLayout = proto.needsResizeLayout;
5074  proto.needsResizeLayout = function() {
5075    if ( this._getOption('horizontal') ) {
5076      return this.needsVerticalResizeLayout();
5077    } else {
5078      return _needsResizeLayout.call( this );
5079    }
5080  };
5081
5082  // point to mode options for horizontal
5083  var _getOption = proto._getOption;
5084  proto._getOption = function( option ) {
5085    if ( option == 'horizontal' ) {
5086      return this.options.isHorizontal !== undefined ?
5087        this.options.isHorizontal : this.options.horizontal;
5088    }
5089    return _getOption.apply( this.isotope, arguments );
5090  };
5091
5092  return PackeryMode;
5093
5094}));
5095
5096/*!
5097 * cellsByRows layout mode for Isotope
5098 * v1.1.3
5099 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html
5100 */
5101
5102/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */
5103
5104( function( window, factory ) {
5105  // universal module definition
5106  /* jshint strict: false */ /*globals define, module, require */
5107  if ( typeof define === 'function' && define.amd ) {
5108    // AMD
5109    define( [
5110        'isotope/js/layout-mode'
5111      ],
5112      factory );
5113  } else if ( typeof exports === 'object' ) {
5114    // CommonJS
5115    module.exports = factory(
5116      require('isotope-layout/js/layout-mode')
5117    );
5118  } else {
5119    // browser global
5120    factory(
5121      window.Isotope.LayoutMode
5122    );
5123  }
5124
5125}( window, function factory( LayoutMode ) {
5126  'use strict';
5127
5128  var CellsByRow = LayoutMode.create( 'cellsByRow' );
5129  var proto = CellsByRow.prototype;
5130
5131  proto._resetLayout = function() {
5132    // reset properties
5133    this.itemIndex = 0;
5134    // measurements
5135    this.getColumnWidth();
5136    this.getRowHeight();
5137    // set cols
5138    this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth );
5139    this.cols = Math.max( this.cols, 1 );
5140  };
5141
5142  proto._getItemLayoutPosition = function( item ) {
5143    item.getSize();
5144    var col = this.itemIndex % this.cols;
5145    var row = Math.floor( this.itemIndex / this.cols );
5146    // center item within cell
5147    var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2;
5148    var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2;
5149    this.itemIndex++;
5150    return { x: x, y: y };
5151  };
5152
5153  proto._getContainerSize = function() {
5154    return {
5155      height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight
5156    };
5157  };
5158
5159  return CellsByRow;
5160
5161}));
5162/*global jQuery: true */
5163
5164/*!
5165   --------------------------------
5166   Infinite Scroll
5167   --------------------------------
5168   + https://github.com/paulirish/infinite-scroll
5169   + version 2.1.0
5170   + Copyright 2011/12 Paul Irish & Luke Shumard
5171   + Licensed under the MIT license
5172
5173   + Documentation: http://infinite-scroll.com/
5174*/
5175
5176// Uses AMD or browser globals to create a jQuery plugin.
5177(function (factory) {
5178    if (typeof define === 'function' && define.amd) {
5179        // AMD. Register as an anonymous module.
5180        define(['jquery'], factory);
5181    } else {
5182        // Browser globals
5183        factory(jQuery);
5184    }
5185}(function ($, undefined) {
5186    'use strict';
5187
5188    $.infinitescroll = function infscr(options, callback, element) {
5189        this.element = $(element);
5190
5191        // Flag the object in the event of a failed creation
5192        if (!this._create(options, callback)) {
5193            this.failed = true;
5194        }
5195    };
5196
5197    $.infinitescroll.defaults = {
5198        loading: {
5199            finished: undefined,
5200            finishedMsg: "<em>Congratulations, you've reached the end of the internet.</em>",
5201            img: 'data:image/gif;base64,R0lGODlh3AATAPQeAPDy+MnQ6LW/4N3h8MzT6rjC4sTM5r/I5NHX7N7j8c7U6tvg8OLl8uXo9Ojr9b3G5MfP6Ovu9tPZ7PT1+vX2+tbb7vf4+8/W69jd7rC73vn5/O/x+K243ai02////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQECgD/ACwAAAAA3AATAAAF/6AnjmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEj0BAScpHLJbDqf0Kh0Sq1ar9isdioItAKGw+MAKYMFhbF63CW438f0mg1R2O8EuXj/aOPtaHx7fn96goR4hmuId4qDdX95c4+RBIGCB4yAjpmQhZN0YGYGXitdZBIVGAsLoq4BBKQDswm1CQRkcG6ytrYKubq8vbfAcMK9v7q7EMO1ycrHvsW6zcTKsczNz8HZw9vG3cjTsMIYqQkCLBwHCgsMDQ4RDAYIqfYSFxDxEfz88/X38Onr16+Bp4ADCco7eC8hQYMAEe57yNCew4IVBU7EGNDiRn8Z831cGLHhSIgdFf9chIeBg7oA7gjaWUWTVQAGE3LqBDCTlc9WOHfm7PkTqNCh54rePDqB6M+lR536hCpUqs2gVZM+xbrTqtGoWqdy1emValeXKzggYBBB5y1acFNZmEvXAoN2cGfJrTv3bl69Ffj2xZt3L1+/fw3XRVw4sGDGcR0fJhxZsF3KtBTThZxZ8mLMgC3fRatCbYMNFCzwLEqLgE4NsDWs/tvqdezZf13Hvk2A9Szdu2X3pg18N+68xXn7rh1c+PLksI/Dhe6cuO3ow3NfV92bdArTqC2Ebd3A8vjf5QWfH6Bg7Nz17c2fj69+fnq+8N2Lty+fuP78/eV2X13neIcCeBRwxorbZrA1ANoCDGrgoG8RTshahQ9iSKEEzUmYIYfNWViUhheCGJyIP5E4oom7WWjgCeBFAJNv1DVV01MAdJhhjdkplWNzO/5oXI846njjVEIqR2OS2B1pE5PVscajkxhMycqLJghQSwT40PgfAl4GqNSXYdZXJn5gSkmmmmJu1aZYb14V51do+pTOCmA40AqVCIhG5IJ9PvYnhIFOxmdqhpaI6GeHCtpooisuutmg+Eg62KOMKuqoTaXgicQWoIYq6qiklmoqFV0UoeqqrLbq6quwxirrrLTWauutJ4QAACH5BAUKABwALAcABADOAAsAAAX/IPd0D2dyRCoUp/k8gpHOKtseR9yiSmGbuBykler9XLAhkbDavXTL5k2oqFqNOxzUZPU5YYZd1XsD72rZpBjbeh52mSNnMSC8lwblKZGwi+0QfIJ8CncnCoCDgoVnBHmKfByGJimPkIwtiAeBkH6ZHJaKmCeVnKKTHIihg5KNq4uoqmEtcRUtEREMBggtEr4QDrjCuRC8h7/BwxENeicSF8DKy82pyNLMOxzWygzFmdvD2L3P0dze4+Xh1Arkyepi7dfFvvTtLQkZBC0T/FX3CRgCMOBHsJ+EHYQY7OinAGECgQsB+Lu3AOK+CewcWjwxQeJBihtNGHSoQOE+iQ3//4XkwBBhRZMcUS6YSXOAwIL8PGqEaSJCiYt9SNoCmnJPAgUVLChdaoFBURN8MAzl2PQphwQLfDFd6lTowglHve6rKpbjhK7/pG5VinZP1qkiz1rl4+tr2LRwWU64cFEihwEtZgbgR1UiHaMVvxpOSwBA37kzGz9e8G+B5MIEKLutOGEsAH2ATQwYfTmuX8aETWdGPZmiZcccNSzeTCA1Sw0bdiitC7LBWgu8jQr8HRzqgpK6gX88QbrB14z/kF+ELpwB8eVQj/JkqdylAudji/+ts3039vEEfK8Vz2dlvxZKG0CmbkKDBvllRd6fCzDvBLKBDSCeffhRJEFebFk1k/Mv9jVIoIJZSeBggwUaNeB+Qk34IE0cXlihcfRxkOAJFFhwGmKlmWDiakZhUJtnLBpnWWcnKaAZcxI0piFGGLBm1mc90kajSCveeBVWKeYEoU2wqeaQi0PetoE+rr14EpVC7oAbAUHqhYExbn2XHHsVqbcVew9tx8+XJKk5AZsqqdlddGpqAKdbAYBn1pcczmSTdWvdmZ17c1b3FZ99vnTdCRFM8OEcAhLwm1NdXnWcBBSMRWmfkWZqVlsmLIiAp/o1gGV2vpS4lalGYsUOqXrddcKCmK61aZ8SjEpUpVFVoCpTj4r661Km7kBHjrDyc1RAIQAAIfkEBQoAGwAsBwAEAM4ACwAABf/gtmUCd4goQQgFKj6PYKi0yrrbc8i4ohQt12EHcal+MNSQiCP8gigdz7iCioaCIvUmZLp8QBzW0EN2vSlCuDtFKaq4RyHzQLEKZNdiQDhRDVooCwkbfm59EAmKi4SGIm+AjIsKjhsqB4mSjT2IOIOUnICeCaB/mZKFNTSRmqVpmJqklSqskq6PfYYCDwYHDC4REQwGCBLGxxIQDsHMwhAIX8bKzcENgSLGF9PU1j3Sy9zX2NrgzQziChLk1BHWxcjf7N046tvN82715czn9Pryz6Ilc4ACj4EBOCZM8KEnAYYADBRKnACAYUMFv1wotIhCEcaJCisqwJFgAUSQGyX/kCSVUUTIdKMwJlyo0oXHlhskwrTJciZHEXsgaqS4s6PJiCAr1uzYU8kBBSgnWFqpoMJMUjGtDmUwkmfVmVypakWhEKvXsS4nhLW5wNjVroJIoc05wSzTr0PtiigpYe4EC2vj4iWrFu5euWIMRBhacaVJhYQBEFjA9jHjyQ0xEABwGceGAZYjY0YBOrRLCxUp29QM+bRkx5s7ZyYgVbTqwwti2ybJ+vLtDYpycyZbYOlptxdx0kV+V7lC5iJAyyRrwYKxAdiz82ng0/jnAdMJFz0cPi104Ec1Vj9/M6F173vKL/feXv156dw11tlqeMMnv4V5Ap53GmjQQH97nFfg+IFiucfgRX5Z8KAgbUlQ4IULIlghhhdOSB6AgX0IVn8eReghen3NRIBsRgnH4l4LuEidZBjwRpt6NM5WGwoW0KSjCwX6yJSMab2GwwAPDXfaBCtWpluRTQqC5JM5oUZAjUNS+VeOLWpJEQ7VYQANW0INJSZVDFSnZphjSikfmzE5N4EEbQI1QJmnWXCmHulRp2edwDXF43txukenJwvI9xyg9Q26Z3MzGUcBYFEChZh6DVTq34AU8Iflh51Sd+CnKFYQ6mmZkhqfBKfSxZWqA9DZanWjxmhrWwi0qtCrt/43K6WqVjjpmhIqgEGvculaGKklKstAACEAACH5BAUKABwALAcABADOAAsAAAX/ICdyQmaMYyAUqPgIBiHPxNpy79kqRXH8wAPsRmDdXpAWgWdEIYm2llCHqjVHU+jjJkwqBTecwItShMXkEfNWSh8e1NGAcLgpDGlRgk7EJ/6Ae3VKfoF/fDuFhohVeDeCfXkcCQqDVQcQhn+VNDOYmpSWaoqBlUSfmowjEA+iEAEGDRGztAwGCDcXEA60tXEiCrq8vREMEBLIyRLCxMWSH
5201MzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/Cpk3ABwSLQkYAQwT/P309vcI7OvXr94jBQMJ/nskkGA/BQBRLNDncAIAiDcG6LsxAWOLiQzmeURBKWSLCQbv/1F0eDGinJUKR47YY1IEgQASKk7Yc7ACRwZm7mHweRJoz59BJUogisKCUaFMR0x4SlJBVBFTk8pZivTR0K73rN5wqlXEAq5Fy3IYgHbEzQ0nLy4QSoCjXLoom96VOJEeCosK5n4kkFfqXjl94wa+l1gvAcGICbewAOAxY8l/Ky/QhAGz4cUkGxu2HNozhwMGBnCUqUdBg9UuW9eUynqSwLHIBujePef1ZGQZXcM+OFuEBeBhi3OYgLyqcuaxbT9vLkf4SeqyWxSQpKGB2gQpm1KdWbu72rPRzR9Ne2Nu9Kzr/1Jqj0yD/fvqP4aXOt5sW/5qsXXVcv1Nsp8IBUAmgswGF3llGgeU1YVXXKTN1FlhWFXW3gIE+DVChApysACHHo7Q4A35lLichh+ROBmLKAzgYmYEYDAhCgxKGOOMn4WR4kkDaoBBOxJtdNKQxFmg5JIWIBnQc07GaORfUY4AEkdV6jHlCEISSZ5yTXpp1pbGZbkWmcuZmQCaE6iJ0FhjMaDjTMsgZaNEHFRAQVp3bqXnZED1qYcECOz5V6BhSWCoVJQIKuKQi2KFKEkEFAqoAo7uYSmO3jk61wUUMKmknJ4SGimBmAa0qVQBhAAAIfkEBQoAGwAsBwAEAM4ACwAABf/gJm5FmRlEqhJC+bywgK5pO4rHI0D3pii22+Mg6/0Ej96weCMAk7cDkXf7lZTTnrMl7eaYoy10JN0ZFdco0XAuvKI6qkgVFJXYNwjkIBcNBgR8TQoGfRsJCRuCYYQQiI+ICosiCoGOkIiKfSl8mJkHZ4U9kZMbKaI3pKGXmJKrngmug4WwkhA0lrCBWgYFCCMQFwoQDRHGxwwGCBLMzRLEx8iGzMMO0cYNeCMKzBDW19lnF9DXDIY/48Xg093f0Q3s1dcR8OLe8+Y91OTv5wrj7o7B+7VNQqABIoRVCMBggsOHE36kSoCBIcSH3EbFangxogJYFi8CkJhqQciLJEf/LDDJEeJIBT0GsOwYUYJGBS0fjpQAMidGmyVP6sx4Y6VQhzs9VUwkwqaCCh0tmKoFtSMDmBOf9phg4SrVrROuasRQAaxXpVUhdsU6IsECZlvX3kwLUWzRt0BHOLTbNlbZG3vZinArge5Dvn7wbqtQkSYAAgtKmnSsYKVKo2AfW048uaPmG386i4Q8EQMBAIAnfB7xBxBqvapJ9zX9WgRS2YMpnvYMGdPK3aMjt/3dUcNI4blpj7iwkMFWDXDvSmgAlijrt9RTR78+PS6z1uAJZIe93Q8g5zcsWCi/4Y+C8bah5zUv3vv89uft30QP23punGCx5954oBBwnwYaNCDY/wYrsYeggnM9B2Fpf8GG2CEUVWhbWAtGouEGDy7Y4IEJVrbSiXghqGKIo7z1IVcXIkKWWR361QOLWWnIhwERpLaaCCee5iMBGJQmJGyPFTnbkfHVZGRtIGrg5HALEJAZbu39BuUEUmq1JJQIPtZilY5hGeSWsSk52G9XqsmgljdIcABytq13HyIM6RcUA+r1qZ4EBF3WHWB29tBgAzRhEGhig8KmqKFv8SeCeo+mgsF7YFXa1qWSbkDpom/mqR1PmHCqJ3fwNRVXjC7S6CZhFVCQ2lWvZiirhQq42SACt25IK2hv8TprriUV1usGgeka7LFcNmCldMLi6qZMgFLgpw16Cipb7bC1knXsBiEAACH5BAUKABsALAcABADOAAsAAAX/4FZsJPkUmUGsLCEUTywXglFuSg7fW1xAvNWLF6sFFcPb42C8EZCj24EJdCp2yoegWsolS0Uu6fmamg8n8YYcLU2bXSiRaXMGvqV6/KAeJAh8VgZqCX+BexCFioWAYgqNi4qAR4ORhRuHY408jAeUhAmYYiuVlpiflqGZa5CWkzc5fKmbbhIpsAoQDRG8vQwQCBLCwxK6vb5qwhfGxxENahvCEA7NzskSy7vNzzzK09W/PNHF1NvX2dXcN8K55cfh69Luveol3vO8zwi4Yhj+AQwmCBw4IYclDAAJDlQggVOChAoLKkgFkSCAHDwWLKhIEOONARsDKryogFPIiAUb/95gJNIiw4wnI778GFPhzBKFOAq8qLJEhQpiNArjMcHCmlTCUDIouTKBhApELSxFWiGiVKY4E2CAekPgUphDu0742nRrVLJZnyrFSqKQ2ohoSYAMW6IoDpNJ4bLdILTnAj8KUF7UeENjAKuDyxIgOuGiOI0EBBMgLNew5AUrDTMGsFixwBIaNCQuAXJB57qNJ2OWm2Aj4skwCQCIyNkhhtMkdsIuodE0AN4LJDRgfLPtn5YDLdBlraAByuUbBgxQwICxMOnYpVOPej074OFdlfc0TqC62OIbcppHjV4o+LrieWhfT8JC/I/T6W8oCl29vQ0XjLdBaA3s1RcPBO7lFvpX8BVoG4O5jTXRQRDuJ6FDTzEWF1/BCZhgbyAKE9qICYLloQYOFtahVRsWYlZ4KQJHlwHS/IYaZ6sZd9tmu5HQm2xi1UaTbzxYwJk/wBF5g5EEYOBZeEfGZmNdFyFZmZIR4jikbLThlh5kUUVJGmRT7sekkziRWUIACABk3T4qCsedgO4xhgGcY7q5pHJ4klBBTQRJ0CeHcoYHHUh6wgfdn9uJdSdMiebGJ0zUPTcoS286FCkrZxnYoYYKWLkBowhQoBeaOlZAgVhLidrXqg2G
5201iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/oGFw2WZuT5oZROsSQnGaKjRvilI893MItlNOJ5v5gDcFrHhKIWcEYu/xFEqNv6B1N62aclysF7fsZYe5aOx2yL5aAUGSaT1oTYMBwQ5VGCAJgYIJCnx1gIOBhXdwiIl7d0p2iYGQUAQBjoOFSQR/lIQHnZ+Ue6OagqYzSqSJi5eTpTxGcjcSChANEbu8DBAIEsHBChe5vL13G7fFuscRDcnKuM3H0La3EA7Oz8kKEsXazr7Cw9/Gztar5uHHvte47MjktznZ2w0G1+D3BgirAqJmJMAQgMGEgwgn5Ei0gKDBhBMALGRYEOJBb5QcWlQo4cbAihZz3GgIMqFEBSM1/4ZEOWPAgpIIJXYU+PIhRG8ja1qU6VHlzZknJNQ6UanCjQkWCIGSUGEjAwVLjc44+DTqUQtPPS5gejUrTa5TJ3g9sWCr1BNUWZI161StiQUDmLYdGfesibQ3XMq1OPYthrwuA2yU2LBs2cBHIypYQPPlYAKFD5cVvNPtW8eVGbdcQADATsiNO4cFAPkvHpedPzc8kUcPgNGgZ5RNDZG05reoE9s2vSEP79MEGiQGy1qP8LA4ZcdtsJE48ONoLTBtTV0B9LsTnPceoIDBDQvS7W7vfjVY3q3eZ4A339J4eaAmKqU/sV58HvJh2RcnIBsDUw0ABqhBA5aV5V9XUFGiHfVeAiWwoFgJJrIXRH1tEMiDFV4oHoAEGlaWhgIGSGBO2nFomYY3mKjVglidaNYJGJDkWW2xxTfbjCbVaOGNqoX2GloR8ZeTaECS9pthRGJH2g0b3Agbk6hNANtteHD2GJUucfajCQBy5OOTQ25ZgUPvaVVQmbKh9510/qQpwXx3SQdfk8tZJOd5b6JJFplT3ZnmmX3qd5l1eg5q00HrtUkUn0AKaiGjClSAgKLYZcgWXwocGRcCFGCKwSB6ceqphwmYRUFYT/1WKlOdUpipmxW0mlCqHjYkAaeoZlqrqZ4qd+upQKaapn/AmgAegZ8KUtYtFAQQAgAh+QQFCgAbACwHAAQAzgALAAAF/+C2PUcmiCiZGUTrEkKBis8jQEquKwU5HyXIbEPgyX7BYa5wTNmEMwWsSXsqFbEh8DYs9mrgGjdK6GkPY5GOeU6ryz7UFopSQEzygOGhJBjoIgMDBAcBM0V/CYqLCQqFOwobiYyKjn2TlI6GKC2YjJZknouaZAcQlJUHl6eooJwKooobqoewrJSEmyKdt59NhRKFMxLEEA4RyMkMEAjDEhfGycqAG8TQx9IRDRDE3d3R2ctD1RLg0ttKEnbY5wZD3+zJ6M7X2RHi9Oby7u/r9g38UFjTh2xZJBEBMDAboogAgwkQI07IMUORwocSJwCgWDFBAIwZOaJIsOBjRogKJP8wTODw5ESVHVtm3AhzpEeQElOuNDlTZ0ycEUWKWFASqEahGwYUPbnxoAgEdlYSqDBkgoUNClAlIHbSAoOsqCRQnQHxq1axVb06FWFxLIqyaze0Tft1JVqyE+pWXMD1pF6bYl3+HTqAWNW8cRUFzmih0ZAAB2oGKukSAAGGRHWJgLiR6AylBLpuHKKUMlMCngMpDSAa9QIUggZVVvDaJobLeC3XZpvgNgCmtPcuwP3WgmXSq4do0DC6o2/guzcseECtUoO0hmcsGKDgOt7ssBd07wqesAIGZC1YIBa7PQHvb1+SFo+++HrJSQfB33xfav3i5eX3Hnb4CTJgegEq8tH/YQEOcIJzbm2G2EoYRLgBXFpVmFYDcREV4HIcnmUhiGBRouEMJGJGzHIspqgdXxK0yCKHRNXoIX4uorCdTyjkyNtdPWrA4Up82EbAbzMRxxZRR54WXVLDIRmRcag5d2R6ugl3ZXzNhTecchpMhIGVAKAYpgJjjsSklBEd99maZoo535ZvdamjBEpusJyctg3h4X8XqodBMx0tiNeg/oGJaKGABpogS40KSqiaEgBqlQWLUtqoVQnytekEjzo0hHqhRorppOZt2p923M2AAV+oBtpAnnPNoB6HaU6mAAIU+IXmi3j2mtFXuUoHKwXpzVrsjcgGOauKEjQrwq157hitGq2NoWmjh7z6Wmxb0m5w66+2VRAuXN/yFUAIACH5BAUKABsALAcABADOAAsAAAX/4CZuRiaM45MZqBgIRbs9AqTcuFLE7VHLOh7KB5ERdjJaEaU4ClO/lgKWjKKcMiJQ8KgumcieVdQMD8cbBeuAkkC6LYLhOxoQ2PF5Ys9PKPBMen17f0CCg4VSh32JV4t8jSNqEIOEgJKPlkYBlJWRInKdiJdkmQlvKAsLBxdABA4RsbIMBggtEhcQsLKxDBC2TAS6vLENdJLDxMZAubu8vjIbzcQRtMzJz79S08oQEt/guNiyy7fcvMbh4OezdAvGrakLAQwyABsELQkY9BP+//ckyPDD4J9BfAMh1GsBoImMeQUN+lMgUJ9CiRMa5msxoB9Gh/o8GmxYMZXIgxtR/yQ46S/gQAURR0pDwYDfywoyLPip5AdnCwsMFPBU4BPFhKBDi444quCmDKZOfwZ9KEGpCKgcN1jdALSpPqIYsabS+nSqvqplvYqQYAeDPgwKwjaMtiDl0oaqUAyo+3TuWwUAMPpVCfee0cEjVBGQq2ABx7oTWmQk4FglZMGN9fGVDMCuiH2AOVOu/PmyxM630gwM0CCn6q8LjVJ8GXvpa5Uwn95OTC/nNxkda1/dLSK475IjCD6dHbK1ZOa4hXP9DXs5chJ00UpVm5xo2qRpoxptwF2E4/IbJpB/SDz9+q9b1aNfQH08+p4a8uvX8B53fLP+ycAfemjsRUBgp1H20K+BghHgVgt1GXZXZpZ5lt4ECjxYR4ScUWiShEtZqBiIInRGWnERNnjiBglw+JyGnxUmGowsyiiZg189lNtPGACjV2+S9UjbU0JWF6SPvEk3QZEqsZYTk3UAaRSUnznJI5LmESCdBVSyaOWUWLK4I5gDUYVeV1T9l+FZClCAUVA09uSmRHBCKAECFEhW51ht6rnmWBXkaR+NjuHpJ40D3DmnQXt2F+ihZxlqVKOfQRACACH5BAUKABwALAcABADOAAsAAAX/ICdyUCkUo/g8mUG8MCGkKgspeC6j6XEIEBpBUeCNfECaglBcOVfJFK7YQwZHQ6JRZBUqTrSuVEuD3nI45pYjFuWKvjjSkCoRaBUMWxkwBGgJCXspQ36Bh4EEB0oKhoiBgyNLjo8Ki4QElIiWfJqHnISNEI+Ql5J9o6SgkqKkgqYihamPkW6oNBgSfiMMDQkGCBLCwxIQDhHIyQwQCGMKxsnKVyPCF9DREQ3MxMPX0cu4wt7J2uHWx9jlKd3o39MiuefYEcvNkuLt5O8c1ePI2tyELXGQwoGDAQf+iEC2xByDCRAjTlAgIUWCBRgCPJQ4AQBFXAs0coT40WLIjRxL/47AcHLkxIomRXL0CHPERZkpa4q4iVKiyp0tR/7kwHMkTUBBJR5dOCEBAVcKKtCAyOHpowXCpk7goABqBZdcvWploACpBKkpIJI1q5OD2rIWE0R1uTZu1LFwbWL9OlKuWb4c6+o9i3dEgw0RCGDUG9KlRw56gDY2qmCByZBaASi+TACA0TucAaTteCcy0ZuOK3N2vJlx58+LRQyY3Xm0ZsgjZg+oPQLi7dUcNXi0LOJw1pgNtB7XG6CBy+U75SYfPTSQAgZTNUDnQHt67wnbZyvwLgKiMN3oCZB3C76tdewpLFgIP2C88rbi4Y+QT3+8S5USMICZXWj1pkEDeUU3lOYGB3alSoEiMIjgX4WlgNF2EibIwQIXauWXSRg2SAOHIU5IIIMoZkhhWiJaiFVbKo6AQEgQXrTAazO1JhkBrBG3Y2Y6EsUhaGn95hprSN0oWpFE7rhkeaQBchGOEWnwEmc0uKWZj0LeuNV3W4Y2lZHFlQCSRjTIl8uZ+kG5HU/3sRlnTG2ytyadytnD3HrmuRcSn+0h1dycexIK1KCjYaCnjCCVqOFFJTZ5GkUUjESWaUIKU2lgCmAKKQIUjHapXRKE+t2og1VgankNYnohqKJ2CmKplso6GKz7WYCgqxeuyoF8u9IQAgA7',
5202            msg: null,
5203            msgText: '<em>Loading the next set of posts...</em>',
5204            selector: null,
5205            speed: 'fast',
5206            start: undefined
5207        },
5208        state: {
5209            isDuringAjax: false,
5210            isInvalidPage: false,
5211            isDestroyed: false,
5212            isDone: false, // For when it goes all the way through the archive.
5213            isPaused: false,
5214            isBeyondMaxPage: false,
5215            currPage: 1
5216        },
5217        debug: false,
5218        behavior: undefined,
5219        binder: $(window), // used to cache the selector
5220        nextSelector: 'div.navigation a:first',
5221        navSelector: 'div.navigation',
5222        contentSelector: null, // rename to pageFragment
5223        extraScrollPx: 150,
5224        itemSelector: 'div.post',
5225        animate: false,
5226        pathParse: undefined,
5227        dataType: 'html',
5228        appendCallback: true,
5229        bufferPx: 40,
5230        errorCallback: function () { },
5231        infid: 0, //Instance ID
5232        pixelsFromNavToBottom: undefined,
5233        path: undefined, // Either parts of a URL as an array (e.g. ["/page/", "/"] or a function that takes in the page number and returns a URL
5234        prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted
5235        maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work)
5236    };
5237
5238    $.infinitescroll.prototype = {
5239
5240        /*
5241            ----------------------------
5242            Private methods
5243            ----------------------------
5244            */
5245
5246        // Bind or unbind from scroll
5247        _binding: function infscr_binding(binding) {
5248
5249            var instance = this,
5250            opts = instance.options;
5251
5252            opts.v = '2.0b2.120520';
5253
5254            // if behavior is defined and this function is extended, call that instead of default
5255            if (!!opts.behavior && this['_binding_'+opts.behavior] !== undefined) {
5256                this['_binding_'+opts.behavior].call(this);
5257                return;
5258            }
5259
5260            if (binding !== 'bind' && binding !== 'unbind') {
5261                this._debug('Binding value  ' + binding + ' not valid');
5262                return false;
5263            }
5264
5265            if (binding === 'unbind') {
5266                (this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid);
5267            } else {
5268                (this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () {
5269                    instance.scroll();
5270                });
5271            }
5272
5273            this._debug('Binding', binding);
5274        },
5275
5276        // Fundamental aspects of the plugin are initialized
5277        _create: function infscr_create(options, callback) {
5278
5279            // Add custom options to defaults
5280            var opts = $.extend(true, {}, $.infinitescroll.defaults, options);
5281            this.options = opts;
5282            var $window = $(window);
5283            var instance = this;
5284
5285            // Validate selectors
5286            if (!instance._validate(options)) {
5287                return false;
5288            }
5289
5290            // Validate page fragment path
5291            var path = $(opts.nextSelector).attr('href');
5292            if (!path) {
5293                this._debug('Navigation selector not found');
5294                return false;
5295            }
5296
5297            // Set the path to be a relative URL from root.
5298            opts.path = opts.path || this._determinepath(path);
5299
5300            // contentSelector is 'page fragment' option for .load() / .ajax() calls
5301            opts.contentSelector = opts.contentSelector || this.element;
5302
5303            // loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector
5304            opts.loading.selector = opts.loading.selector || opts.contentSelector;
5305
5306            // Define loading.msg
5307            opts.loading.msg = opts.loading.msg || $('<div id="infscr-loading"><img alt="Loading..." src="' + opts.loading.img + '" /><div>' + opts.loading.msgText + '</div></div>');
5308
5309            // Preload loading.img
5310            (new Image()).src = opts.loading.img;
5311
5312            // distance from nav links to bottom
5313            // computed as: height of the document + top offset of container - top offset of nav link
5314            if(opts.pixelsFromNavToBottom === undefined) {
5315                opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top;
5316                this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom);
5317            }
5318
5319            var self = this;
5320
5321            // determine loading.start actions
5322            opts.loading.start = opts.loading.start || function() {
5323                $(opts.navSelector).hide();
5324                opts.loading.msg
5325                .appendTo(opts.loading.selector)
5326                .show(opts.loading.speed, $.proxy(function() {
5327                    this.beginAjax(opts);
5328                }, self));
5329            };
5330
5331            // determine loading.finished actions
5332            opts.loading.finished = opts.loading.finished || function() {
5333                if (!opts.state.isBeyondMaxPage)
5334                    opts.loading.msg.fadeOut(opts.loading.speed);
5335            };
5336
5337            // callback loading
5338            opts.callback = function(instance, data, url) {
5339                if (!!opts.behavior && instance['_callback_'+opts.behavior] !== undefined) {
5340                    instance['_callback_'+opts.behavior].call($(opts.contentSelector)[0], data, url);
5341                }
5342
5343                if (callback) {
5344                    callback.call($(opts.contentSelector)[0], data, opts, url);
5345                }
5346
5347                if (opts.prefill) {
5348                    $window.bind('resize.infinite-scroll', instance._prefill);
5349                }
5350            };
5351
5352            if (options.debug) {
5353                // Tell IE9 to use its built-in console
5354                if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') {
5355                    ['log','info','warn','error','assert','dir','clear','profile','profileEnd']
5356                        .forEach(function (method) {
5357                            console[method] = this.call(console[method], console);
5358                        }, Function.prototype.bind);
5359                }
5360            }
5361
5362            this._setup();
5363
5364            // Setups the prefill method for use
5365            if (opts.prefill) {
5366                this._prefill();
5367            }
5368
5369            // Return true to indicate successful creation
5370            return true;
5371        },
5372
5373        _prefill: function infscr_prefill() {
5374            var instance = this;
5375            var $window = $(window);
5376
5377            function needsPrefill() {
5378                return ( $(instance.options.contentSelector).height() <= $window.height() );
5379            }
5380
5381            this._prefill = function() {
5382                if (needsPrefill()) {
5383                    instance.scroll();
5384                }
5385
5386                $window.bind('resize.infinite-scroll', function() {
5387                    if (needsPrefill()) {
5388                        $window.unbind('resize.infinite-scroll');
5389                        instance.scroll();
5390                    }
5391                });
5392            };
5393
5394            // Call self after setting up the new function
5395            this._prefill();
5396        },
5397
5398        // Console log wrapper
5399        _debug: function infscr_debug() {
5400            if (true !== this.options.debug) {
5401                return;
5402            }
5403
5404            if (typeof console !== 'undefined' && typeof console.log === 'function') {
5405                // Modern browsers
5406                // Single argument, which is a string
5407                if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') {
5408                    console.log( (Array.prototype.slice.call(arguments)).toString() );
5409                } else {
5410                    console.log( Array.prototype.slice.call(arguments) );
5411                }
5412            } else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') {
5413                // IE8
5414                Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments));
5415            }
5416        },
5417
5418        // find the number to increment in the path.
5419        _determinepath: function infscr_determinepath(path) {
5420
5421            var opts = this.options;
5422
5423            // if behavior is defined and this function is extended, call that instead of default
5424            if (!!opts.behavior && this['_determinepath_'+opts.behavior] !== undefined) {
5425                return this['_determinepath_'+opts.behavior].call(this,path);
5426            }
5427
5428            if (!!opts.pathParse) {
5429
5430                this._debug('pathParse manual');
5431                return opts.pathParse(path, this.options.state.currPage+1);
5432
5433            } else if (path.match(/^(.*?)\b2\b(.*?$)/)) {
5434                path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
5435
5436                // if there is any 2 in the url at all.
5437            } else if (path.match(/^(.*?)2(.*?$)/)) {
5438
5439                // page= is used in django:
5440                // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127
5441                if (path.match(/^(.*?page=)2(\/.*|$)/)) {
5442                    path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1);
5443                    return path;
5444                }
5445
5446                path = path.match(/^(.*?)2(.*?$)/).slice(1);
5447
5448            } else {
5449
5450                // page= is used in drupal too but second page is page=1 not page=2:
5451                // thx Jerod Fritz, vladikoff
5452                if (path.match(/^(.*?page=)1(\/.*|$)/)) {
5453                    path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1);
5454                    return path;
5455                } else {
5456                    this._debug("Sorry, we couldn't parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.");
5457                    // Get rid of isInvalidPage to allow permalink to state
5458                    opts.state.isInvalidPage = true;  //prevent it from running on this page.
5459                }
5460            }
5461            this._debug('determinePath', path);
5462            return path;
5463
5464        },
5465
5466        // Custom error
5467        _error: function infscr_error(xhr) {
5468
5469            var opts = this.options;
5470
5471            // if behavior is defined and this function is extended, call that instead of default
5472            if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) {
5473                this['_error_'+opts.behavior].call(this,xhr);
5474                return;
5475            }
5476
5477            if (xhr !== 'destroy' && xhr !== 'end') {
5478                xhr = 'unknown';
5479            }
5480
5481            this._debug('Error', xhr);
5482
5483            if (xhr === 'end' || opts.state.isBeyondMaxPage) {
5484                this._showdonemsg();
5485            }
5486
5487            opts.state.isDone = true;
5488            opts.state.currPage = 1; // if you need to go back to this instance
5489            opts.state.isPaused = false;
5490            opts.state.isBeyondMaxPage = false;
5491            this._binding('unbind');
5492
5493        },
5494
5495        // Load Callback
5496        _loadcallback: function infscr_loadcallback(box, data, url) {
5497            var opts = this.options,
5498            callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK
5499            result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append',
5500            frag;
5501
5502            // if behavior is defined and this function is extended, call that instead of default
5503            if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) {
5504                this['_loadcallback_'+opts.behavior].call(this,box,data);
5505                return;
5506            }
5507
5508            switch (result) {
5509                case 'done':
5510                    this._showdonemsg();
5511                    return false;
5512
5513                case 'no-append':
5514                    if (opts.dataType === 'html') {
5515                        data = '<div>' + data + '</div>';
5516                        data = $(data).find(opts.itemSelector);
5517                    }
5518
5519                    // if it didn't return anything
5520                    if (data.length === 0) {
5521                        return this._error('end');
5522                    }
5523
5524                    break;
5525
5526                case 'append':
5527                    var children = box.children();
5528                    // if it didn't return anything
5529                    if (children.length === 0) {
5530                        return this._error('end');
5531                    }
5532
5533                    // use a documentFragment because it works when content is going into a table or UL
5534                    frag = document.createDocumentFragment();
5535                    while (box[0].firstChild) {
5536                        frag.appendChild(box[0].firstChild);
5537                    }
5538
5539                    this._debug('contentSelector', $(opts.contentSelector)[0]);
5540                    $(opts.contentSelector)[0].appendChild(frag);
5541                    // previously, we would pass in the new DOM element as context for the callback
5542                    // however we're now using a documentfragment, which doesn't have parents or children,
5543                    // so the context is the contentContainer guy, and we pass in an array
5544                    // of the elements collected as the first argument.
5545
5546                    data = children.get();
5547                    break;
5548            }
5549
5550            // loadingEnd function
5551            opts.loading.finished.call($(opts.contentSelector)[0],opts);
5552
5553            // smooth scroll to ease in the new content
5554            if (opts.animate) {
5555                var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px';
5556                $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; });
5557            }
5558
5559            if (!opts.animate) {
5560                // once the call is done, we can allow it again.
5561                opts.state.isDuringAjax = false;
5562            }
5563
5564            callback(this, data, url);
5565
5566            if (opts.prefill) {
5567                this._prefill();
5568            }
5569        },
5570
5571        _nearbottom: function infscr_nearbottom() {
5572
5573            var opts = this.options,
5574            pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height();
5575
5576            // if behavior is defined and this function is extended, call that instead of default
5577            if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) {
5578                return this['_nearbottom_'+opts.behavior].call(this);
5579            }
5580
5581            this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom);
5582
5583            // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
5584            return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom);
5585
5586        },
5587
5588        // Pause / temporarily disable plugin from firing
5589        _pausing: function infscr_pausing(pause) {
5590
5591            var opts = this.options;
5592
5593            // if behavior is defined and this function is extended, call that instead of default
5594            if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) {
5595                this['_pausing_'+opts.behavior].call(this,pause);
5596                return;
5597            }
5598
5599            // If pause is not 'pause' or 'resume', toggle it's value
5600            if (pause !== 'pause' && pause !== 'resume' && pause !== null) {
5601                this._debug('Invalid argument. Toggling pause value instead');
5602            }
5603
5604            pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle';
5605
5606            switch (pause) {
5607                case 'pause':
5608                    opts.state.isPaused = true;
5609                break;
5610
5611                case 'resume':
5612                    opts.state.isPaused = false;
5613                break;
5614
5615                case 'toggle':
5616                    opts.state.isPaused = !opts.state.isPaused;
5617                break;
5618            }
5619
5620            this._debug('Paused', opts.state.isPaused);
5621            return false;
5622
5623        },
5624
5625        // Behavior is determined
5626        // If the behavior option is undefined, it will set to default and bind to scroll
5627        _setup: function infscr_setup() {
5628
5629            var opts = this.options;
5630
5631            // if behavior is defined and this function is extended, call that instead of default
5632            if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) {
5633                this['_setup_'+opts.behavior].call(this);
5634                return;
5635            }
5636
5637            this._binding('bind');
5638
5639            return false;
5640
5641        },
5642
5643        // Show done message
5644        _showdonemsg: function infscr_showdonemsg() {
5645
5646            var opts = this.options;
5647
5648            // if behavior is defined and this function is extended, call that instead of default
5649            if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) {
5650                this['_showdonemsg_'+opts.behavior].call(this);
5651                return;
5652            }
5653
5654            opts.loading.msg
5655            .find('img')
5656            .hide()
5657            .parent()
5658            .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () {
5659                $(this).parent().fadeOut(opts.loading.speed);
5660            });
5661
5662            // user provided callback when done
5663            opts.errorCallback.call($(opts.contentSelector)[0],'done');
5664        },
5665
5666        // grab each selector option and see if any fail
5667        _validate: function infscr_validate(opts) {
5668            for (var key in opts) {
5669                if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) {
5670                    this._debug('Your ' + key + ' found no elements.');
5671                    return false;
5672                }
5673            }
5674
5675            return true;
5676        },
5677
5678        /*
5679            ----------------------------
5680            Public methods
5681            ----------------------------
5682            */
5683
5684        // Bind to scroll
5685        bind: function infscr_bind() {
5686            this._binding('bind');
5687        },
5688
5689        // Destroy current instance of plugin
5690        destroy: function infscr_destroy() {
5691            this.options.state.isDestroyed = true;
5692            this.options.loading.finished();
5693            return this._error('destroy');
5694        },
5695
5696        // Set pause value to false
5697        pause: function infscr_pause() {
5698            this._pausing('pause');
5699        },
5700
5701        // Set pause value to false
5702        resume: function infscr_resume() {
5703            this._pausing('resume');
5704        },
5705
5706        beginAjax: function infscr_ajax(opts) {
5707            var instance = this,
5708                path = opts.path,
5709                box, desturl, method, condition;
5710
5711            // increment the URL bit. e.g. /page/3/
5712            opts.state.currPage++;
5713
5714            // Manually control maximum page
5715            if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){
5716                opts.state.isBeyondMaxPage = true;
5717                this.destroy();
5718                return;
5719            }
5720
5721            // if we're dealing with a table we can't use DIVs
5722            box = $(opts.contentSelector).is('table, tbody') ? $('<tbody/>') : $('<div/>');
5723
5724            desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage);
5725            instance._debug('heading into ajax', desturl);
5726
5727            method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback';
5728            if (opts.appendCallback && opts.dataType === 'html') {
5729                method += '+callback';
5730            }
5731
5732            switch (method) {
5733                case 'html+callback':
5734                    instance._debug('Using HTML via .load() method');
5735                    box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) {
5736                        instance._loadcallback(box, responseText, desturl);
5737                    });
5738
5739                    break;
5740
5741                case 'html':
5742                    instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method');
5743                    $.ajax({
5744                        // params
5745                        url: desturl,
5746                        dataType: opts.dataType,
5747                        complete: function infscr_ajax_callback(jqXHR, textStatus) {
5748                            condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified');
5749                            if (condition) {
5750                                instance._loadcallback(box, jqXHR.responseText, desturl);
5751                            } else {
5752                                instance._error('end');
5753                            }
5754                        }
5755                    });
5756
5757                    break;
5758                case 'json':
5759                    instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method');
5760                    $.ajax({
5761                        dataType: 'json',
5762                        type: 'GET',
5763                        url: desturl,
5764                        success: function (data, textStatus, jqXHR) {
5765                            condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified');
5766                            if (opts.appendCallback) {
5767                                // if appendCallback is true, you must defined template in options.
5768                                // note that data passed into _loadcallback is already an html (after processed in opts.template(data)).
5769                                if (opts.template !== undefined) {
5770                                    var theData = opts.template(data);
5771                                    box.append(theData);
5772                                    if (condition) {
5773                                        instance._loadcallback(box, theData);
5774                                    } else {
5775                                        instance._error('end');
5776                                    }
5777                                } else {
5778                                    instance._debug('template must be defined.');
5779                                    instance._error('end');
5780                                }
5781                            } else {
5782                                // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback.
5783                                if (condition) {
5784                                    instance._loadcallback(box, data, desturl);
5785                                } else {
5786                                    instance._error('end');
5787                                }
5788                            }
5789                        },
5790                        error: function() {
5791                            instance._debug('JSON ajax request failed.');
5792                            instance._error('end');
5793                        }
5794                    });
5795
5796                    break;
5797            }
5798        },
5799
5800        // Retrieve next set of content items
5801        retrieve: function infscr_retrieve(pageNum) {
5802            pageNum = pageNum || null;
5803
5804            var instance = this,
5805            opts = instance.options;
5806
5807            // if behavior is defined and this function is extended, call that instead of default
5808            if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) {
5809                this['retrieve_'+opts.behavior].call(this,pageNum);
5810                return;
5811            }
5812
5813            // for manual triggers, if destroyed, get out of here
5814            if (opts.state.isDestroyed) {
5815                this._debug('Instance is destroyed');
5816                return false;
5817            }
5818
5819            // we dont want to fire the ajax multiple times
5820            opts.state.isDuringAjax = true;
5821
5822            opts.loading.start.call($(opts.contentSelector)[0],opts);
5823        },
5824
5825        // Check to see next page is needed
5826        scroll: function infscr_scroll() {
5827
5828            var opts = this.options,
5829            state = opts.state;
5830
5831            // if behavior is defined and this function is extended, call that instead of default
5832            if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) {
5833                this['scroll_'+opts.behavior].call(this);
5834                return;
5835            }
5836
5837            if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) {
5838                return;
5839            }
5840
5841            if (!this._nearbottom()) {
5842                return;
5843            }
5844
5845            this.retrieve();
5846
5847        },
5848
5849        // Toggle pause value
5850        toggle: function infscr_toggle() {
5851            this._pausing();
5852        },
5853
5854        // Unbind from scroll
5855        unbind: function infscr_unbind() {
5856            this._binding('unbind');
5857        },
5858
5859        // update options
5860        update: function infscr_options(key) {
5861            if ($.isPlainObject(key)) {
5862                this.options = $.extend(true,this.options,key);
5863            }
5864        }
5865    };
5866
5867
5868    /*
5869        ----------------------------
5870        Infinite Scroll function
5871        ----------------------------
5872
5873        Borrowed logic from the following...
5874
5875        jQuery UI
5876        - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
5877
5878        jCarousel
5879        - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js
5880
5881        Masonry
5882        - https://github.com/desandro/masonry/blob/master/jquery.masonry.js
5883
5884*/
5885
5886    $.fn.infinitescroll = function infscr_init(options, callback) {
5887
5888
5889        var thisCall = typeof options;
5890
5891        switch (thisCall) {
5892
5893            // method
5894            case 'string':
5895                var args = Array.prototype.slice.call(arguments, 1);
5896
5897                this.each(function () {
5898                    var instance = $.data(this, 'infinitescroll');
5899
5900                    if (!instance) {
5901                        // not setup yet
5902                        // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup');
5903                        return false;
5904                    }
5905
5906                    if (!$.isFunction(instance[options]) || options.charAt(0) === '_') {
5907                        // return $.error('No such method ' + options + ' for Infinite Scroll');
5908                        return false;
5909                    }
5910
5911                    // no errors!
5912                    instance[options].apply(instance, args);
5913                });
5914
5915            break;
5916
5917            // creation
5918            case 'object':
5919
5920                this.each(function () {
5921
5922                var instance = $.data(this, 'infinitescroll');
5923
5924                if (instance) {
5925
5926                    // update options of current instance
5927                    instance.update(options);
5928
5929                } else {
5930
5931                    // initialize new instance
5932                    instance = new $.infinitescroll(options, callback, this);
5933
5934                    // don't attach if instantiation failed
5935                    if (!instance.failed) {
5936                        $.data(this, 'infinitescroll', instance);
5937                    }
5938
5939                }
5940
5941            });
5942
5943            break;
5944
5945        }
5946
5947        return this;
5948    };
5949
5950
5951
5952    /*
5953     * smartscroll: debounced scroll event for jQuery *
5954     * https://github.com/lukeshumard/smartscroll
5955     * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js *
5956     * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. *
5957     */
5958
5959    var event = $.event,
5960    scrollTimeout;
5961
5962    event.special.smartscroll = {
5963        setup: function () {
5964            $(this).bind('scroll', event.special.smartscroll.handler);
5965        },
5966        teardown: function () {
5967            $(this).unbind('scroll', event.special.smartscroll.handler);
5968        },
5969        handler: function (event, execAsap) {
5970            // Save the context
5971            var context = this,
5972            args = arguments;
5973
5974            // set correct event type
5975            event.type = 'smartscroll';
5976
5977            if (scrollTimeout) { clearTimeout(scrollTimeout); }
5978            scrollTimeout = setTimeout(function () {
5979                $(context).trigger('smartscroll', args);
5980            }, execAsap === 'execAsap' ? 0 : 100);
5981        }
5982    };
5983
5984    $.fn.smartscroll = function (fn) {
5985        return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']);
5986    };
5987
5988}));
5989
5990/*!
5991Waypoints - 4.0.1
5992Copyright © 2011-2016 Caleb Troughton
5993Licensed under the MIT license.
5994https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
5995*/
5996(function() {
5997  'use strict'
5998
5999  var keyCounter = 0
6000  var allWaypoints = {}
6001
6002  /* http://imakewebthings.com/waypoints/api/waypoint */
6003  function Waypoint(options) {
6004    if (!options) {
6005      throw new Error('No options passed to Waypoint constructor')
6006    }
6007    if (!options.element) {
6008      throw new Error('No element option passed to Waypoint constructor')
6009    }
6010    if (!options.handler) {
6011      throw new Error('No handler option passed to Waypoint constructor')
6012    }
6013
6014    this.key = 'waypoint-' + keyCounter
6015    this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
6016    this.element = this.options.element
6017    this.adapter = new Waypoint.Adapter(this.element)
6018    this.callback = options.handler
6019    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
6020    this.enabled = this.options.enabled
6021    this.triggerPoint = null
6022    this.group = Waypoint.Group.findOrCreate({
6023      name: this.options.group,
6024      axis: this.axis
6025    })
6026    this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
6027
6028    if (Waypoint.offsetAliases[this.options.offset]) {
6029      this.options.offset = Waypoint.offsetAliases[this.options.offset]
6030    }
6031    this.group.add(this)
6032    this.context.add(this)
6033    allWaypoints[this.key] = this
6034    keyCounter += 1
6035  }
6036
6037  /* Private */
6038  Waypoint.prototype.queueTrigger = function(direction) {
6039    this.group.queueTrigger(this, direction)
6040  }
6041
6042  /* Private */
6043  Waypoint.prototype.trigger = function(args) {
6044    if (!this.enabled) {
6045      return
6046    }
6047    if (this.callback) {
6048      this.callback.apply(this, args)
6049    }
6050  }
6051
6052  /* Public */
6053  /* http://imakewebthings.com/waypoints/api/destroy */
6054  Waypoint.prototype.destroy = function() {
6055    this.context.remove(this)
6056    this.group.remove(this)
6057    delete allWaypoints[this.key]
6058  }
6059
6060  /* Public */
6061  /* http://imakewebthings.com/waypoints/api/disable */
6062  Waypoint.prototype.disable = function() {
6063    this.enabled = false
6064    return this
6065  }
6066
6067  /* Public */
6068  /* http://imakewebthings.com/waypoints/api/enable */
6069  Waypoint.prototype.enable = function() {
6070    this.context.refresh()
6071    this.enabled = true
6072    return this
6073  }
6074
6075  /* Public */
6076  /* http://imakewebthings.com/waypoints/api/next */
6077  Waypoint.prototype.next = function() {
6078    return this.group.next(this)
6079  }
6080
6081  /* Public */
6082  /* http://imakewebthings.com/waypoints/api/previous */
6083  Waypoint.prototype.previous = function() {
6084    return this.group.previous(this)
6085  }
6086
6087  /* Private */
6088  Waypoint.invokeAll = function(method) {
6089    var allWaypointsArray = []
6090    for (var waypointKey in allWaypoints) {
6091      allWaypointsArray.push(allWaypoints[waypointKey])
6092    }
6093    for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
6094      allWaypointsArray[i][method]()
6095    }
6096  }
6097
6098  /* Public */
6099  /* http://imakewebthings.com/waypoints/api/destroy-all */
6100  Waypoint.destroyAll = function() {
6101    Waypoint.invokeAll('destroy')
6102  }
6103
6104  /* Public */
6105  /* http://imakewebthings.com/waypoints/api/disable-all */
6106  Waypoint.disableAll = function() {
6107    Waypoint.invokeAll('disable')
6108  }
6109
6110  /* Public */
6111  /* http://imakewebthings.com/waypoints/api/enable-all */
6112  Waypoint.enableAll = function() {
6113    Waypoint.Context.refreshAll()
6114    for (var waypointKey in allWaypoints) {
6115      allWaypoints[waypointKey].enabled = true
6116    }
6117    return this
6118  }
6119
6120  /* Public */
6121  /* http://imakewebthings.com/waypoints/api/refresh-all */
6122  Waypoint.refreshAll = function() {
6123    Waypoint.Context.refreshAll()
6124  }
6125
6126  /* Public */
6127  /* http://imakewebthings.com/waypoints/api/viewport-height */
6128  Waypoint.viewportHeight = function() {
6129    return window.innerHeight || document.documentElement.clientHeight
6130  }
6131
6132  /* Public */
6133  /* http://imakewebthings.com/waypoints/api/viewport-width */
6134  Waypoint.viewportWidth = function() {
6135    return document.documentElement.clientWidth
6136  }
6137
6138  Waypoint.adapters = []
6139
6140  Waypoint.defaults = {
6141    context: window,
6142    continuous: true,
6143    enabled: true,
6144    group: 'default',
6145    horizontal: false,
6146    offset: 0
6147  }
6148
6149  Waypoint.offsetAliases = {
6150    'bottom-in-view': function() {
6151      return this.context.innerHeight() - this.adapter.outerHeight()
6152    },
6153    'right-in-view': function() {
6154      return this.context.innerWidth() - this.adapter.outerWidth()
6155    }
6156  }
6157
6158  window.Waypoint = Waypoint
6159}())
6160;(function() {
6161  'use strict'
6162
6163  function requestAnimationFrameShim(callback) {
6164    window.setTimeout(callback, 1000 / 60)
6165  }
6166
6167  var keyCounter = 0
6168  var contexts = {}
6169  var Waypoint = window.Waypoint
6170  var oldWindowLoad = window.onload
6171
6172  /* http://imakewebthings.com/waypoints/api/context */
6173  function Context(element) {
6174    this.element = element
6175    this.Adapter = Waypoint.Adapter
6176    this.adapter = new this.Adapter(element)
6177    this.key = 'waypoint-context-' + keyCounter
6178    this.didScroll = false
6179    this.didResize = false
6180    this.oldScroll = {
6181      x: this.adapter.scrollLeft(),
6182      y: this.adapter.scrollTop()
6183    }
6184    this.waypoints = {
6185      vertical: {},
6186      horizontal: {}
6187    }
6188
6189    element.waypointContextKey = this.key
6190    contexts[element.waypointContextKey] = this
6191    keyCounter += 1
6192    if (!Waypoint.windowContext) {
6193      Waypoint.windowContext = true
6194      Waypoint.windowContext = new Context(window)
6195    }
6196
6197    this.createThrottledScrollHandler()
6198    this.createThrottledResizeHandler()
6199  }
6200
6201  /* Private */
6202  Context.prototype.add = function(waypoint) {
6203    var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
6204    this.waypoints[axis][waypoint.key] = waypoint
6205    this.refresh()
6206  }
6207
6208  /* Private */
6209  Context.prototype.checkEmpty = function() {
6210    var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
6211    var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
6212    var isWindow = this.element == this.element.window
6213    if (horizontalEmpty && verticalEmpty && !isWindow) {
6214      this.adapter.off('.waypoints')
6215      delete contexts[this.key]
6216    }
6217  }
6218
6219  /* Private */
6220  Context.prototype.createThrottledResizeHandler = function() {
6221    var self = this
6222
6223    function resizeHandler() {
6224      self.handleResize()
6225      self.didResize = false
6226    }
6227
6228    this.adapter.on('resize.waypoints', function() {
6229      if (!self.didResize) {
6230        self.didResize = true
6231        Waypoint.requestAnimationFrame(resizeHandler)
6232      }
6233    })
6234  }
6235
6236  /* Private */
6237  Context.prototype.createThrottledScrollHandler = function() {
6238    var self = this
6239    function scrollHandler() {
6240      self.handleScroll()
6241      self.didScroll = false
6242    }
6243
6244    this.adapter.on('scroll.waypoints', function() {
6245      if (!self.didScroll || Waypoint.isTouch) {
6246        self.didScroll = true
6247        Waypoint.requestAnimationFrame(scrollHandler)
6248      }
6249    })
6250  }
6251
6252  /* Private */
6253  Context.prototype.handleResize = function() {
6254    Waypoint.Context.refreshAll()
6255  }
6256
6257  /* Private */
6258  Context.prototype.handleScroll = function() {
6259    var triggeredGroups = {}
6260    var axes = {
6261      horizontal: {
6262        newScroll: this.adapter.scrollLeft(),
6263        oldScroll: this.oldScroll.x,
6264        forward: 'right',
6265        backward: 'left'
6266      },
6267      vertical: {
6268        newScroll: this.adapter.scrollTop(),
6269        oldScroll: this.oldScroll.y,
6270        forward: 'down',
6271        backward: 'up'
6272      }
6273    }
6274
6275    for (var axisKey in axes) {
6276      var axis = axes[axisKey]
6277      var isForward = axis.newScroll > axis.oldScroll
6278      var direction = isForward ? axis.forward : axis.backward
6279
6280      for (var waypointKey in this.waypoints[axisKey]) {
6281        var waypoint = this.waypoints[axisKey][waypointKey]
6282        if (waypoint.triggerPoint === null) {
6283          continue
6284        }
6285        var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
6286        var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
6287        var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
6288        var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
6289        if (crossedForward || crossedBackward) {
6290          waypoint.queueTrigger(direction)
6291          triggeredGroups[waypoint.group.id] = waypoint.group
6292        }
6293      }
6294    }
6295
6296    for (var groupKey in triggeredGroups) {
6297      triggeredGroups[groupKey].flushTriggers()
6298    }
6299
6300    this.oldScroll = {
6301      x: axes.horizontal.newScroll,
6302      y: axes.vertical.newScroll
6303    }
6304  }
6305
6306  /* Private */
6307  Context.prototype.innerHeight = function() {
6308    /*eslint-disable eqeqeq */
6309    if (this.element == this.element.window) {
6310      return Waypoint.viewportHeight()
6311    }
6312    /*eslint-enable eqeqeq */
6313    return this.adapter.innerHeight()
6314  }
6315
6316  /* Private */
6317  Context.prototype.remove = function(waypoint) {
6318    delete this.waypoints[waypoint.axis][waypoint.key]
6319    this.checkEmpty()
6320  }
6321
6322  /* Private */
6323  Context.prototype.innerWidth = function() {
6324    /*eslint-disable eqeqeq */
6325    if (this.element == this.element.window) {
6326      return Waypoint.viewportWidth()
6327    }
6328    /*eslint-enable eqeqeq */
6329    return this.adapter.innerWidth()
6330  }
6331
6332  /* Public */
6333  /* http://imakewebthings.com/waypoints/api/context-destroy */
6334  Context.prototype.destroy = function() {
6335    var allWaypoints = []
6336    for (var axis in this.waypoints) {
6337      for (var waypointKey in this.waypoints[axis]) {
6338        allWaypoints.push(this.waypoints[axis][waypointKey])
6339      }
6340    }
6341    for (var i = 0, end = allWaypoints.length; i < end; i++) {
6342      allWaypoints[i].destroy()
6343    }
6344  }
6345
6346  /* Public */
6347  /* http://imakewebthings.com/waypoints/api/context-refresh */
6348  Context.prototype.refresh = function() {
6349    /*eslint-disable eqeqeq */
6350    var isWindow = this.element == this.element.window
6351    /*eslint-enable eqeqeq */
6352    var contextOffset = isWindow ? undefined : this.adapter.offset()
6353    var triggeredGroups = {}
6354    var axes
6355
6356    this.handleScroll()
6357    axes = {
6358      horizontal: {
6359        contextOffset: isWindow ? 0 : contextOffset.left,
6360        contextScroll: isWindow ? 0 : this.oldScroll.x,
6361        contextDimension: this.innerWidth(),
6362        oldScroll: this.oldScroll.x,
6363        forward: 'right',
6364        backward: 'left',
6365        offsetProp: 'left'
6366      },
6367      vertical: {
6368        contextOffset: isWindow ? 0 : contextOffset.top,
6369        contextScroll: isWindow ? 0 : this.oldScroll.y,
6370        contextDimension: this.innerHeight(),
6371        oldScroll: this.oldScroll.y,
6372        forward: 'down',
6373        backward: 'up',
6374        offsetProp: 'top'
6375      }
6376    }
6377
6378    for (var axisKey in axes) {
6379      var axis = axes[axisKey]
6380      for (var waypointKey in this.waypoints[axisKey]) {
6381        var waypoint = this.waypoints[axisKey][waypointKey]
6382        var adjustment = waypoint.options.offset
6383        var oldTriggerPoint = waypoint.triggerPoint
6384        var elementOffset = 0
6385        var freshWaypoint = oldTriggerPoint == null
6386        var contextModifier, wasBeforeScroll, nowAfterScroll
6387        var triggeredBackward, triggeredForward
6388
6389        if (waypoint.element !== waypoint.element.window) {
6390          elementOffset = waypoint.adapter.offset()[axis.offsetProp]
6391        }
6392
6393        if (typeof adjustment === 'function') {
6394          adjustment = adjustment.apply(waypoint)
6395        }
6396        else if (typeof adjustment === 'string') {
6397          adjustment = parseFloat(adjustment)
6398          if (waypoint.options.offset.indexOf('%') > - 1) {
6399            adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
6400          }
6401        }
6402
6403        contextModifier = axis.contextScroll - axis.contextOffset
6404        waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
6405        wasBeforeScroll = oldTriggerPoint < axis.oldScroll
6406        nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
6407        triggeredBackward = wasBeforeScroll && nowAfterScroll
6408        triggeredForward = !wasBeforeScroll && !nowAfterScroll
6409
6410        if (!freshWaypoint && triggeredBackward) {
6411          waypoint.queueTrigger(axis.backward)
6412          triggeredGroups[waypoint.group.id] = waypoint.group
6413        }
6414        else if (!freshWaypoint && triggeredForward) {
6415          waypoint.queueTrigger(axis.forward)
6416          triggeredGroups[waypoint.group.id] = waypoint.group
6417        }
6418        else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
6419          waypoint.queueTrigger(axis.forward)
6420          triggeredGroups[waypoint.group.id] = waypoint.group
6421        }
6422      }
6423    }
6424
6425    Waypoint.requestAnimationFrame(function() {
6426      for (var groupKey in triggeredGroups) {
6427        triggeredGroups[groupKey].flushTriggers()
6428      }
6429    })
6430
6431    return this
6432  }
6433
6434  /* Private */
6435  Context.findOrCreateByElement = function(element) {
6436    return Context.findByElement(element) || new Context(element)
6437  }
6438
6439  /* Private */
6440  Context.refreshAll = function() {
6441    for (var contextId in contexts) {
6442      contexts[contextId].refresh()
6443    }
6444  }
6445
6446  /* Public */
6447  /* http://imakewebthings.com/waypoints/api/context-find-by-element */
6448  Context.findByElement = function(element) {
6449    return contexts[element.waypointContextKey]
6450  }
6451
6452  window.onload = function() {
6453    if (oldWindowLoad) {
6454      oldWindowLoad()
6455    }
6456    Context.refreshAll()
6457  }
6458
6459
6460  Waypoint.requestAnimationFrame = function(callback) {
6461    var requestFn = window.requestAnimationFrame ||
6462      window.mozRequestAnimationFrame ||
6463      window.webkitRequestAnimationFrame ||
6464      requestAnimationFrameShim
6465    requestFn.call(window, callback)
6466  }
6467  Waypoint.Context = Context
6468}())
6469;(function() {
6470  'use strict'
6471
6472  function byTriggerPoint(a, b) {
6473    return a.triggerPoint - b.triggerPoint
6474  }
6475
6476  function byReverseTriggerPoint(a, b) {
6477    return b.triggerPoint - a.triggerPoint
6478  }
6479
6480  var groups = {
6481    vertical: {},
6482    horizontal: {}
6483  }
6484  var Waypoint = window.Waypoint
6485
6486  /* http://imakewebthings.com/waypoints/api/group */
6487  function Group(options) {
6488    this.name = options.name
6489    this.axis = options.axis
6490    this.id = this.name + '-' + this.axis
6491    this.waypoints = []
6492    this.clearTriggerQueues()
6493    groups[this.axis][this.name] = this
6494  }
6495
6496  /* Private */
6497  Group.prototype.add = function(waypoint) {
6498    this.waypoints.push(waypoint)
6499  }
6500
6501  /* Private */
6502  Group.prototype.clearTriggerQueues = function() {
6503    this.triggerQueues = {
6504      up: [],
6505      down: [],
6506      left: [],
6507      right: []
6508    }
6509  }
6510
6511  /* Private */
6512  Group.prototype.flushTriggers = function() {
6513    for (var direction in this.triggerQueues) {
6514      var waypoints = this.triggerQueues[direction]
6515      var reverse = direction === 'up' || direction === 'left'
6516      waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
6517      for (var i = 0, end = waypoints.length; i < end; i += 1) {
6518        var waypoint = waypoints[i]
6519        if (waypoint.options.continuous || i === waypoints.length - 1) {
6520          waypoint.trigger([direction])
6521        }
6522      }
6523    }
6524    this.clearTriggerQueues()
6525  }
6526
6527  /* Private */
6528  Group.prototype.next = function(waypoint) {
6529    this.waypoints.sort(byTriggerPoint)
6530    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
6531    var isLast = index === this.waypoints.length - 1
6532    return isLast ? null : this.waypoints[index + 1]
6533  }
6534
6535  /* Private */
6536  Group.prototype.previous = function(waypoint) {
6537    this.waypoints.sort(byTriggerPoint)
6538    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
6539    return index ? this.waypoints[index - 1] : null
6540  }
6541
6542  /* Private */
6543  Group.prototype.queueTrigger = function(waypoint, direction) {
6544    this.triggerQueues[direction].push(waypoint)
6545  }
6546
6547  /* Private */
6548  Group.prototype.remove = function(waypoint) {
6549    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
6550    if (index > -1) {
6551      this.waypoints.splice(index, 1)
6552    }
6553  }
6554
6555  /* Public */
6556  /* http://imakewebthings.com/waypoints/api/first */
6557  Group.prototype.first = function() {
6558    return this.waypoints[0]
6559  }
6560
6561  /* Public */
6562  /* http://imakewebthings.com/waypoints/api/last */
6563  Group.prototype.last = function() {
6564    return this.waypoints[this.waypoints.length - 1]
6565  }
6566
6567  /* Private */
6568  Group.findOrCreate = function(options) {
6569    return groups[options.axis][options.name] || new Group(options)
6570  }
6571
6572  Waypoint.Group = Group
6573}())
6574;(function() {
6575  'use strict'
6576
6577  var $ = window.jQuery
6578  var Waypoint = window.Waypoint
6579
6580  function JQueryAdapter(element) {
6581    this.$element = $(element)
6582  }
6583
6584  $.each([
6585    'innerHeight',
6586    'innerWidth',
6587    'off',
6588    'offset',
6589    'on',
6590    'outerHeight',
6591    'outerWidth',
6592    'scrollLeft',
6593    'scrollTop'
6594  ], function(i, method) {
6595    JQueryAdapter.prototype[method] = function() {
6596      var args = Array.prototype.slice.call(arguments)
6597      return this.$element[method].apply(this.$element, args)
6598    }
6599  })
6600
6601  $.each([
6602    'extend',
6603    'inArray',
6604    'isEmptyObject'
6605  ], function(i, method) {
6606    JQueryAdapter[method] = $[method]
6607  })
6608
6609  Waypoint.adapters.push({
6610    name: 'jquery',
6611    Adapter: JQueryAdapter
6612  })
6613  Waypoint.Adapter = JQueryAdapter
6614}())
6615;(function() {
6616  'use strict'
6617
6618  var Waypoint = window.Waypoint
6619
6620  function createExtension(framework) {
6621    return function() {
6622      var waypoints = []
6623      var overrides = arguments[0]
6624
6625      if (framework.isFunction(arguments[0])) {
6626        overrides = framework.extend({}, arguments[1])
6627        overrides.handler = arguments[0]
6628      }
6629
6630      this.each(function() {
6631        var options = framework.extend({}, overrides, {
6632          element: this
6633        })
6634        if (typeof options.context === 'string') {
6635          options.context = framework(this).closest(options.context)[0]
6636        }
6637        waypoints.push(new Waypoint(options))
6638      })
6639
6640      return waypoints
6641    }
6642  }
6643
6644  if (window.jQuery) {
6645    window.jQuery.fn.waypoint = createExtension(window.jQuery)
6646  }
6647  if (window.Zepto) {
6648    window.Zepto.fn.waypoint = createExtension(window.Zepto)
6649  }
6650}())
6651;
6652/*!
6653Waypoints Inview Shortcut - 4.0.1
6654Copyright © 2011-2016 Caleb Troughton
6655Licensed under the MIT license.
6656https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6657*/
6658(function() {
6659  'use strict'
6660
6661  function noop() {}
6662
6663  var Waypoint = window.Waypoint
6664
6665  /* http://imakewebthings.com/waypoints/shortcuts/inview */
6666  function Inview(options) {
6667    this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
6668    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
6669    this.waypoints = []
6670    this.element = this.options.element
6671    this.createWaypoints()
6672  }
6673
6674  /* Private */
6675  Inview.prototype.createWaypoints = function() {
6676    var configs = {
6677      vertical: [{
6678        down: 'enter',
6679        up: 'exited',
6680        offset: '100%'
6681      }, {
6682        down: 'entered',
6683        up: 'exit',
6684        offset: 'bottom-in-view'
6685      }, {
6686        down: 'exit',
6687        up: 'entered',
6688        offset: 0
6689      }, {
6690        down: 'exited',
6691        up: 'enter',
6692        offset: function() {
6693          return -this.adapter.outerHeight()
6694        }
6695      }],
6696      horizontal: [{
6697        right: 'enter',
6698        left: 'exited',
6699        offset: '100%'
6700      }, {
6701        right: 'entered',
6702        left: 'exit',
6703        offset: 'right-in-view'
6704      }, {
6705        right: 'exit',
6706        left: 'entered',
6707        offset: 0
6708      }, {
6709        right: 'exited',
6710        left: 'enter',
6711        offset: function() {
6712          return -this.adapter.outerWidth()
6713        }
6714      }]
6715    }
6716
6717    for (var i = 0, end = configs[this.axis].length; i < end; i++) {
6718      var config = configs[this.axis][i]
6719      this.createWaypoint(config)
6720    }
6721  }
6722
6723  /* Private */
6724  Inview.prototype.createWaypoint = function(config) {
6725    var self = this
6726    this.waypoints.push(new Waypoint({
6727      context: this.options.context,
6728      element: this.options.element,
6729      enabled: this.options.enabled,
6730      handler: (function(config) {
6731        return function(direction) {
6732          self.options[config[direction]].call(self, direction)
6733        }
6734      }(config)),
6735      offset: config.offset,
6736      horizontal: this.options.horizontal
6737    }))
6738  }
6739
6740  /* Public */
6741  Inview.prototype.destroy = function() {
6742    for (var i = 0, end = this.waypoints.length; i < end; i++) {
6743      this.waypoints[i].destroy()
6744    }
6745    this.waypoints = []
6746  }
6747
6748  Inview.prototype.disable = function() {
6749    for (var i = 0, end = this.waypoints.length; i < end; i++) {
6750      this.waypoints[i].disable()
6751    }
6752  }
6753
6754  Inview.prototype.enable = function() {
6755    for (var i = 0, end = this.waypoints.length; i < end; i++) {
6756      this.waypoints[i].enable()
6757    }
6758  }
6759
6760  Inview.defaults = {
6761    context: window,
6762    enabled: true,
6763    enter: noop,
6764    entered: noop,
6765    exit: noop,
6766    exited: noop
6767  }
6768
6769  Waypoint.Inview = Inview
6770}())
6771;
6772
6773/*
6774 * SmartMenus jQuery v0.9.6
6775 * http://www.smartmenus.org/
6776 *
6777 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd.
6778 * http://vadikom.com/
6779 *
6780 * Released under the MIT license:
6781 * http://www.opensource.org/licenses/MIT
6782 */
6783
6784(function($) {
6785
6786	var menuTrees = [],
6787		IE = !!window.createPopup, // we need to detect it, unfortunately
6788		IElt9 = IE && !document.defaultView,
6789		IElt8 = IE && !document.querySelector,
6790		IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined',
6791		mouse = false, // optimize for touch by default - we will detect for mouse input
6792		mouseDetectionEnabled = false;
6793
6794	// Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.)
6795	function initMouseDetection(disable) {
6796		if (!mouseDetectionEnabled && !disable) {
6797			// if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present
6798			// in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events)
6799			var firstTime = true,
6800				lastMove = null;
6801			$(document).bind({
6802				'mousemove.smartmenus_mouse': function(e) {
6803					var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() };
6804					if (lastMove) {
6805						var deltaX = Math.abs(lastMove.x - thisMove.x),
6806							deltaY = Math.abs(lastMove.y - thisMove.y);
6807	 					if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
6808							mouse = true;
6809							// if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes
6810							if (firstTime) {
6811								var $a = $(e.target).closest('a');
6812								if ($a.is('a')) {
6813									$.each(menuTrees, function() {
6814										if ($.contains(this.$root[0], $a[0])) {
6815											this.itemEnter({ currentTarget: $a[0] });
6816											return false;
6817										}
6818									});
6819								}
6820								firstTime = false;
6821							}
6822						}
6823					}
6824					lastMove = thisMove;
6825				},
6826				'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) {
6827					if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) {
6828						mouse = false;
6829					}
6830				}
6831			});
6832			mouseDetectionEnabled = true;
6833		} else if (mouseDetectionEnabled && disable) {
6834			$(document).unbind('.smartmenus_mouse');
6835			mouseDetectionEnabled = false;
6836		}
6837	};
6838
6839	$.SmartMenus = function(elm, options) {
6840		this.$root = $(elm);
6841		this.opts = options;
6842		this.rootId = ''; // internal
6843		this.$subArrow = null;
6844		this.subMenus = []; // all sub menus in the tree (UL elms) in no particular order (only real - e.g. UL's in mega sub menus won't be counted)
6845		this.activatedItems = []; // stores last activated A's for each level
6846		this.visibleSubMenus = []; // stores visible sub menus UL's
6847		this.showTimeout = 0;
6848		this.hideTimeout = 0;
6849		this.scrollTimeout = 0;
6850		this.clickActivated = false;
6851		this.zIndexInc = 0;
6852		this.$firstLink = null; // we'll use these for some tests
6853		this.$firstSub = null; // at runtime so we'll cache them
6854		this.disabled = false;
6855		this.$disableOverlay = null;
6856		this.init();
6857	};
6858
6859	$.extend($.SmartMenus, {
6860		hideAll: function() {
6861			$.each(menuTrees, function() {
6862				this.menuHideAll();
6863			});
6864		},
6865		destroy: function() {
6866			while (menuTrees.length) {
6867				menuTrees[0].destroy();
6868			}
6869			initMouseDetection(true);
6870		},
6871		prototype: {
6872			init: function(refresh) {
6873				var self = this;
6874
6875				if (!refresh) {
6876					menuTrees.push(this);
6877
6878					this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, '');
6879
6880					if (this.$root.hasClass('sm-rtl')) {
6881						this.opts.rightToLeftSubMenus = true;
6882					}
6883
6884					// init root (main menu)
6885					this.$root
6886						.data('smartmenus', this)
6887						.attr('data-smartmenus-id', this.rootId)
6888						.dataSM('level', 1)
6889						.bind({
6890							'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
6891							'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this)
6892						})
6893						.delegate('a', {
6894							'mouseenter.smartmenus': $.proxy(this.itemEnter, this),
6895							'mouseleave.smartmenus': $.proxy(this.itemLeave, this),
6896							'mousedown.smartmenus': $.proxy(this.itemDown, this),
6897							'focus.smartmenus': $.proxy(this.itemFocus, this),
6898							'blur.smartmenus': $.proxy(this.itemBlur, this),
6899							'click.smartmenus': $.proxy(this.itemClick, this),
6900							'touchend.smartmenus': $.proxy(this.itemTouchEnd, this)
6901						});
6902
6903					var eNamespace = '.smartmenus' + this.rootId;
6904					// hide menus on tap or click outside the root UL
6905					if (this.opts.hideOnClick) {
6906						$(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this))
6907							.bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this))
6908							.bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this))
6909							// for Opera Mobile < 11.5, webOS browser, etc. we'll check click too
6910							.bind('click' + eNamespace, $.proxy(this.docClick, this));
6911					}
6912					// hide sub menus on resize
6913					$(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
6914					$(window).bind('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
6915
6916					if (this.opts.subIndicators) {
6917						this.$subArrow = $('<span/>').addClass('sub-arrow');
6918						if (this.opts.subIndicatorsText) {
6919							this.$subArrow.html(this.opts.subIndicatorsText);
6920						}
6921					}
6922
6923					// make sure mouse detection is enabled
6924					initMouseDetection();
6925				}
6926
6927				// init sub menus
6928				this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0);
6929
6930				this.$firstLink = this.$root.find('a').eq(0);
6931
6932				// find current item
6933				if (this.opts.markCurrentItem) {
6934					var reDefaultDoc = /(index|default)\.[^#\?\/]*/i,
6935						reHash = /#.*/,
6936						locHref = window.location.href.replace(reDefaultDoc, ''),
6937						locHrefNoHash = locHref.replace(reHash, '');
6938					this.$root.find('a').each(function() {
6939						var href = this.href.replace(reDefaultDoc, ''),
6940							$this = $(this);
6941						if (href == locHref || href == locHrefNoHash) {
6942							$this.addClass('current');
6943							if (self.opts.markCurrentTree) {
6944								$this.parents('li').each(function() {
6945									var $this = $(this);
6946									if ($this.dataSM('sub')) {
6947										$this.children('a').addClass('current');
6948									}
6949								});
6950							}
6951						}
6952					});
6953				}
6954			},
6955			destroy: function() {
6956				this.menuHideAll();
6957				this.$root
6958					.removeData('smartmenus')
6959					.removeAttr('data-smartmenus-id')
6960					.removeDataSM('level')
6961					.unbind('.smartmenus')
6962					.undelegate('.smartmenus');
6963				var eNamespace = '.smartmenus' + this.rootId;
6964				$(document).unbind(eNamespace);
6965				$(window).unbind(eNamespace);
6966				if (this.opts.subIndicators) {
6967					this.$subArrow = null;
6968				}
6969				var self = this;
6970				$.each(this.subMenus, function() {
6971					if (this.hasClass('mega-menu')) {
6972						this.find('ul').removeDataSM('in-mega');
6973					}
6974					if (this.dataSM('shown-before')) {
6975						if (IElt8) {
6976							this.children().css({ styleFloat: '', width: '' });
6977						}
6978						if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) {
6979							if (!IE6) {
6980								this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap');
6981							} else {
6982								this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', '');
6983							}
6984						}
6985						if (this.dataSM('scroll-arrows')) {
6986							this.dataSM('scroll-arrows').remove();
6987						}
6988						this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' });
6989					}
6990					if (self.opts.subIndicators) {
6991						this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove();
6992					}
6993					this.removeDataSM('shown-before')
6994						.removeDataSM('ie-shim')
6995						.removeDataSM('scroll-arrows')
6996						.removeDataSM('parent-a')
6997						.removeDataSM('level')
6998						.removeDataSM('beforefirstshowfired')
6999						.parent().removeDataSM('sub');
7000				});
7001				if (this.opts.markCurrentItem) {
7002					this.$root.find('a.current').removeClass('current');
7003				}
7004				this.$root = null;
7005				this.$firstLink = null;
7006				this.$firstSub = null;
7007				if (this.$disableOverlay) {
7008					this.$disableOverlay.remove();
7009					this.$disableOverlay = null;
7010				}
7011				menuTrees.splice($.inArray(this, menuTrees), 1);
7012			},
7013			disable: function(noOverlay) {
7014				if (!this.disabled) {
7015					this.menuHideAll();
7016					// display overlay over the menu to prevent interaction
7017					if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) {
7018						var pos = this.$root.offset();
7019						this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({
7020							position: 'absolute',
7021							top: pos.top,
7022							left: pos.left,
7023							width: this.$root.outerWidth(),
7024							height: this.$root.outerHeight(),
7025							zIndex: this.getStartZIndex() + 1,
7026							opacity: 0
7027						}).appendTo(document.body);
7028					}
7029					this.disabled = true;
7030				}
7031			},
7032			docClick: function(e) {
7033				// hide on any click outside the menu or on a menu link
7034				if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) {
7035					this.menuHideAll($(e.target));
7036				}
7037			},
7038			docTouchEnd: function(e) {
7039				if (!this.lastTouch) {
7040					return;
7041				}
7042				if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) {
7043					if (this.hideTimeout) {
7044						clearTimeout(this.hideTimeout);
7045						this.hideTimeout = 0;
7046					}
7047					// hide with a delay to prevent triggering accidental unwanted click on some page element
7048					var self = this;
7049					this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350);
7050				}
7051				this.lastTouch = null;
7052			},
7053			docTouchMove: function(e) {
7054				if (!this.lastTouch) {
7055					return;
7056				}
7057				var touchPoint = e.originalEvent.touches[0];
7058				this.lastTouch.x2 = touchPoint.pageX;
7059				this.lastTouch.y2 = touchPoint.pageY;
7060			},
7061			docTouchStart: function(e) {
7062				var touchPoint = e.originalEvent.touches[0];
7063				this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target };
7064			},
7065			enable: function() {
7066				if (this.disabled) {
7067					if (this.$disableOverlay) {
7068						this.$disableOverlay.remove();
7069						this.$disableOverlay = null;
7070					}
7071					this.disabled = false;
7072				}
7073			},
7074			getHeight: function($elm) {
7075				return this.getOffset($elm, true);
7076			},
7077			// returns precise width/height float values in IE9+, FF4+, recent WebKit
7078			// http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
7079			getOffset: function($elm, height) {
7080				var old;
7081				if ($elm.css('display') == 'none') {
7082					old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility };
7083					$elm.css({ position: 'absolute', visibility: 'hidden' }).show();
7084				}
7085				var defaultView = $elm[0].ownerDocument.defaultView,
7086					compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null),
7087					val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']);
7088				if (val) {
7089					val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft'])
7090	 					+ parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight'])
7091	 					+ parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth'])
7092	 					+ parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']);
7093				} else {
7094					val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth;
7095				}
7096				if (old) {
7097					$elm.hide().css(old);
7098				}
7099				return val;
7100			},
7101			getWidth: function($elm) {
7102				return this.getOffset($elm);
7103			},
7104			getStartZIndex: function() {
7105				var zIndex = parseInt(this.$root.css('z-index'));
7106				return !isNaN(zIndex) ? zIndex : 1;
7107			},
7108			handleEvents: function() {
7109				return !this.disabled && this.isCSSOn();
7110			},
7111			handleItemEvents: function($a) {
7112				return this.handleEvents() && !this.isLinkInMegaMenu($a);
7113			},
7114			isCollapsible: function() {
7115				return this.$firstSub.css('position') == 'static';
7116			},
7117			isCSSOn: function() {
7118				return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'inline';
7119			},
7120			isFixed: function() {
7121				return this.$root.css('position') == 'fixed';
7122			},
7123			isLinkInMegaMenu: function($a) {
7124				return !$a.parent().parent().dataSM('level');
7125			},
7126			isTouchMode: function() {
7127				return !mouse || this.isCollapsible();
7128			},
7129			itemActivate: function($a) {
7130				var $li = $a.parent(),
7131					$ul = $li.parent(),
7132					level = $ul.dataSM('level');
7133				// if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first
7134				if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) {
7135					var self = this;
7136					$($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() {
7137						self.itemActivate($(this).dataSM('parent-a'));
7138					});
7139				}
7140				// hide any visible deeper level sub menus
7141				if (this.visibleSubMenus.length > level) {
7142					for (var i = this.visibleSubMenus.length - 1, l = !this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level; i > l; i--) {
7143						this.menuHide(this.visibleSubMenus[i]);
7144					}
7145				}
7146				// save new active item and sub menu for this level
7147				this.activatedItems[level - 1] = $a;
7148				this.visibleSubMenus[level - 1] = $ul;
7149				if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) {
7150					return;
7151				}
7152				// show the sub menu if this item has one
7153				var $sub = $li.dataSM('sub');
7154				if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) {
7155					this.menuShow($sub);
7156				}
7157			},
7158			itemBlur: function(e) {
7159				var $a = $(e.currentTarget);
7160				if (!this.handleItemEvents($a)) {
7161					return;
7162				}
7163				this.$root.triggerHandler('blur.smapi', $a[0]);
7164			},
7165			itemClick: function(e) {
7166				var $a = $(e.currentTarget);
7167
7168				if (!this.handleItemEvents($a)) {
7169					return;
7170				}
7171				$a.removeDataSM('mousedown');
7172				if (this.$root.triggerHandler('click.smapi', $a[0]) === false) {
7173					return false;
7174				}
7175				var $sub = $a.parent().dataSM('sub');
7176				if (this.isTouchMode()) {
7177					// undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu
7178					if ($a.dataSM('href')) {
7179						$a.attr('href', $a.dataSM('href')).removeDataSM('href');
7180					}
7181					// if the sub is not visible
7182					if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
7183						// try to activate the item and show the sub
7184						this.itemActivate($a);
7185						// if "itemActivate" showed the sub, prevent the click so that the link is not loaded
7186						// if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded
7187						if ($sub.is(':visible')) {
7188							return false;
7189						}
7190					}
7191				} else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) {
7192					this.clickActivated = true;
7193					this.menuShow($sub);
7194					return false;
7195				}
7196				if ($a.hasClass('disabled')) {
7197					return false;
7198				}
7199				if (this.$root.triggerHandler('select.smapi', $a[0]) === false) {
7200					return false;
7201				}
7202			},
7203			itemDown: function(e) {
7204				var $a = $(e.currentTarget);
7205				if (!this.handleItemEvents($a)) {
7206					return;
7207				}
7208				$a.dataSM('mousedown', true);
7209			},
7210			itemEnter: function(e) {
7211				var $a = $(e.currentTarget);
7212				if (!this.handleItemEvents($a)) {
7213					return;
7214				}
7215				if (!this.isTouchMode()) {
7216					if (this.showTimeout) {
7217						clearTimeout(this.showTimeout);
7218						this.showTimeout = 0;
7219					}
7220					var self = this;
7221					this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout);
7222				}
7223				this.$root.triggerHandler('mouseenter.smapi', $a[0]);
7224			},
7225			itemFocus: function(e) {
7226				var $a = $(e.currentTarget);
7227				if (!this.handleItemEvents($a)) {
7228					return;
7229				}
7230				// fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus
7231				if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) {
7232					this.itemActivate($a);
7233				}
7234				this.$root.triggerHandler('focus.smapi', $a[0]);
7235			},
7236			itemLeave: function(e) {
7237				var $a = $(e.currentTarget);
7238				if (!this.handleItemEvents($a)) {
7239					return;
7240				}
7241				if (!this.isTouchMode()) {
7242					if ($a[0].blur) {
7243						$a[0].blur();
7244					}
7245					if (this.showTimeout) {
7246						clearTimeout(this.showTimeout);
7247						this.showTimeout = 0;
7248					}
7249				}
7250				$a.removeDataSM('mousedown');
7251				this.$root.triggerHandler('mouseleave.smapi', $a[0]);
7252			},
7253			itemTouchEnd: function(e) {
7254				var $a = $(e.currentTarget);
7255				if (!this.handleItemEvents($a)) {
7256					return;
7257				}
7258				// prevent the address bar on iPhone from sliding down when expanding a sub menu
7259				var $sub = $a.parent().dataSM('sub');
7260				if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
7261					$a.dataSM('href', $a.attr('href'));
7262					$a.attr('href', '#');
7263				}
7264			},
7265			menuFixLayout: function($ul) {
7266				// fixes a menu that is being shown for the first time
7267				if (!$ul.dataSM('shown-before')) {
7268					$ul.hide().dataSM('shown-before', true);
7269					// fix the layout of the items in IE<8
7270					if (IElt8) {
7271						$ul.children().css({ styleFloat: 'left', width: '100%' });
7272					}
7273				}
7274			},
7275			menuHide: function($sub) {
7276				if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) {
7277					return;
7278				}
7279				$sub.stop(true, true);
7280				if ($sub.is(':visible')) {
7281					var complete = function() {
7282						// unset z-index
7283						if (IElt9) {
7284							$sub.parent().css('z-index', '');
7285						} else {
7286							$sub.css('z-index', '');
7287						}
7288					};
7289					// if sub is collapsible (mobile view)
7290					if (this.isCollapsible()) {
7291						if (this.opts.collapsibleHideFunction) {
7292							this.opts.collapsibleHideFunction.call(this, $sub, complete);
7293						} else {
7294							$sub.hide(this.opts.collapsibleHideDuration, complete);
7295						}
7296					} else {
7297						if (this.opts.hideFunction) {
7298							this.opts.hideFunction.call(this, $sub, complete);
7299						} else {
7300							$sub.hide(this.opts.hideDuration, complete);
7301						}
7302					}
7303					// remove IE iframe shim
7304					if ($sub.dataSM('ie-shim')) {
7305						$sub.dataSM('ie-shim').remove();
7306					}
7307					// deactivate scrolling if it is activated for this sub
7308					if ($sub.dataSM('scroll')) {
7309						$sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide();
7310					}
7311					// unhighlight parent item
7312					$sub.dataSM('parent-a').removeClass('highlighted');
7313					var level = $sub.dataSM('level');
7314					this.activatedItems.splice(level - 1, 1);
7315					this.visibleSubMenus.splice(level - 1, 1);
7316					this.$root.triggerHandler('hide.smapi', $sub[0]);
7317				}
7318			},
7319			menuHideAll: function($item) {
7320				if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return;
7321				var $win = $(window),
7322					winW = $win.width();
7323				if ( $('body').hasClass('vmenu') && winW >= 560 ) {
7324					return;
7325				}
7326				if (this.showTimeout) {
7327					clearTimeout(this.showTimeout);
7328					this.showTimeout = 0;
7329				}
7330				// hide all subs
7331				for (var i = this.visibleSubMenus.length - 1; i > 0; i--) {
7332					this.menuHide(this.visibleSubMenus[i]);
7333				}
7334				// hide root if it's popup
7335				if (this.opts.isPopup) {
7336					this.$root.stop(true, true);
7337					if (this.$root.is(':visible')) {
7338						if (this.opts.hideFunction) {
7339							this.opts.hideFunction.call(this, this.$root);
7340						} else {
7341							this.$root.hide(this.opts.hideDuration);
7342						}
7343						// remove IE iframe shim
7344						if (this.$root.dataSM('ie-shim')) {
7345							this.$root.dataSM('ie-shim').remove();
7346						}
7347					}
7348				}
7349				this.activatedItems = [];
7350				this.visibleSubMenus = [];
7351				this.clickActivated = false;
7352				// reset z-index increment
7353				this.zIndexInc = 0;
7354			},
7355			menuIframeShim: function($ul) {
7356				// create iframe shim for the menu
7357				if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
7358					$ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
7359						.css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
7360					);
7361				}
7362			},
7363			menuInit: function($ul) {
7364				if (!$ul.dataSM('in-mega')) {
7365					this.subMenus.push($ul);
7366					// mark UL's in mega drop downs (if any) so we can neglect them
7367					if ($ul.hasClass('mega-menu')) {
7368						$ul.find('ul').dataSM('in-mega', true);
7369					}
7370					// get level (much faster than, for example, using parentsUntil)
7371					var level = 2,
7372						par = $ul[0];
7373					while ((par = par.parentNode.parentNode) != this.$root[0]) {
7374						level++;
7375					}
7376					// cache stuff
7377					$ul.dataSM('parent-a', $ul.prevAll('a').eq(-1))
7378						.dataSM('level', level)
7379						.parent().dataSM('sub', $ul);
7380					// add sub indicator to parent item
7381					if (this.opts.subIndicators) {
7382						$ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone());
7383					}
7384				}
7385			},
7386			menuPosition: function($sub) {
7387				var fixIE = $('html.ie').length;
7388				// if (fixIE) {
7389				// 	var $rowParent = $($sub).closest('.main-menu-container');
7390				// 	$rowParent.height($rowParent.height());
7391				// }
7392				var $a = $sub.dataSM('parent-a'),
7393					$li = $sub.parent(),
7394					$ul = $sub.parent().parent(),
7395					$container = $ul.closest('.row-menu-inner').length ? $ul.closest('.row-menu-inner') : $ul.closest('.uncol'),
7396					level = $sub.dataSM('level'),
7397					subW = this.getWidth($sub),
7398					subH = this.getHeight($sub),
7399					itemOffset = $a.offset(),
7400					itemX = itemOffset.left,
7401					itemY = itemOffset.top,
7402					itemW = this.getWidth($a),
7403					itemH = this.getHeight($a),
7404					$win = $(window),
7405					winX = $win.scrollLeft(),
7406					winY = $win.scrollTop(),
7407					winW = $win.width(),
7408					winH = $win.height(),
7409					containerW = $container.width(),
7410					containerOffsetX = containerW + ((winW - containerW) / 2),
7411					horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'),
7412					subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
7413					subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
7414					x, y, leftPos;
7415				if (horizontalParent) {
7416					x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX;
7417					y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
7418				} else {
7419					x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX;
7420					y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
7421				}
7422				if (this.opts.keepInViewport && !this.isCollapsible()) {
7423					if (this.isFixed()) {
7424						itemX -= winX;
7425						itemY -= winY;
7426						winX = winY = 0;
7427					}
7428					var absX = itemX + x,
7429						absY = itemY + y;
7430					if (this.opts.rightToLeftSubMenus && absX < winX) {
7431						x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
7432					} else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) {
7433						x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW;
7434					}
7435					if (!horizontalParent) {
7436						if (subH < winH && absY + subH > winY + winH) {
7437							y += winY + winH - subH - absY;
7438						} else if (subH >= winH || absY < winY) {
7439							y += winY - absY;
7440						}
7441					}
7442					// do we need scrolling?
7443					// 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH"
7444					if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) {
7445						var self = this;
7446						if (!$sub.dataSM('scroll-arrows')) {
7447							$sub.dataSM('scroll-arrows', $([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0], $('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]])
7448								.bind({
7449									mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); },
7450									mouseleave: function(e) {
7451										self.menuScrollStop($sub);
7452										self.menuScrollOut($sub, e);
7453									},
7454									'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
7455								})
7456								.insertAfter($sub)
7457							);
7458						}
7459						// bind events to show/hide arrows on hover and save scrolling data for this sub
7460						var vportY = winY - (itemY + itemH);
7461						$sub.dataSM('scroll', {
7462								vportY: vportY,
7463								subH: subH,
7464								winH: winH,
7465								step: 1
7466							})
7467							.bind({
7468								'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); },
7469								'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); },
7470								'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); }
7471							})
7472							.dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: this.getWidth($sub) - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: this.get
7472StartZIndex() + this.zIndexInc })
7473							.eq(0).css('margin-top', vportY).end()
7474							.eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end()
7475							.eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
7476					}
7477				}
7478				// if ($sub.hasClass('mega-menu-inner')) {
7479				// 	if ($('.menu-wrapper .megamenu-diff').length > 0) {
7480				// 		leftPos = parseFloat($('.menu-wrapper .megamenu-diff').outerWidth());
7481				// 		leftPos = -leftPos;
7482				// 	} else leftPos = parseFloat($('.menu-wrapper .main-menu-container').css('paddingLeft'));
7483
7484				// 	if ($('body.header-full-width').length > 0) {
7485				// 		$sub.css({ width: $('.box-container').width()});
7486				// 		leftPos = (leftPos - parseFloat($('.menu-wrapper .row-menu-inner').css('paddingLeft')));
7487				// 	} else $sub.css({ width: containerW});
7488				// 	leftPos = leftPos + 'px';
7489
7490				// } else {
7491				// 	leftPos = $li.position().left + 'px';
7492				// }
7493				var rightPos = 'auto';
7494				if ( $sub.parents('.isotope-filters').length ) {
7495					if ( $sub.parents('.text-right').eq(0).length ) {
7496						leftPos = '0px';
7497						rightPos = 'auto';
7498					} else {
7499						leftPos = 'auto';
7500						rightPos = '0px';
7501					}
7502					x = 0;
7503				} else {
7504					if ($sub.hasClass('mega-menu-inner')) {
7505						$sub.css({ width: containerW});
7506						if ( $('body.hmenu-center-double').length ) {
7507							leftPos = '0px';
7508						} else {
7509							if ( $('body.hmenu-center-split').length > 0 && !$sub.closest('.navbar-cta').length && ! $('body.hormenu-position-right').length ) {
7510								leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px';
7511							} else {
7512								if ( $sub.closest('.navbar-cta').length && !$('body.hmenu').length && !$('body.hmenu-center').length ) {
7513									leftPos = - ( parseFloat($sub.closest('.navbar-cta').offset().left) - parseFloat($sub.closest('.row-menu-inner').find('.logo-container').offset().left) ) + 'px';
7514								} else if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0 && !$('body.hmenu-center-split').length) {
7515									leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px';
7516								} else {
7517									leftPos = '0px';
7518								}
7519							}
7520						}
7521					} else {
7522						leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px';
7523						x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1;
7524					}
7525				}
7526
7527
7528				$sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, right: rightPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) });
7529				// IE iframe shim
7530				this.menuIframeShim($sub);
7531				if ($sub.dataSM('ie-shim')) {
7532					$sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) });
7533				}
7534			},
7535			menuScroll: function($sub, up, wheel) {
7536				var y = parseFloat($sub.css('margin-top')),
7537					scroll = $sub.dataSM('scroll'),
7538					end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH),
7539					step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
7540				$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
7541				y = parseFloat($sub.css('margin-top'));
7542				// show opposite arrow if appropriate
7543				if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
7544					$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
7545				}
7546				// accelerate when not using mousewheel to scroll
7547				if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
7548					$sub.dataSM('scroll').step += 0.5;
7549				}
7550				// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
7551				if (Math.abs(y - end) < 1) {
7552					$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
7553					$sub.dataSM('scroll').step = 1;
7554				} else if (!wheel) {
7555					var self = this;
7556					this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
7557				}
7558			},
7559			menuScrollMousewheel: function($sub, e) {
7560				var $closestSub = $(e.target).closest('ul');
7561				while ($closestSub.dataSM('in-mega')) {
7562					$closestSub = $closestSub.parent().closest('ul');
7563				}
7564				if ($closestSub[0] == $sub[0]) {
7565					var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
7566					if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
7567						this.menuScroll($sub, up, true);
7568					}
7569				}
7570				e.preventDefault();
7571			},
7572			menuScrollOut: function($sub, e) {
7573				var reClass = /^scroll-(up|down)/,
7574					$closestSub = $(e.relatedTarget).closest('ul');
7575				while ($closestSub.dataSM('in-mega')) {
7576					$closestSub = $closestSub.parent().closest('ul');
7577				}
7578				if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
7579					$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
7580				}
7581			},
7582			menuScrollOver: function($sub, e) {
7583				var reClass = /^scroll-(up|down)/,
7584					$closestSub = $(e.target).closest('ul');
7585				while ($closestSub.dataSM('in-mega')) {
7586					$closestSub = $closestSub.parent().closest('ul');
7587				}
7588				if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
7589					$sub.dataSM('scroll-arrows').css('visibility', 'visible');
7590				}
7591			},
7592			menuScrollStop: function($sub) {
7593				if (this.scrollTimeout) {
7594					clearTimeout(this.scrollTimeout);
7595					this.scrollTimeout = 0;
7596					$sub.dataSM('scroll').step = 1;
7597				}
7598			},
7599			menuShow: function($sub) {
7600				if (!$sub.dataSM('beforefirstshowfired')) {
7601					$sub.dataSM('beforefirstshowfired', true);
7602					if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
7603						return;
7604					}
7605				}
7606				if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
7607					return;
7608				}
7609				this.menuFixLayout($sub);
7610				$sub.stop(true, true);
7611				if (!$sub.is(':visible')) {
7612					$sub.css({
7613						'visibility': 'visible',
7614						'pointer-events': 'auto',
7615					});
7616					// set z-index - for IE < 9 set it to the parent LI
7617					var zIndex = this.getStartZIndex() + (++this.zIndexInc);
7618					if (IElt9) {
7619						$sub.parent().css('z-index', zIndex);
7620					} else {
7621						$sub.css('z-index', zIndex);
7622					}
7623					// highlight parent item
7624					if (this.opts.keepHighlighted || this.isCollapsible()) {
7625						if ($sub.dataSM('parent-a').attr('data-type') != 'title')
7626							$sub.dataSM('parent-a').addClass('highlighted');
7627					}
7628					// min/max-width fix - no way to rely purely on CSS as all UL's are nested
7629					if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
7630						if (!IElt8) {
7631							$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
7632							if (this.opts.subMenusMinWidth) {
7633							 	$sub.css('min-width', this.opts.subMenusMinWidth);
7634							}
7635							if (this.opts.subMenusMaxWidth) {
7636							 	var noMaxWidth = this.getWidth($sub);
7637							 	$sub.css('max-width', this.opts.subMenusMaxWidth);
7638								if (noMaxWidth > this.getWidth($sub)) {
7639									$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
7640								}
7641							}
7642						// IE6,7
7643 						} else {
7644							$sub.children().css('styleFloat', 'none');
7645							if (IE6) {
7646								$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
7647									.children().children('a').css('white-space', 'nowrap');
7648							} else { // IE7
7649								$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
7650								if (this.opts.subMenusMinWidth) {
7651							    $sub.css('min-width', this.opts.subMenusMinWidth);
7652								}
7653							}
7654							if (this.opts.subMenusMaxWidth) {
7655								var noMaxWidth = $sub.width();
7656								if (IE6) {
7657							 		var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
7658									if (noMaxWidth > maxWidth) {
7659										$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
7660									} else {
7661										$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
7662									}
7663								} else { // IE7
7664									$sub.css('max-width', this.opts.subMenusMaxWidth);
7665									if (noMaxWidth > $sub.width()) {
7666										$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
7667									} else {
7668										$sub.width(noMaxWidth);
7669									}
7670								}
7671							} else {
7672							 	$sub.width($sub.width());
7673							}
7674							$sub.children().css('styleFloat', 'left');
7675						}
7676					}
7677					this.menuPosition($sub);
7678					// insert IE iframe shim
7679					if ($sub.dataSM('ie-shim')) {
7680						$sub.dataSM('ie-shim').insertBefore($sub);
7681					}
7682					var complete = function() {
7683						// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
7684						$sub.css('overflow', '');
7685					};
7686					// if sub is collapsible (mobile view)
7687					if (this.isCollapsible()) {
7688						if (this.opts.collapsibleShowFunction) {
7689							this.opts.collapsibleShowFunction.call(this, $sub, complete);
7690						} else {
7691							$sub.show(this.opts.collapsibleShowDuration, complete);
7692						}
7693					} else {
7694						if (this.opts.showFunction) {
7695							this.opts.showFunction.call(this, $sub, complete);
7696						} else {
7697							$sub.show(this.opts.showDuration, complete);
7698						}
7699					}
7700					// save new sub menu for this level
7701					this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
7702					this.$root.triggerHandler('show.smapi', $sub[0]);
7703				}
7704			},
7705			popupHide: function(noHideTimeout) {
7706				if (this.hideTimeout) {
7707					clearTimeout(this.hideTimeout);
7708					this.hideTimeout = 0;
7709				}
7710				var self = this;
7711				this.hideTimeout = setTimeout(function() {
7712					self.menuHideAll();
7713				}, noHideTimeout ? 1 : this.opts.hideTimeout);
7714			},
7715			popupShow: function(left, top) {
7716				if (!this.opts.isPopup) {
7717					alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
7718					return;
7719				}
7720				if (this.hideTimeout) {
7721					clearTimeout(this.hideTimeout);
7722					this.hideTimeout = 0;
7723				}
7724				this.menuFixLayout(this.$root);
7725				this.$root.stop(true, true);
7726				if (!this.$root.is(':visible')) {
7727					this.$root.css({ left: left, top: top });
7728					// IE iframe shim
7729					this.menuIframeShim(this.$root);
7730					if (this.$root.dataSM('ie-shim')) {
7731						this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
7731: left, top: top }).insertBefore(this.$root);
7732					}
7733					// show menu
7734					if (this.opts.showFunction) {
7735						this.opts.showFunction.call(this, this.$root);
7736					} else {
7737						this.$root.show(this.opts.showDuration);
7738					}
7739					this.visibleSubMenus[0] = this.$root;
7740				}
7741			},
7742			refresh: function() {
7743				this.menuHideAll();
7744				this.$root.find('ul').each(function() {
7745						var $this = $(this);
7746						if ($this.dataSM('scroll-arrows')) {
7747							$this.dataSM('scroll-arrows').remove();
7748						}
7749					})
7750					.removeDataSM('in-mega')
7751					.removeDataSM('shown-before')
7752					.removeDataSM('ie-shim')
7753					.removeDataSM('scroll-arrows')
7754					.removeDataSM('parent-a')
7755					.removeDataSM('level')
7756					.removeDataSM('beforefirstshowfired');
7757				this.$root.find('a.has-submenu').removeClass('has-submenu')
7758					.parent().removeDataSM('sub');
7759				if (this.opts.subIndicators) {
7760					this.$root.find('span.sub-arrow').remove();
7761				}
7762				if (this.opts.markCurrentItem) {
7763					this.$root.find('a.current').removeClass('current');
7764				}
7765				this.subMenus = [];
7766				this.init(true);
7767			},
7768			rootOut: function(e) {
7769				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
7770					return;
7771				}
7772				if (this.hideTimeout) {
7773					clearTimeout(this.hideTimeout);
7774					this.hideTimeout = 0;
7775				}
7776				if (!this.opts.showOnClick || !this.opts.hideOnClick) {
7777					var self = this;
7778					this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
7779				}
7780			},
7781			rootOver: function(e) {
7782				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
7783					return;
7784				}
7785				if (this.hideTimeout) {
7786					clearTimeout(this.hideTimeout);
7787					this.hideTimeout = 0;
7788				}
7789			},
7790			winResize: function(e) {
7791				if (!this.handleEvents()) {
7792					// we still need to resize the disable overlay if it's visible
7793					if (this.$disableOverlay) {
7794						var pos = this.$root.offset();
7795	 					this.$disableOverlay.css({
7796							top: pos.top,
7797							left: pos.left,
7798							width: this.$root.outerWidth(),
7799							height: this.$root.outerHeight()
7800						});
7801					}
7802					return;
7803				}
7804				// hide sub menus on resize - on mobile do it only on orientation change
7805				if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
7806					if (this.activatedItems.length) {
7807						this.activatedItems[this.activatedItems.length - 1][0].blur();
7808					}
7809					this.menuHideAll();
7810				}
7811			}
7812		}
7813	});
7814
7815	$.fn.dataSM = function(key, val) {
7816		if (val) {
7817			return this.data(key + '_smartmenus', val);
7818		}
7819		return this.data(key + '_smartmenus');
7820	}
7821
7822	$.fn.removeDataSM = function(key) {
7823		return this.removeData(key + '_smartmenus');
7824	}
7825
7826	$.fn.smartmenus = function(options) {
7827		if (typeof options == 'string') {
7828			var args = arguments,
7829				method = options;
7830			Array.prototype.shift.call(args);
7831			return this.each(function() {
7832				var smartmenus = $(this).data('smartmenus');
7833				if (smartmenus && smartmenus[method]) {
7834					smartmenus[method].apply(smartmenus, args);
7835				}
7836			});
7837		}
7838		var opts = $.extend({}, $.fn.smartmenus.defaults, options);
7839		return this.each(function() {
7840			new $.SmartMenus(this, opts);
7841		});
7842	}
7843
7844	// default settings
7845	$.fn.smartmenus.defaults = {
7846		isPopup:		false,		// is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
7847		mainMenuSubOffsetX:	0,		// pixels offset from default position
7848		mainMenuSubOffsetY:	0,		// pixels offset from default position
7849		subMenusSubOffsetX:	0,		// pixels offset from default position
7850		subMenusSubOffsetY:	0,		// pixels offset from default position
7851		subMenusMinWidth:	'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
7852		subMenusMaxWidth:	'20em',		// max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
7853		subIndicators: 		true,		// create sub menu indicators - creates a SPAN and inserts it in the A
7854		subIndicatorsPos: 	'prepend',	// position of the SPAN relative to the menu item content ('prepend', 'append')
7855		subIndicatorsText:	'+',		// [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
7856		scrollStep: 		30,		// pixels step when scrolling long sub menus that do not fit in the viewport height
7857		scrollInterval:		30,		// interval between each scrolling step
7858		scrollAccelerate:	true,		// accelerate scrolling or use a fixed step
7859		showTimeout:		250,		// timeout before showing the sub menus
7860		hideTimeout:		500,		// timeout before hiding the sub menus
7861		showDuration:		0,		// duration for show animation - set to 0 for no animation - matters only if showFunction:null
7862		showFunction:		null,		// custom function to use when showing a sub menu (the default is the jQuery 'show')
7863							// don't forget to call complete() at the end of whatever you do
7864							// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
7865		hideDuration:		0,		// duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
7866		hideFunction:		function($ul, complete) { $ul.fadeOut(200, complete); },	// custom function to use when hiding a sub menu (the default is the jQuery 'hide')
7867							// don't forget to call complete() at the end of whatever you do
7868							// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
7869		collapsibleShowDuration:0,		// duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
7870		collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); },	// custom function to use when showing a collapsible sub menu
7871							// (i.e. when mobile styles are used to make the sub menus collapsible)
7872		collapsibleHideDuration:0,		// duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
7873		collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); },	// custom function to use when hiding a collapsible sub menu
7874							// (i.e. when mobile styles are used to make the sub menus collapsible)
7875		showOnClick:		false,		// show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
7876		hideOnClick:		true,		// hide the sub menus on click/tap anywhere on the page
7877		keepInViewport:		true,		// reposition the sub menus if needed to make sure they always appear inside the viewport
7878		keepHighlighted:	true,		// keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
7879		markCurrentItem:	false,		// automatically add the 'current' class to the A element of the item linking to the current URL
7880		markCurrentTree:	true,		// add the 'current' class also to the A elements of all ancestor items of the current item
7881		rightToLeftSubMenus:	false,		// right to left display of the sub menus (check the CSS for the sub indicators' position)
7882		bottomToTopSubMenus:	false,		// bottom to top display of the sub menus
7883		overlapControlsInIE:	true		// make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
7884	};
7885
7886})(jQuery);
7887
7888/*
7889 * jQuery Easing v1.4.1 - http://gsgd.co.uk/sandbox/jquery/easing/
7890 * Open source under the BSD License.
7891 * Copyright © 2008 George McGinley Smith
7892 * All rights reserved.
7893 * https://raw.github.com/gdsmith/jquery.easing/master/LICENSE
7894*/
7895
7896/* globals jQuery, define, module, require */
7897(function (factory) {
7898	if (typeof define === "function" && define.amd) {
7899		define(['jquery'], function ($) {
7900			return factory($);
7901		});
7902	} else if (typeof module === "object" && typeof module.exports === "object") {
7903		module.exports = factory(require('jquery'));
7904	} else {
7905		factory(jQuery);
7906	}
7907})(function($){
7908
7909	// Preserve the original jQuery "swing" easing as "jswing"
7910	if (typeof $.easing !== 'undefined') {
7911		$.easing['jswing'] = $.easing['swing'];
7912	}
7913
7914	var pow = Math.pow,
7915		sqrt = Math.sqrt,
7916		sin = Math.sin,
7917		cos = Math.cos,
7918		PI = Math.PI,
7919		c1 = 1.70158,
7920		c2 = c1 * 1.525,
7921		c3 = c1 + 1,
7922		c4 = ( 2 * PI ) / 3,
7923		c5 = ( 2 * PI ) / 4.5;
7924
7925	// x is the fraction of animation progress, in the range 0..1
7926	function bounceOut(x) {
7927		var n1 = 7.5625,
7928			d1 = 2.75;
7929		if ( x < 1/d1 ) {
7930			return n1*x*x;
7931		} else if ( x < 2/d1 ) {
7932			return n1*(x-=(1.5/d1))*x + .75;
7933		} else if ( x < 2.5/d1 ) {
7934			return n1*(x-=(2.25/d1))*x + .9375;
7935		} else {
7936			return n1*(x-=(2.625/d1))*x + .984375;
7937		}
7938	}
7939
7940	$.extend( $.easing, {
7941		def: 'easeOutQuad',
7942		swing: function (x) {
7943			return $.easing[$.easing.def](x);
7944		},
7945		easeInQuad: function (x) {
7946			return x * x;
7947		},
7948		easeOutQuad: function (x) {
7949			return 1 - ( 1 - x ) * ( 1 - x );
7950		},
7951		easeInOutQuad: function (x) {
7952			return x < 0.5 ?
7953				2 * x * x :
7954				1 - pow( -2 * x + 2, 2 ) / 2;
7955		},
7956		easeInCubic: function (x) {
7957			return x * x * x;
7958		},
7959		easeOutCubic: function (x) {
7960			return 1 - pow( 1 - x, 3 );
7961		},
7962		easeInOutCubic: function (x) {
7963			return x < 0.5 ?
7964				4 * x * x * x :
7965				1 - pow( -2 * x + 2, 3 ) / 2;
7966		},
7967		easeInQuart: function (x) {
7968			return x * x * x * x;
7969		},
7970		easeOutQuart: function (x) {
7971			return 1 - pow( 1 - x, 4 );
7972		},
7973		easeInOutQuart: function (x) {
7974			return x < 0.5 ?
7975				8 * x * x * x * x :
7976				1 - pow( -2 * x + 2, 4 ) / 2;
7977		},
7978		easeInQuint: function (x) {
7979			return x * x * x * x * x;
7980		},
7981		easeOutQuint: function (x) {
7982			return 1 - pow( 1 - x, 5 );
7983		},
7984		easeInOutQuint: function (x) {
7985			return x < 0.5 ?
7986				16 * x * x * x * x * x :
7987				1 - pow( -2 * x + 2, 5 ) / 2;
7988		},
7989		easeInSine: function (x) {
7990			return 1 - cos( x * PI/2 );
7991		},
7992		easeOutSine: function (x) {
7993			return sin( x * PI/2 );
7994		},
7995		easeInOutSine: function (x) {
7996			return -( cos( PI * x ) - 1 ) / 2;
7997		},
7998		easeInExpo: function (x) {
7999			return x === 0 ? 0 : pow( 2, 10 * x - 10 );
8000		},
8001		easeOutExpo: function (x) {
8002			return x === 1 ? 1 : 1 - pow( 2, -10 * x );
8003		},
8004		easeInOutExpo: function (x) {
8005			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
8006				pow( 2, 20 * x - 10 ) / 2 :
8007				( 2 - pow( 2, -20 * x + 10 ) ) / 2;
8008		},
8009		easeInCirc: function (x) {
8010			return 1 - sqrt( 1 - pow( x, 2 ) );
8011		},
8012		easeOutCirc: function (x) {
8013			return sqrt( 1 - pow( x - 1, 2 ) );
8014		},
8015		easeInOutCirc: function (x) {
8016			return x < 0.5 ?
8017				( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 :
8018				( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2;
8019		},
8020		easeInElastic: function (x) {
8021			return x === 0 ? 0 : x === 1 ? 1 :
8022				-pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 );
8023		},
8024		easeOutElastic: function (x) {
8025			return x === 0 ? 0 : x === 1 ? 1 :
8026				pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1;
8027		},
8028		easeInOutElastic: function (x) {
8029			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
8030				-( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 :
8031				pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1;
8032		},
8033		easeInBack: function (x) {
8034			return c3 * x * x * x - c1 * x * x;
8035		},
8036		easeOutBack: function (x) {
8037			return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 );
8038		},
8039		easeInOutBack: function (x) {
8040			return x < 0.5 ?
8041				( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 :
8042				( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2;
8043		},
8044		easeInBounce: function (x) {
8045			return 1 - bounceOut( 1 - x );
8046		},
8047		easeOutBounce: bounceOut,
8048		easeInOutBounce: function (x) {
8049			return x < 0.5 ?
8050				( 1 - bounceOut( 1 - 2 * x ) ) / 2 :
8051				( 1 + bounceOut( 2 * x - 1 ) ) / 2;
8052		}
8053	});
8054	return $;
8055});
8056
8057(function($, window, undefined) {
8058    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
8059    // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
8060 
8061    // requestAnimationFrame polyfill by Erik Möller
8062    // fixes from Paul Irish and Tino Zijdel
8063 
8064    var lastTime = 0,
8065        running,
8066        animate = function (elem) {
8067            if (running) {
8068                window.requestAnimationFrame(animate, elem);
8069                jQuery.fx.tick();
8070            }
8071        },
8072        vendors = ['ms', 'moz', 'webkit', 'o'];
8073 
8074    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
8075        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
8076        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
8077            || window[vendors[x]+'CancelRequestAnimationFrame'];
8078    }
8079 
8080    if (!window.requestAnimationFrame)
8081        window.requestAnimationFrame = function(fn, element) {
8082            var currTime = new Date().getTime(),
8083                delta = currTime - lastTime,
8084                timeToCall = Math.max(0, 16 - delta);
8085 
8086            var id = window.setTimeout(function() {
8087                    fn(currTime + timeToCall);
8088                },
8089                timeToCall
8090            );
8091 
8092            lastTime = currTime + timeToCall;
8093 
8094            return id;
8095        };
8096 
8097    if (!window.cancelAnimationFrame) {
8098        window.cancelAnimationFrame = function(id) {
8099            clearTimeout(id);
8100        };
8101    }
8102 
8103    jQuery.fx.timer = function (timer) {
8104        if (timer() && jQuery.timers.push(timer) && !running) {
8105            running = true;
8106            animate(timer.elem);
8107        }
8108    };
8109 
8110    jQuery.fx.stop = function() {
8111        running = false;
8112    };
8113 
8114}(jQuery, this));
8115/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
8116 * Licensed under the MIT License (LICENSE.txt).
8117 *
8118 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
8119 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
8120 * Thanks to: Seamus Leahy for adding deltaX and deltaY
8121 *
8122 * Version: 3.0.6
8123 *
8124 * Requires: 1.2.2+
8125 */
8126(function($) {
8127    var types = ['DOMMouseScroll', 'mousewheel'];
8128    if ($.event.fixHooks) {
8129        for (var i = types.length; i;) {
8130            $.event.fixHooks[types[--i]] = $.event.mouseHooks;
8131        }
8132    }
8133    $.event.special.mousewheel = {
8134        setup: function() {
8135            if (this.addEventListener) {
8136                for (var i = types.length; i;) {
8137                    this.addEventListener(types[--i], handler, false);
8138                }
8139            } else {
8140                this.onmousewheel = handler;
8141            }
8142        },
8143        teardown: function() {
8144            if (this.removeEventListener) {
8145                for (var i = types.length; i;) {
8146                    this.removeEventListener(types[--i], handler, false);
8147                }
8148            } else {
8149                this.onmousewheel = null;
8150            }
8151        }
8152    };
8153    $.fn.extend({
8154        mousewheel: function(fn) {
8155            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
8156        },
8157        unmousewheel: function(fn) {
8158            return this.unbind("mousewheel", fn);
8159        }
8160    });
8161
8162    function handler(event) {
8163        var orgEvent = event || window.event,
8164            args = [].slice.call(arguments, 1),
8165            delta = 0,
8166            returnValue = true,
8167            deltaX = 0,
8168            deltaY = 0;
8169        event = $.event.fix(orgEvent);
8170        event.type = "mousewheel";
8171        // Old school scrollwheel delta
8172        if (orgEvent.wheelDelta) {
8173            delta = orgEvent.wheelDelta / 120;
8174        }
8175        if (orgEvent.detail) {
8176            delta = -orgEvent.detail / 3;
8177        }
8178        // New school multidimensional scroll (touchpads) deltas
8179        deltaY = delta;
8180        // Gecko
8181        if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
8182            deltaY = 0;
8183            deltaX = -1 * delta;
8184        }
8185        // Webkit
8186        if (orgEvent.wheelDeltaY !== undefined) {
8187            deltaY = orgEvent.wheelDeltaY / 120;
8188        }
8189        if (orgEvent.wheelDeltaX !== undefined) {
8190            deltaX = -1 * orgEvent.wheelDeltaX / 120;
8191        }
8192        // Add event and delta to the front of the arguments
8193        args.unshift(event, delta, deltaX, deltaY);
8194        return ($.event.dispatch || $.event.handle).apply(this, args);
8195    }
8196})(jQuery);
8197/**
8198 * jQuery iLightBox - Revolutionary Lightbox Plugin
8199 * http://www.ilightbox.net/
8200 *
8201 * @version: 2.2.4 - October 14, 2017
8202 *
8203 * @author: iProDev (Hemn Chawroka)
8204 *          http://www.iprodev.com/
8205 *
8206 */
8207(function($, window, undefined) {
8208
8209	var extensions = {
8210			flash: ['swf'],
8211			image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'],
8212			iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'],
8213			video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v']
8214		},
8215
8216		// Global DOM elements
8217		$win = $(window),
8218		$doc = $(document),
8219
8220		// Support indicators
8221		browser,
8222		transform,
8223		gpuAcceleration,
8224		fullScreenApi = '',
8225		userAgent = navigator.userAgent || navigator.vendor || window.opera,
8226        supportTouch = "ontouchstart" in window || navigator.msMaxTouchPoints || (navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1),
8227        ishybrid = navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1,
8228        isMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
8228sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)),
8229
8230		// Events
8231		clickEvent = ishybrid ? "itap.iLightBox click.iLightBox" : supportTouch ? "itap.iLightBox" : "click.iLightBox",
8232		touchStartEvent = ishybrid ? "touchstart.iLightBox mousedown.iLightBox" : supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox",
8233		touchStopEvent = ishybrid ? "touchend.iLightBox mouseup.iLightBox" : supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox",
8234		touchMoveEvent = ishybrid ? "touchmove.iLightBox mousemove.iLightBox" : supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox",
8235
8236		// Math shorthands
8237		abs = Math.abs,
8238		sqrt = Math.sqrt,
8239		round = Math.round,
8240		max = Math.max,
8241		min = Math.min,
8242		floor = Math.floor,
8243		random = Math.random,
8244
8245		pluginspages = {
8246			quicktime: 'http://www.apple.com/quicktime/download',
8247			flash: 'http://www.adobe.com/go/getflash'
8248		},
8249
8250		iLightBox = function(el, options, items, instant) {
8251			var iL = this;
8252
8253			iL.options = options,
8254				iL.selector = options.selector || el,
8255				iL.context = document,
8256				iL.instant = instant;
8257
8258			if (items.length < 1) iL.attachItems();
8259			else iL.items = items;
8260
8261			iL.vars = {
8262				total: iL.items.length,
8263				start: 0,
8264				current: null,
8265				next: null,
8266				prev: null,
8267				BODY: $('body'),
8268				loadRequests: 0,
8269				overlay: $('<div class="ilightbox-overlay"></div>'),
8270				loader: $('<div class="ilightbox-loader"><div></div></div>'),
8271				toolbar: $('<div class="ilightbox-toolbar"></div>'),
8272				innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'),
8273				title: $('<div class="ilightbox-title"></div>'),
8274				closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'),
8275				fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'),
8276				innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'),
8277				innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'),
8278				innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'),
8279				holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
8280				nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
8281				prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
8282				nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'),
8283				prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
8284				thumbnails: $('<div class="ilightbox-thumbnails" ondragstart="return false;"><div class="ilightbox-thumbnails-container"><a class="ilightbox-thumbnails-dragger"></a><div class="ilightbox-thumbnails-grid"></div></div></div>'),
8285				thumbs: false,
8286				nextLock: false,
8287				prevLock: false,
8288				hashLock: false,
8289				isMobile: false,
8290				mobileMaxWidth: 980,
8291				isInFullScreen: false,
8292				isSwipe: false,
8293				mouseID: 0,
8294				cycleID: 0,
8295				isPaused: 0,
8296				captionHeight: 39,
8297			};
8298
8299			// Hideable elements with mousemove event
8300			iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton);
8301
8302			iL.normalizeItems();
8303
8304			//Check necessary plugins
8305			iL.availPlugins();
8306
8307			//Set startFrom
8308			iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom;
8309
8310			//If randomStart
8311			iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom;
8312			iL.vars.start = iL.options.startFrom;
8313
8314			if (instant) iL.instantCall();
8315			else iL.patchItemsEvents();
8316
8317			if (iL.options.linkId) {
8318				iL.hashChangeHandler();
8319				$win.iLightBoxHashChange(function() {
8320					iL.hashChangeHandler();
8321				});
8322			}
8323
8324			if (supportTouch) {
8325				var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig,
8326					replace = "itap";
8327				iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace),
8328					iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace),
8329					iL.options.social.show = iL.options.social.show.replace(RegExp, replace),
8330					iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace);
8331			}
8332
8333			if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) {
8334				$.extend(iL.options.styles, {
8335					nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
8336					prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
8337					nextOpacity: 0,
8338					prevOpacity: 0
8339				});
8340			}
8341		};
8342
8343	//iLightBox helpers
8344	iLightBox.prototype = {
8345		showLoader: function() {
8346			var iL = this;
8347			iL.vars.loadRequests += 1;
8348			if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({
8349				//top: '-30px'
8350				opacity: '1'
8351			}, iL.options.show.speed, 'easeOutCirc');
8352			else iL.vars.loader.addClass('ilightbox-show').stop().animate({
8353				//left: '-30px'
8354				opacity: '1'
8355			}, iL.options.show.speed, 'easeOutCirc');
8356		},
8357
8358		hideLoader: function() {
8359			var iL = this;
8360			iL.vars.loadRequests -= 1;
8361			iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests;
8362			if (iL.options.path.toLowerCase() == "horizontal") {
8363				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
8364					//top: '-192px'
8365					opacity: '0'
8366				}, iL.options.show.speed, 'easeInCirc');
8367			} else {
8368				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
8369					//left: '-192px'
8370					opacity: '0'
8371				}, iL.options.show.speed, 'easeInCirc');
8372			}
8373		},
8374
8375		createUI: function() {
8376			var iL = this;
8377
8378			iL.ui = {
8379				currentElement: iL.vars.holder,
8380				nextElement: iL.vars.nextPhoto,
8381				prevElement: iL.vars.prevPhoto,
8382				currentItem: iL.vars.current,
8383				nextItem: iL.vars.next,
8384				prevItem: iL.vars.prev,
8385				hide: function() {
8386					iL.closeAction();
8387				},
8388				refresh: function() {
8389					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
8390				},
8391				fullscreen: function() {
8392					iL.fullScreenAction();
8393				}
8394			};
8395		},
8396
8397		attachItems: function() {
8398			var iL = this,
8399				itemsObject = new Array(),
8400				items = new Array();
8401
8402			$(iL.selector, iL.context).each(function() {
8403				var t = $(this),
8404					URL = t.attr(iL.options.attr) || null,
8405					options = t.data("options") && eval("({" + t.data("options") + "})") || {},
8406					caption = t.data('caption'),
8407					title = t.data('title'),
8408					type = t.data('type') || getTypeByExtension(URL),
8409					clone = t.data('lbox-clone') || false;
8410
8411				//Uncode addition ##START##
8412				if (type === false) {
8413					return;
8414				}
8415				//Uncode addition ##END##
8416
8417				if (t.data('lbox-clone') != undefined) return;
8418
8419				//Uncode addition ##START##
8420				if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) {
8421					var ALBUM_URLS = JSON.parse(t.attr('data-album')),
8422						URL_i,
8423						URLS_LENGHT = ALBUM_URLS.length;
8424
8425					for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) {
8426						if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) {
8427							var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\'';
8428							item_opts = item_opts && eval("({" + item_opts + "})") || {},
8429							items.push({
8430								URL: ALBUM_URLS[URL_i].url,
8431								caption: ALBUM_URLS[URL_i].caption,
8432								title: ALBUM_URLS[URL_i].title,
8433								type: getTypeByExtension(ALBUM_URLS[URL_i].url),
8434								options: item_opts,
8435								clone: clone
8436							});
8437							var newT = t;
8438							newT.attr('href',ALBUM_URLS[URL_i].url);
8439							if (!iL.instant) itemsObject.push(newT);
8440						}
8441					}
8442				} else {
8443				//Uncode addition ##END##
8444					items.push({
8445						URL: URL,
8446						caption: caption,
8447						title: title,
8448						type: type,
8449						options: options,
8450						clone: clone
8451					});
8452				}
8453
8454
8455				if (iL.vars != undefined) iL.vars.total = items.length;
8456
8457				if (!iL.instant) itemsObject.push(t);
8458			});
8459
8460			iL.items = items,
8461				iL.itemsObject = itemsObject;
8462
8463		},
8464
8465		normalizeItems: function() {
8466			var iL = this,
8467				newItems = new Array();
8468
8469			$.each(iL.items, function(key, val) {
8470
8471				if (typeof val == "string") val = {
8472					url: val
8473				};
8474
8475				var URL = val.url || val.URL || null,
8476					options = val.options || {},
8477					caption = val.caption || null,
8478					title = val.title || null,
8479					type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL),
8480					ext = (typeof URL != 'object') ? getExtension(URL) : '';
8481
8482				options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
8483				options.videoType = options.videoType || null,
8484				options.skin = options.skin || iL.options.skin,
8485				options.width = options.width || null,
8486				options.height = options.height || null,
8487				options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true,
8488				options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true,
8489				options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons);
8490
8491				if (type == "video") {
8492					options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {};
8493
8494					options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null;
8495					options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls";
8496					options.html5video.preload = options.html5video.preload || "metadata";
8497					options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false;
8498					//UNCODE addition
8499					options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false;
8500				}
8501
8502				if (!options.width || !options.height) {
8503					if (type == "video") options.width = 1280, options.height = 720;
8504					else if (type == "iframe") options.width = '100%', options.height = '90%';
8505					else if (type == "flash") options.width = 1280, options.height = 720;
8506				}
8507
8508				delete val.url;
8509				val.index = key;
8510				val.URL = URL;
8511				val.caption = caption;
8512				val.title = title;
8513				val.type = type;
8514				val.options = options;
8515				val.ext = ext;
8516
8517				newItems.push(val);
8518			});
8519
8520			iL.items = newItems;
8521		},
8522
8523		instantCall: function() {
8524			var iL = this,
8525				key = iL.vars.start;
8526
8527			iL.vars.current = key;
8528			iL.vars.next = (iL.items[key + 1]) ? key + 1 : null;
8529			iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null;
8530
8531			iL.addContents();
8532			iL.patchEvents();
8533		},
8534
8535		addContents: function() {
8536			var iL = this,
8537				vars = iL.vars,
8538				opts = iL.options,
8539				viewport = getViewport(),
8540				path = opts.path.toLowerCase(),
8541				recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) {
8542					return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition);
8543				}),
8544				needRecognition = recognizingItems.length > 0;
8545
8546			if (opts.mobileOptimizer && !opts.innerToolbar)
8547				vars.isMobile = viewport.width <= vars.mobileMaxWidth;
8548
8549			vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity);
8550
8551			if (opts.linkId)
8552				vars.overlay[0].setAttribute('linkid', opts.linkId);
8553
8554			//Add Toolbar Buttons
8555			if (opts.controls.toolbar) {
8556				vars.toolbar.addClass(opts.skin).append(vars.closeButton);
8557				if (opts.controls.fullscreen)
8558					vars.toolbar.append(vars.fullScreenButton);
8559				if (opts.controls.slideshow)
8560					vars.toolbar.append(vars.innerPlayButton);
8561				if (vars.total > 1)
8562					vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton);
8563			}
8564
8565			//Append elements to body
8566			vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto);
8567
8568			if (!opts.innerToolbar)
8569				vars.BODY.append(vars.toolbar);
8570			if (opts.controls.arrows)
8571				vars.BODY.append(vars.nextButton).append(vars.prevButton);
8572
8573			if (opts.controls.thumbnail && vars.total > 1) {
8574				vars.BODY.append(vars.thumbnails);
8575				vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path);
8576				$('div.ilightbox-thumbnails-grid', vars.thumbnails).empty();
8577				vars.thumbs = true;
8578			}
8579
8580			//Configure loader and arrows
8581			var loaderCss = (opts.path.toLowerCase() == "horizontal") ? {
8582				left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2))
8583			} : {
8584				top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2))
8585			};
8586			vars.loader.addClass(opts.skin).css(loaderCss);
8587			vars.nextButton.add(vars.prevButton).addClass(opts.skin);
8588			if (path == "horizontal")
8589				vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal');
8590
8591			// Configure arrow buttons
8592			vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
8593
8594			if (!opts.infinite) {
8595				vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8596
8597				if (vars.current == 0)
8598					vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8599				if (vars.current >= vars.total - 1)
8600					vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8601			}
8602
8603			if (opts.show.effect) {
8604				vars.overlay.stop().fadeIn(opts.show.speed);
8605				vars.toolbar.stop().fadeIn(opts.show.speed);
8606			} else {
8607				vars.overlay.show();
8608				vars.toolbar.show();
8609			}
8610
8611			var length = recognizingItems.length;
8612			if (needRecognition) {
8613				iL.showLoader();
8614
8615				$.each(recognizingItems, function(key, val) {
8616					var resultFnc = function(result) {
8617							var key = -1,
8618								filter = iL.items.filter(function(e, i, arr) {
8619									if (e.URL == result.url)
8620										key = i;
8621
8622									return e.URL == result.url;
8623								}),
8624								self = iL.items[key];
8625
8626							if (result)
8627								$.extend(true, self, {
8628									URL: result.source,
8629									type: result.type,
8630									recognized: true,
8631									options: {
8632										html5video: result.html5video,
8633										width: (result.type == "image") ? 0 : (result.width || self.width),
8634										height: (result.type == "image") ? 0 : (result.height || self.height),
8635										thumbnail: self.options.thumbnail || result.thumbnail
8636									}
8637								});
8638
8639							length--;
8640
8641							if (length == 0) {
8642								iL.hideLoader();
8643
8644								vars.dontGenerateThumbs = false;
8645								iL.generateThumbnails();
8646
8647								if (opts.show.effect)
8648									setTimeout(function() {
8649										iL.generateBoxes();
8650									}, opts.show.speed);
8651								else
8652									iL.generateBoxes();
8653							}
8654						};
8655
8656					iL.ogpRecognition(this, resultFnc);
8657				});
8658			}
8659			else {
8660				if (opts.show.effect)
8661					setTimeout(function() {
8662						iL.generateBoxes();
8663					}, opts.show.speed);
8664				else
8665					iL.generateBoxes();
8666			}
8667
8668			iL.createUI();
8669
8670			window.iLightBox = {
8671				close: function() {
8672					iL.closeAction();
8673				},
8674				fullscreen: function() {
8675					iL.fullScreenAction();
8676				},
8677				moveNext: function() {
8678					iL.moveTo('next');
8679				},
8680				movePrev: function() {
8681					iL.moveTo('prev');
8682				},
8683				goTo: function(index) {
8684					iL.goTo(index);
8685				},
8686				refresh: function() {
8687					iL.refresh();
8688				},
8689				reposition: function() {
8690					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
8691				},
8692				setOption: function(options) {
8693					iL.setOption(options);
8694				},
8695				destroy: function() {
8696					iL.closeAction();
8697					iL.dispatchItemsEvents();
8698				}
8699			};
8700
8701			if (opts.linkId) {
8702				vars.hashLock = true;
8703				window.location.hash = opts.linkId + '/' + vars.current;
8704				setTimeout(function() {
8705					vars.hashLock = false;
8706				}, 55);
8707			}
8708
8709			if (!opts.slideshow.startPaused) {
8710				iL.resume();
8711				vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause');
8712			}
8713
8714			//Trigger the onOpen callback
8715			if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL);
8716		},
8717
8718		loadContent: function(obj, opt, speed) {
8719			var iL = this,
8720				holder, item;
8721
8722			iL.createUI();
8723
8724			obj.speed = speed || iL.options.effects.loadedFadeSpeed;
8725
8726			if (opt == 'current') {
8727				if (!obj.options.mousewheel) iL.vars.lockWheel = true;
8728				else iL.vars.lockWheel = false;
8729
8730				if (!obj.options.swipe) iL.vars.lockSwipe = true;
8731				else iL.vars.lockSwipe = false;
8732			}
8733
8734			switch (opt) {
8735				case 'current':
8736					holder = iL.vars.holder, item = iL.vars.current;
8737					break;
8738				case 'next':
8739					holder = iL.vars.nextPhoto, item = iL.vars.next;
8740					break;
8741				case 'prev':
8742					holder = iL.vars.prevPhoto, item = iL.vars.prev;
8743					break;
8744			}
8745
8746			holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin);
8747			$('div.ilightbox-inner-toolbar', holder).remove();
8748
8749			if (obj.title || iL.options.innerToolbar) {
8750				var innerToolbar = iL.vars.innerToolbar.clone();
8751				if (obj.title && iL.options.show.title) {
8752					var title = iL.vars.title.clone();
8753					title.empty().html(obj.title);
8754					innerToolbar.append(title);
8755				}
8756				if (iL.options.innerToolbar) {
8757					innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar);
8758				}
8759				holder.prepend(innerToolbar);
8760			}
8761
8762			//console.warn('loadContent', arguments);
8763
8764			iL.loadSwitcher(obj, holder, item, opt);
8765		},
8766
8767		loadSwitcher: function(obj, holder, item, opt) {
8768			var iL = this,
8769				opts = iL.options,
8770				api = {
8771					element: holder,
8772					position: item
8773				};
8774
8775			switch (obj.type) {
8776				case 'image':
8777					//Trigger the onBeforeLoad callback
8778					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8779					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8780
8781					iL.loadImage(obj.URL, function(img) {
8782						//Trigger the onAfterLoad callback
8783						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8784						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8785
8786						var width = (img) ? img.width : 400,
8787							height = (img) ? img.height : 200;
8788
8789						holder.data({
8790							naturalWidth: width,
8791							naturalHeight: height
8792						});
8793
8794						$('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>');
8795
8796						//Trigger the onRender callback
8797						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8798						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8799
8800						iL.configureHolder(obj, opt, holder);
8801					});
8802
8803					break;
8804
8805				case 'video':
8806					holder.data({
8807						naturalWidth: obj.options.width,
8808						naturalHeight: obj.options.height
8809					});
8810
8811					if (opt === 'current') {
8812						iL.addContent(holder, obj);
8813
8814						//Trigger the onRender callback
8815						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8816						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8817					} else {
8818						$('div.ilightbox-container', holder).empty();
8819					}
8820
8821					iL.configureHolder(obj, opt, holder);
8822
8823					break;
8824
8825				case 'iframe':
8826					//iL.showLoader();
8827					holder.data({
8828						naturalWidth: obj.options.width,
8829						naturalHeight: obj.options.height
8830					});
8831
8832					iL.configureHolder(obj, opt, holder);
8833
8834					if (opt === 'current') {
8835						var el = iL.addContent(holder, obj);
8836
8837						//Trigger the onRender callback
8838						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8839						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8840
8841						//Trigger the onBeforeLoad callback
8842						if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8843						if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8844
8845						el.bind('load', function() {
8846							//Trigger the onAfterLoad callback
8847							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8848							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8849
8850							//iL.hideLoader();
8851							el.unbind('load');
8852						});
8853					} else {
8854						$('div.ilightbox-container', holder).empty();
8855					}
8856
8857					break;
8858
8859				case 'inline':
8860					var el = $(obj.URL),
8861						content = iL.addContent(holder, obj),
8862						images = findImageInElement(holder);
8863
8864					holder.data({
8865						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
8866						naturalHeight: (iL.items[item].options.height || el.outerHeight())
8867					});
8868					content.children().eq(0).show();
8869
8870					//Trigger the onRender callback
8871					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8872					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8873
8874					//Trigger the onBeforeLoad callback
8875					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8876					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8877
8878					iL.loadImage(images, function() {
8879						//Trigger the onAfterLoad callback
8880						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8881						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8882
8883						iL.configureHolder(obj, opt, holder);
8884					});
8885
8886					break;
8887
8888				case 'flash':
8889					var el = iL.addContent(holder, obj);
8890
8891					holder.data({
8892						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
8893						naturalHeight: (iL.items[item].options.height || el.outerHeight())
8894					});
8895
8896					//Trigger the onRender callback
8897					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8898					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8899
8900					iL.configureHolder(obj, opt, holder);
8901
8902					break;
8903
8904				case 'ajax':
8905					var ajax = obj.options.ajax || {};
8906					//Trigger the onBeforeLoad callback
8907					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8908					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8909
8910					iL.showLoader();
8911					$.ajax({
8912						url: obj.URL || opts.ajaxSetup.url,
8913						data: ajax.data || null,
8914						dataType: ajax.dataType || "html",
8915						type: ajax.type || opts.ajaxSetup.type,
8916						cache: ajax.cache || opts.ajaxSetup.cache,
8917						crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain,
8918						global: ajax.global || opts.ajaxSetup.global,
8919						ifModified: ajax.ifModified || opts.ajaxSetup.ifModified,
8920						username: ajax.username || opts.ajaxSetup.username,
8921						password: ajax.password || opts.ajaxSetup.password,
8922						beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend,
8923						complete: ajax.complete || opts.ajaxSetup.complete,
8924						success: function(data, textStatus, jqXHR) {
8925							iL.hideLoader();
8926
8927							var el = $(data),
8928								container = $('div.ilightbox-container', holder),
8929								elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')),
8930								elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')),
8931								css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? {
8932									'overflow': 'hidden'
8933								} : {};
8934
8935							container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el));
8936							holder.show().data({
8937								naturalWidth: (elWidth || container.outerWidth()),
8938								naturalHeight: (elHeight || container.outerHeight())
8939							}).hide();
8940
8941							//Trigger the onRender callback
8942							if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8943							if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8944
8945							var images = findImageInElement(holder);
8946							iL.loadImage(images, function() {
8947								//Trigger the onAfterLoad callback
8948								if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8949								if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8950
8951								iL.configureHolder(obj, opt, holder);
8952							});
8953
8954							opts.ajaxSetup.success(data, textStatus, jqXHR);
8955							if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR);
8956						},
8957						error: function(jqXHR, textStatus, errorThrown) {
8958							//Trigger the onAfterLoad callback
8959							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8960							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8961
8962							iL.hideLoader();
8963							$('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>');
8964							iL.configureHolder(obj, opt, holder);
8965
8966							opts.ajaxSetup.error(jqXHR, textStatus, errorThrown);
8967							if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown);
8968						}
8969					});
8970
8971					break;
8972
8973				case 'html':
8974					var object = obj.URL,
8975						el
8976					container = $('div.ilightbox-container', holder);
8977
8978					if (object[0].nodeName) el = object.clone();
8979					else {
8980						var dom = $(object);
8981						if (dom.selector) el = $('<div>' + dom + '</div>');
8982						else el = dom;
8983					}
8984
8985					var elWidth = iL.items[item].options.width || parseInt(el.attr('width')),
8986						elHeight = iL.items[item].options.height || parseInt(el.attr('height'));
8987
8988					iL.addContent(holder, obj);
8989
8990					el.appendTo(document.documentElement).hide();
8991
8992					//Trigger the onRender callback
8993					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8994					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8995
8996					var images = findImageInElement(holder);
8997
8998					//Trigger the onBeforeLoad callback
8999					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
9000					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
9001
9002					iL.loadImage(images, function() {
9003						//Trigger the onAfterLoad callback
9004						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
9005						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
9006
9007						holder.show().data({
9008							naturalWidth: (elWidth || container.outerWidth()),
9009							naturalHeight: (elHeight || container.outerHeight())
9010						}).hide();
9011						el.remove();
9012
9013						iL.configureHolder(obj, opt, holder);
9014					});
9015
9016					break;
9017			}
9018		},
9019
9020		configureHolder: function(obj, opt, holder) {
9021			var iL = this,
9022				vars = iL.vars,
9023				opts = iL.options;
9024
9025			if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev');
9026
9027			if (opt == "current")
9028				var item = vars.current;
9029			else if (opt == "next")
9030				var opacity = opts.styles.nextOpacity,
9031					item = vars.next;
9032			else
9033				var opacity = opts.styles.prevOpacity,
9034					item = vars.prev;
9035
9036			var api = {
9037				element: holder,
9038				position: item
9039			};
9040
9041			iL.items[item].options.width = iL.items[item].options.width || 0,
9042			iL.items[item].options.height = iL.items[item].options.height || 0;
9043
9044			if (opt == "current") {
9045				if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() {
9046					holder.css(transform, '');
9047					if (obj.caption) {
9048						iL.setCaption(obj, holder);
9049						var caption = $('div.ilightbox-caption', holder),
9050							percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100);
9051						if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
9051Speed);
9052					}
9053
9054					var social = obj.options.social;
9055					if (social) {
9056						iL.setSocial(social, obj.URL, holder);
9057						if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed);
9058					}
9059
9060					//Generate thumbnails
9061					iL.generateThumbnails();
9062
9063					//Trigger the onShow callback
9064					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9065					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9066				});
9067				else {
9068					holder.show();
9069
9070					//Generate thumbnails
9071					iL.generateThumbnails();
9072
9073					//Trigger the onShow callback
9074					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9075					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9076				}
9077			} else {
9078				if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() {
9079					if (opt == "next") vars.nextLock = false;
9080					else vars.prevLock = false;
9081
9082					//Generate thumbnails
9083					iL.generateThumbnails();
9084
9085					//Trigger the onShow callback
9086					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9087					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9088				});
9089				else {
9090					holder.css({
9091						opacity: opacity
9092					}).show();
9093					if (opt == "next") vars.nextLock = false;
9094					else vars.prevLock = false;
9095
9096					//Generate thumbnails
9097					iL.generateThumbnails();
9098
9099					//Trigger the onShow callback
9100					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9101					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9102				}
9103			}
9104
9105			setTimeout(function() {
9106				iL.repositionPhoto();
9107			}, 0);
9108		},
9109
9110		generateBoxes: function() {
9111			var iL = this,
9112				vars = iL.vars,
9113				opts = iL.options;
9114
9115			if (opts.infinite && vars.total >= 3) {
9116				if (vars.current == vars.total - 1) vars.next = 0;
9117				if (vars.current == 0) vars.prev = vars.total - 1;
9118			} else opts.infinite = false;
9119
9120			//UNCODE addition
9121			if ( typeof iL.items[vars.current] == 'undefined' )
9122				vars.current = 0;
9123
9124			iL.loadContent(iL.items[vars.current], 'current', opts.show.speed);
9125
9126			if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed);
9127			if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed);
9128		},
9129
9130		generateThumbnails: function() {
9131			var iL = this,
9132				vars = iL.vars,
9133				opts = iL.options,
9134				timeOut = null;
9135
9136			if (vars.thumbs && !iL.vars.dontGenerateThumbs) {
9137				var thumbnails = vars.thumbnails,
9138					container = $('div.ilightbox-thumbnails-container', thumbnails),
9139					grid = $('div.ilightbox-thumbnails-grid', container),
9140					i = 0;
9141
9142				grid.removeAttr('style').empty();
9143
9144				$.each(iL.items, function(key, val) {
9145					var isActive = (vars.current == key) ? 'ilightbox-active' : '',
9146						opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity,
9147						thumb = val.options.thumbnail,
9148						thumbnail = $('<div class="ilightbox-thumbnail"></div>'),
9149						icon = $('<div class="ilightbox-thumbnail-icon"></div>');
9150
9151					thumbnail.css({
9152						opacity: 0
9153					}).addClass(isActive);
9154
9155					if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') {
9156						icon.addClass('ilightbox-thumbnail-video');
9157						thumbnail.append(icon);
9158					} else if (val.options.icon) {
9159						icon.addClass('ilightbox-thumbnail-' + val.options.icon);
9160						thumbnail.append(icon);
9161					}
9162
9163					if (thumb) iL.loadImage(thumb, function(img) {
9164						i++;
9165						if (img) thumbnail.data({
9166							naturalWidth: img.width,
9167							naturalHeight: img.height
9168						}).append('<img src="' + thumb + '" border="0" />');
9169						else thumbnail.data({
9170							naturalWidth: opts.thumbnails.maxWidth,
9171							naturalHeight: opts.thumbnails.maxHeight
9172						});
9173
9174						clearTimeout(timeOut);
9175						timeOut = setTimeout(function() {
9176							iL.positionThumbnails(thumbnails, container, grid);
9177						}, 20);
9178						setTimeout(function() {
9179							thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity);
9180						}, i * 20);
9181					});
9182
9183					grid.append(thumbnail);
9184				});
9185				iL.vars.dontGenerateThumbs = true;
9186			}
9187		},
9188
9189		positionThumbnails: function(thumbnails, container, grid) {
9190			var iL = this,
9191				vars = iL.vars,
9192				opts = iL.options,
9193				viewport = getViewport(),
9194				path = opts.path.toLowerCase();
9195
9196			if (!thumbnails) thumbnails = vars.thumbnails;
9197			if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails);
9198			if (!grid) grid = $('div.ilightbox-thumbnails-grid', container);
9199
9200			var thumbs = $('.ilightbox-thumbnail', grid),
9201				widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX,
9202				heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY,
9203				gridWidth = (path == 'horizontal') ? 0 : widthAvail,
9204				gridHeight = (path == 'horizontal') ? heightAvail : 0,
9205				active = $('.ilightbox-active', grid),
9206				gridCss = {},
9207				css = {};
9208
9209			if (arguments.length < 3) {
9210				thumbs.css({
9211					opacity: opts.thumbnails.normalOpacity
9212				});
9213				active.css({
9214					opacity: opts.thumbnails.activeOpacity
9215				});
9216			}
9217
9218			thumbs.each(function(i) {
9219				var t = $(this),
9220					data = t.data(),
9221					width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth;
9222				height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0;
9223				dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true);
9224
9225				t.css({
9226					width: dims.width,
9227					height: dims.height
9228				});
9229				if (path == 'horizontal') t.css({
9230					'float': 'left'
9231				});
9232
9233				(path == 'horizontal') ? (
9234					gridWidth += t.outerWidth()
9235				) : (
9236					gridHeight += t.outerHeight()
9237				);
9238			});
9239
9240			gridCss = {
9241				width: gridWidth,
9242				height: gridHeight
9243			};
9244
9245			grid.css(gridCss);
9246
9247			gridCss = {};
9248
9249			var gridOffset = grid.offset(),
9250				activeOffset = (active.length) ? active.offset() : {
9251					top: parseInt(heightAvail / 2),
9252					left: parseInt(widthAvail / 2)
9253				};
9254
9255			gridOffset.top = (gridOffset.top - $doc.scrollTop()),
9256				gridOffset.left = (gridOffset.left - $doc.scrollLeft()),
9257				activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()),
9258				activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft());
9259
9260			(path == 'horizontal') ? (
9261				gridCss.top = 0,
9262				gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2))
9263			) : (
9264				gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))),
9265				gridCss.left = 0
9266			);
9267
9268			if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc');
9269			else grid.css(gridCss);
9270		},
9271
9272		loadImage: function(image, callback) {
9273			if (!$.isArray(image)) image = [image];
9274
9275			var iL = this,
9276				length = image.length;
9277
9278			if (length > 0) {
9279				iL.showLoader();
9280				$.each(image, function(index, value) {
9281					var img = new Image();
9282					img.onload = function() {
9283						length -= 1;
9284						if (length == 0) {
9285							iL.hideLoader();
9286							callback(img);
9287						}
9288					};
9289					img.onerror = img.onabort = function() {
9290						length -= 1;
9291						if (length == 0) {
9292							iL.hideLoader();
9293							callback(false);
9294						}
9295					};
9296					img.src = image[index];
9297				});
9298			} else callback(false);
9299		},
9300
9301		patchItemsEvents: function() {
9302			var iL = this,
9303				vars = iL.vars,
9304				clickEvent = ishybrid ? "itap.iL click.iL" : supportTouch ? "itap.iL" : "click.iL",
9305				vEvent = ishybrid ? "click.iL itap.iL" : supportTouch ? "click.iL" : "itap.iL";
9306
9307			if (iL.context && iL.selector) {
9308				var $items = $(iL.selector, iL.context);
9309
9310				$(iL.context).on(clickEvent, iL.selector, function() {
9311					var $this = $(this),
9312						//UNCODE addition
9313						key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this);
9314					if (UNCODE.isMobile) {
9315						var isCarousel = $this.closest('.owl-carousel');
9316						if (isCarousel.length) {
9317							if (isCarousel.hasClass('owl-translating')) return false;
9318						}
9319					}
9320
9321					vars.current = key;
9322					vars.next = iL.items[key + 1] ? key + 1 : null;
9323					vars.prev = iL.items[key - 1] ? key - 1 : null;
9324
9325					//UNCODE addition
9326					if ( vars.BODY.hasClass('fp-slide-scrolling') )
9327						return false;
9328
9329					iL.addContents();
9330					iL.patchEvents();
9331
9332					return false;
9333				}).on(vEvent, iL.selector, function() {
9334					return false;
9335				});
9336			} else
9337				$.each(iL.itemsObject, function(key, val) {
9338					val.on(clickEvent, function() {
9339						vars.current = key;
9340						vars.next = iL.items[key + 1] ? key + 1 : null;
9341						vars.prev = iL.items[key - 1] ? key - 1 : null;
9342
9343						iL.addContents();
9344						iL.patchEvents();
9345
9346						return false;
9347					}).on(vEvent, function() {
9348						return false;
9349					});
9350				});
9351		},
9352
9353		dispatchItemsEvents: function() {
9354			var iL = this,
9355				vars = iL.vars,
9356				opts = iL.options;
9357
9358			if (iL.context && iL.selector)
9359				$(iL.context).off('.iL', iL.selector);
9360			else
9361				$.each(iL.itemsObject, function(key, val) {
9362					val.off('.iL');
9363				});
9364		},
9365
9366		refresh: function() {
9367			var iL = this;
9368
9369			iL.dispatchItemsEvents();
9370			iL.attachItems();
9371			iL.normalizeItems();
9372			iL.patchItemsEvents();
9373		},
9374
9375		patchEvents: function() {
9376			var iL = this,
9377				vars = iL.vars,
9378				opts = iL.options,
9379				path = opts.path.toLowerCase(),
9380				holders = $('.ilightbox-holder'),
9381				fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox',
9382				durationThreshold = 1000,
9383				horizontalDistanceThreshold =
9384				verticalDistanceThreshold = 100,
9385				buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild];
9386
9387			$win.bind('resize.iLightBox', function() {
9388				var viewport = getViewport();
9389
9390				if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth;
9391				vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
9392
9393				iL.repositionPhoto(null);
9394				if (supportTouch) {
9395					clearTimeout(vars.setTime);
9396					vars.setTime = setTimeout(function() {
9397						var scrollTop = getScrollXY().y;
9398						window.scrollTo(0, scrollTop - 30);
9399						window.scrollTo(0, scrollTop + 30);
9400						window.scrollTo(0, scrollTop);
9401					}, 2000);
9402				}
9403				if (vars.thumbs) iL.positionThumbnails();
9404			}).bind('keydown.iLightBox', function(event) {
9405				if (opts.controls.keyboard) {
9406					switch (event.keyCode) {
9407						case 13:
9408							if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction();
9409							break;
9410						case 27:
9411							if (opts.keyboard.esc) iL.closeAction();
9412							break;
9413						case 37:
9414							if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev');
9415							break;
9416						case 38:
9417							if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev');
9418							break;
9419						case 39:
9420							if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next');
9421							break;
9422						case 40:
9423							if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next');
9424							break;
9425					}
9426				}
9427			});
9428
9429			if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() {
9430				iL.doFullscreen();
9431			});
9432
9433			var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) {
9434					return arr.lastIndexOf(e) === i;
9435				}),
9436				holderEvents = "";
9437
9438			$.each(holderEventsArr, function(key, val) {
9439				if (key != 0) holderEvents += ' ';
9440				holderEvents += val;
9441			});
9442
9443			$doc.on(clickEvent, '.ilightbox-overlay', function() {
9444				if (opts.overlay.blur) iL.closeAction();
9445			}).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() {
9446				iL.moveTo('next');
9447			}).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() {
9448				iL.moveTo('prev');
9449			}).on(clickEvent, '.ilightbox-thumbnail', function() {
9450				var t = $(this),
9451					thumbs = $('.ilightbox-thumbnail', vars.thumbnails),
9452					index = thumbs.index(t);
9453
9454				if (index != vars.current) iL.goTo(index);
9455			}).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
9456				var caption = $('div.ilightbox-caption', vars.holder),
9457					social = $('div.ilightbox-social', vars.holder),
9458					fadeSpeed = opts.effects.fadeSpeed;
9459
9460				if (vars.nextLock || vars.prevLock) {
9461					if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed);
9462					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed);
9463
9464					if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed);
9465					else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed);
9466				} else {
9467					if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed);
9468					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed);
9469
9470					if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed);
9471					else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed);
9472				}
9473			}).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) {
9474				if (e.type == 'mouseenter') vars.lockWheel = true;
9475				else vars.lockWheel = false;
9476			}).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() {
9477				var t = $(this);
9478
9479				if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction();
9480				else if (t.hasClass('ilightbox-play')) {
9481					iL.resume();
9482					t.addClass('ilightbox-pause').removeClass('ilightbox-play');
9483				} else if (t.hasClass('ilightbox-pause')) {
9484					iL.pause();
9485					t.addClass('ilightbox-play').removeClass('ilightbox-pause');
9486				} else iL.closeAction();
9487			}).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) {
9488				// prevent scrolling
9489				e.preventDefault();
9490			});
9491
9492			function mouseMoveHandler(e) {
9493				if (!vars.isMobile) {
9494					if (!vars.mouseID) {
9495						vars.hideableElements.show();
9496					}
9497
9498					vars.mouseID = clearTimeout(vars.mouseID);
9499
9500					if (buttonsArray.indexOf(e.target) === -1)
9501						vars.mouseID = setTimeout(function() {
9502							vars.hideableElements.hide();
9503							vars.mouseID = clearTimeout(vars.mouseID);
9504						}, 3000);
9505				}
9506			}
9507
9508			if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler);
9509
9510			if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
9511				if (e.type == 'mouseenter' && vars.cycleID) iL.pause();
9512				else if (e.type == 'mouseleave' && vars.isPaused) iL.resume();
9513			});
9514
9515			var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'),
9516				delay = false;
9517
9518			if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) {
9519				event.preventDefault();
9520				if (delay) return;
9521				delay = true;
9522				if (!vars.lockWheel) {
9523					event.preventDefault();
9524					if (delta < 0) {
9525						iL.moveTo('next');
9526					} else if (delta > 0) {
9527						iL.moveTo('prev');
9528					}
9529				}
9530				setTimeout(function(){
9531					delay = false;
9532				}, 2000);
9533			});
9534
9535			if (opts.controls.swipe) holders.on(touchStartEvent, function(event) {
9536				if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return;
9537
9538				vars.BODY.addClass('ilightbox-closedhand');
9539
9540				var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event,
9541					scrollTop = $doc.scrollTop(),
9542					scrollLeft = $doc.scrollLeft(),
9543					offsets = [
9544						holders.eq(0).offset(),
9545						holders.eq(1).offset(),
9546						holders.eq(2).offset()
9547					],
9548					offSet = [{
9549						top: offsets[0].top - scrollTop,
9550						left: offsets[0].left - scrollLeft
9551					}, {
9552						top: offsets[1].top - scrollTop,
9553						left: offsets[1].left - scrollLeft
9554					}, {
9555						top: offsets[2].top - scrollTop,
9556						left: offsets[2].left - scrollLeft
9557					}],
9558					start = {
9559						time: (new Date()).getTime(),
9560						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
9561					},
9562					stop;
9563
9564				function moveEachHandler(i) {
9565					var t = $(this),
9566						offset = offSet[i],
9567						scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])];
9568
9569					t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px';
9570				}
9571
9572				function moveHandler(event) {
9573
9574					if (!start) return;
9575
9576					var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event;
9577
9578					stop = {
9579						time: (new Date()).getTime(),
9580						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
9581					};
9582
9583					holders.each(moveEachHandler);
9584
9585					// prevent scrolling
9586					event.preventDefault();
9587				}
9588
9589				function repositionHolders() {
9590					holders.each(function() {
9591						var t = $(this),
9592							offset = t.data('offset') || {
9593								top: t.offset().top - scrollTop,
9594								left: t.offset().left - scrollLeft
9595							},
9596							top = offset.top,
9597							left = offset.left;
9598
9599						t.css(transform, gpuAcceleration).stop().animate({
9600							top: top,
9601							left: left
9602						}, 500, 'easeOutCirc', function() {
9603							t.css(transform, '');
9604						});
9605					});
9606				}
9607
9608				holders.bind(touchMoveEvent, moveHandler);
9609				$doc.one(touchStopEvent, function(event) {
9610					holders.unbind(touchMoveEvent, moveHandler);
9611
9612					vars.BODY.removeClass('ilightbox-closedhand');
9613
9614					if (start && stop) {
9615						if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) {
9616							if (start.coords[0] > stop.coords[0]) {
9617								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
9618								else {
9619									vars.isSwipe = true;
9620									iL.moveTo('next');
9621								}
9622							} else {
9623								if (vars.current == 0 && !opts.infinite) repositionHolders();
9624								else {
9625									vars.isSwipe = true;
9626									iL.moveTo('prev');
9627								}
9628							}
9629						} else if (path == "vertical" && stop.time - start.time < durationThreshold && abs(start.coords[1] - stop.coords[1]) > horizontalDistanceThreshold && abs(start.coords[0] - stop.coords[0]) < verticalDistanceThreshold) {
9630							if (start.coords[1] > stop.coords[1]) {
9631								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
9632								else {
9633									vars.isSwipe = true;
9634									iL.moveTo('next');
9635								}
9636							} else {
9637								if (vars.current == 0 && !opts.infinite) repositionHolders();
9638								else {
9639									vars.isSwipe = true;
9640									iL.moveTo('prev');
9641								}
9642							}
9643						} else repositionHolders();
9644					}
9645					start = stop = undefined;
9646				});
9647			});
9648
9649		},
9650
9651		goTo: function(index) {
9652			var iL = this,
9653				vars = iL.vars,
9654				opts = iL.options,
9655				diff = (index - vars.current);
9656
9657			if (opts.infinite) {
9658				if (index == vars.total - 1 && vars.current == 0) diff = -1;
9659				if (vars.current == vars.total - 1 && index == 0) diff = 1;
9660			}
9661
9662			if (diff == 1) iL.moveTo('next');
9663			else if (diff == -1) iL.moveTo('prev');
9664			else {
9665
9666				if (vars.nextLock || vars.prevLock) return false;
9667
9668				//Trigger the onBeforeChange callback
9669				if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui);
9670
9671				if (opts.linkId) {
9672					vars.hashLock = true;
9673					window.location.hash = opts.linkId + '/' + index;
9674				}
9675
9676				if (iL.items[index]) {
9677					if (!iL.items[index].options.mousewheel) vars.lockWheel = true;
9678					else iL.vars.lockWheel = false;
9679
9680					if (!iL.items[index].options.swipe) vars.lockSwipe = true;
9681					else vars.lockSwipe = false;
9682				}
9683
9684				$.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) {
9685					val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed);
9686				});
9687
9688				vars.current = index;
9689				vars.next = index + 1;
9690				vars.prev = index - 1;
9691
9692				iL.createUI();
9693
9694				setTimeout(function() {
9695					iL.generateBoxes();
9696				}, opts.effects.loadedFadeSpeed + 50);
9697
9698				$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active');
9699				iL.positionThumbnails();
9700
9701				if (opts.linkId) setTimeout(function() {
9702					vars.hashLock = false;
9703				}, 55);
9704
9705				// Configure arrow buttons
9706				if (!opts.infinite) {
9707					vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
9708
9709					if (vars.current == 0) {
9710						vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
9711					}
9712					if (vars.current >= vars.total - 1) {
9713						vars.nextButton.add(vars.innerNextButton).addClass('disabled');
9714					}
9715				}
9716
9717				// Reset next cycle timeout
9718				iL.resetCycle();
9719
9720				//Trigger the onAfterChange callback
9721				if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui);
9722			}
9723		},
9724
9725		moveTo: function(side) {
9726			var iL = this,
9727				vars = iL.vars,
9728				opts = iL.options,
9729				path = opts.path.toLowerCase(),
9730				viewport = getViewport(),
9731				switchSpeed = opts.effects.switchSpeed;
9732
9733			if (vars.nextLock || vars.prevLock) return false;
9734			else {
9735
9736				var item = (side == "next") ? vars.next : vars.prev;
9737
9738				if (opts.linkId) {
9739					vars.hashLock = true;
9740					window.location.hash = opts.linkId + '/' + item;
9741				}
9742
9743				if (side == "next") {
9744					if (!iL.items[item]) return false;
9745					var firstHolder = vars.nextPhoto,
9746						secondHolder = vars.holder,
9747						lastHolder = vars.prevPhoto,
9748						firstClass = 'ilightbox-prev',
9749						secondClass = 'ilightbox-next';
9750				} else if (side == "prev") {
9751					if (!iL.items[item]) return false;
9752					var firstHolder = vars.prevPhoto,
9753						secondHolder = vars.holder,
9754						lastHolder = vars.nextPhoto,
9755						firstClass = 'ilightbox-next',
9756						secondClass = 'ilightbox-prev';
9757				}
9758
9759				//Trigger the onBeforeChange callback
9760				if (typeof opts.callback.onBeforeChange == 'function')
9761					opts.callback.onBeforeChange.call(iL, iL.ui);
9762
9763				(side == "next") ? vars.nextLock = true: vars.prevLock = true;
9764
9765				var captionFirst = $('div.ilightbox-caption', secondHolder),
9766					socialFirst = $('div.ilightbox-social', secondHolder);
9767
9768				if (captionFirst.length)
9769					captionFirst.stop().fadeOut(switchSpeed, function() {
9770						$(this).remove();
9771					});
9772				if (socialFirst.length)
9773					socialFirst.stop().fadeOut(switchSpeed, function() {
9774						$(this).remove();
9775					});
9776
9777				if (iL.items[item].caption) {
9778					iL.setCaption(iL.items[item], firstHolder);
9779					var caption = $('div.ilightbox-caption', firstHolder),
9780						percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100);
9781					if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed);
9782				}
9783
9784				var social = iL.items[item].options.social;
9785				if (social) {
9786					iL.setSocial(social, iL.items[item].URL, firstHolder);
9787					if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed);
9788				}
9789
9790				$.each([firstHolder, secondHolder, lastHolder], function(key, val) {
9791					val.removeClass('ilightbox-next ilightbox-prev');
9792				});
9793
9794				var firstOffset = firstHolder.data('offset'),
9795					winW = (viewport.width - (opts.styles.pageOffsetX)),
9796					winH = (viewport.height - (opts.styles.pageOffsetY)),
9797					width = firstOffset.newDims.width,
9798					height = firstOffset.newDims.height,
9799					thumbsOffset = firstOffset.thumbsOffset,
9800					diff = firstOffset.diff,
9801					top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)),
9802					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
9803
9804				var secondOffset = secondHolder.data('offset'),
9805					object = secondOffset.object;
9806
9807				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
9808					var objRatio = width / height;
9809					height = height - vars.captionHeight;
9810					width = height * objRatio;
9811					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top,
9812					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
9813				}*/
9814
9815				firstHolder.show().css(transform, gpuAcceleration).animate({
9816					top: top,
9817					left: left,
9818					opacity: 1
9819				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
9820					firstHolder.css(transform, '');
9821				});
9822
9823				$('div.ilightbox-container', firstHolder).animate({
9824					width: width,
9825					height: height
9826				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
9827
9828				diff = secondOffset.diff;
9829
9830				width = secondOffset.newDims.width,
9831					height = secondOffset.newDims.height;
9832
9833				width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
9834					height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
9835					top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2));
9836
9837				if (side == 'prev')
9838					left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2));
9839				else {
9840					top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)),
9841					left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2));
9842				}
9843
9844				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
9845					var objRatio = width / height;
9846					height = height - vars.captionHeight;
9847					width = height * objRatio;
9848					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top;
9849				}*/
9850
9851				$('div.ilightbox-container', secondHolder).animate({
9852					width: width,
9853					height: height
9854				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
9855
9856				secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({
9857					top: top,
9858					left: left,
9859					opacity: opts.styles.prevOpacity,
9860				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
9861					secondHolder.css(transform, '');
9862
9863					$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active');
9864					iL.positionThumbnails();
9865
9866					if (iL.items[item]) {
9867						if (!iL.items[item].options.mousewheel) vars.lockWheel = true;
9868						else vars.lockWheel = false;
9869
9870						if (!iL.items[item].options.swipe) vars.lockSwipe = true;
9871						else vars.lockSwipe = false;
9872					}
9873
9874					vars.isSwipe = false;
9875
9876					// Remove iframe & video from previous slide
9877					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
9878						$('div.ilightbox-container', secondHolder).empty();
9879					}
9880
9881					if (side == "next") {
9882						vars.nextPhoto = lastHolder,
9883							vars.prevPhoto = secondHolder,
9884							vars.holder = firstHolder;
9885
9886						vars.nextPhoto.hide();
9887
9888						vars.next = vars.next + 1,
9889							vars.prev = vars.current,
9890							vars.current = vars.current + 1;
9891
9892						if (opts.infinite) {
9893							if (vars.current > vars.total - 1) vars.current = 0;
9894							if (vars.current == vars.total - 1) vars.next = 0;
9895							if (vars.current == 0) vars.prev = vars.total - 1;
9896						}
9897
9898						iL.createUI();
9899
9900						if (!iL.items[vars.next])
9901							vars.nextLock = false;
9902						else
9903							iL.loadContent(iL.items[vars.next], 'next');
9904					} else {
9905						vars.prevPhoto = lastHolder;
9906						vars.nextPhoto = secondHolder;
9907						vars.holder = firstHolder;
9908
9909						vars.prevPhoto.hide();
9910
9911						vars.next = vars.current;
9912						vars.current = vars.prev;
9913						vars.prev = vars.current - 1;
9914
9915						if (opts.infinite) {
9916							if (vars.current == vars.total - 1) vars.next = 0;
9917							if (vars.current == 0) vars.prev = vars.total - 1;
9918						}
9919
9920						iL.createUI();
9921
9922						if (!iL.items[vars.prev])
9923							vars.prevLock = false;
9924						else
9925							iL.loadContent(iL.items[vars.prev], 'prev');
9926					}
9927
9928					// Add iframe & video content for current slide
9929					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
9930						iL.loadContent(iL.items[vars.current], 'current');
9931					}
9932
9933					if (opts.linkId) setTimeout(function() {
9934						vars.hashLock = false;
9935					}, 55);
9936
9937					// Configure arrow buttons
9938					if (!opts.infinite) {
9939						vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
9940
9941						if (vars.current == 0)
9942							vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
9943						if (vars.current >= vars.total - 1)
9944							vars.nextButton.add(vars.innerNextButton).addClass('disabled');
9945					}
9946
9947					iL.repositionPhoto();
9948
9949					// Reset next cycle timeout
9950					iL.resetCycle();
9951
9952					//Trigger the onAfterChange callback
9953					if (typeof opts.callback.onAfterChange == 'function')
9954						opts.callback.onAfterChange.call(iL, iL.ui);
9955				});
9956
9957				top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)),
9958					left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left');
9959
9960				lastHolder.css(transform, gpuAcceleration).animate({
9961					top: top,
9962					left: left,
9963					opacity: opts.styles.nextOpacity
9964				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
9965					lastHolder.css(transform, '');
9966				}).addClass(secondClass);
9967			}
9968		},
9969
9970		setCaption: function(obj, target) {
9971			var iL = this,
9972				caption = $('<div class="ilightbox-caption"></div>');
9973
9974			if (obj.caption) {
9975				caption.html(obj.caption);
9976				$('div.ilightbox-container', target).append(caption);
9977			}
9978		},
9979
9980		normalizeSocial: function(obj, url) {
9981			var iL = this,
9982				vars = iL.vars,
9983				opts = iL.options,
9984				baseURL = window.location.href;
9985
9986			$.each(obj, function(key, value) {
9987				if (!value)
9988					return true;
9989
9990				var item = key.toLowerCase(),
9991					source, text;
9992
9993				switch (item) {
9994					case 'facebook':
9995						source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}",
9996							text = "Share on Facebook";
9997						break;
9998					case 'twitter':
9999						source = "http://twitter.com/home?status={URL}",
10000							text = "Share on Twitter";
10001						break;
10002					case 'googleplus':
10003						source = "https://plus.google.com/share?url={URL}",
10004							text = "Share on Google+";
10005						break;
10006					case 'delicious':
10007						source = "http://delicious.com/post?url={URL}",
10008							text = "Share on Delicious";
10009						break;
10010					case 'digg':
10011						source = "http://digg.com/submit?phase=2&url={URL}",
10012							text = "Share on Digg";
10013						break;
10014					case 'reddit':
10015						source = "http://reddit.com/submit?url={URL}",
10016							text = "Share on reddit";
10017						break;
10018				}
10019
10020				obj[key] = {
10021					URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL,
10022					source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url),
10023					text: value.text || text || "Share on " + key,
10024					width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640,
10025					height: value.height || 360
10026				};
10027
10028			});
10029
10030			return obj;
10031		},
10032
10033		setSocial: function(obj, url, target) {
10034			var iL = this,
10035				socialBar = $('<div class="ilightbox-social"></div>'),
10036				buttons = '<ul>';
10037
10038			obj = iL.normalizeSocial(obj, url);
10039
10040			$.each(obj, function(key, value) {
10041				var item = key.toLowerCase(),
10042					source = value.source.replace(/\{URL\}/g, encodeURIComponent(value.URL).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+'));
10043				buttons += '<li class="' + key + '"><a href="' + source + '" onclick="javascript:window.open(this.href' + ((value.width <= 0 || value.height <= 0) ? '' : ', \'\', \'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=' + value.height + ',width=' + value.width + ',left=40,top=40\'') + ');return false;" title="' + value.text + '" target="_blank"></a></li>';
10044			});
10045
10046			buttons += '</ul>';
10047
10048			socialBar.html(buttons);
10049			$('div.ilightbox-container', target).append(socialBar);
10050		},
10051
10052		fullScreenAction: function() {
10053			var iL = this,
10054				vars = iL.vars;
10055
10056			if (fullScreenApi.supportsFullScreen) {
10057				if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement);
10058				else fullScreenApi.requestFullScreen(document.documentElement);
10059			} else {
10060				iL.doFullscreen();
10061			}
10062		},
10063
10064		doFullscreen: function() {
10065			var iL = this,
10066				vars = iL.vars,
10067				viewport = getViewport(),
10068				opts = iL.options;
10069
10070			if (opts.fullAlone) {
10071				var currentHolder = vars.holder,
10072					current = iL.items[vars.current],
10073					windowWidth = viewport.width,
10074					windowHeight = viewport.height,
10075					elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader],
10076					hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
10077
10078				if (!vars.isInFullScreen) {
10079					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true;
10080					vars.overlay.css({
10081						opacity: 1
10082					});
10083
10084					$.each(hideElements, function(i, element) {
10085						element.hide();
10086					});
10087
10088					vars.fullScreenButton.attr('title', opts.text.exitFullscreen);
10089
10090					if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
10091						naturalWidthOld: currentHolder.data('naturalWidth'),
10092						naturalHeightOld: currentHolder.data('naturalHeight'),
10093						naturalWidth: windowWidth,
10094						naturalHeight: windowHeight
10095					});
10096					else {
10097						var viewport = current.options.fullViewPort || opts.fullViewPort || '',
10098							newWidth = windowWidth,
10099							newHeight = windowHeight,
10100							width = currentHolder.data('naturalWidth'),
10101							height = currentHolder.data('naturalHeight');
10102
10103						if (viewport.toLowerCase() == 'fill') {
10104							newHeight = (newWidth / width) * height;
10105
10106							if (newHeight < windowHeight) {
10107								newWidth = (windowHeight / height) * width,
10108									newHeight = windowHeight;
10109							}
10110						} else if (viewport.toLowerCase() == 'fit') {
10111							var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true);
10112
10113							newWidth = dims.width,
10114								newHeight = dims.height;
10115						} else if (viewport.toLowerCase() == 'stretch') {
10116							newWidth = newWidth,
10117								newHeight = newHeight;
10118						} else {
10119							var scale = (width > newWidth || height > newHeight) ? true : false,
10120								dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale);
10121							newWidth = dims.width,
10122								newHeight = dims.height;
10123						}
10124
10125						currentHolder.data({
10126							naturalWidthOld: currentHolder.data('naturalWidth'),
10127							naturalHeightOld: currentHolder.data('naturalHeight'),
10128							naturalWidth: newWidth,
10129							naturalHeight: newHeight
10130						});
10131					}
10132
10133					$.each(elements, function(key, val) {
10134						val.addClass('ilightbox-fullscreen');
10135					});
10136
10137					//Trigger the onEnterFullScreen callback
10138					if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui);
10139				} else {
10140					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false;
10141					vars.overlay.css({
10142						opacity: iL.options.overlay.opacity
10143					});
10144
10145					$.each(hideElements, function(i, element) {
10146						element.show();
10147					});
10148
10149					vars.fullScreenButton.attr('title', opts.text.enterFullscreen);
10150
10151					currentHolder.data({
10152						naturalWidth: currentHolder.data('naturalWidthOld'),
10153						naturalHeight: currentHolder.data('naturalHeightOld'),
10154						naturalWidthOld: null,
10155						naturalHeightOld: null
10156					});
10157
10158					$.each(elements, function(key, val) {
10159						val.removeClass('ilightbox-fullscreen');
10160					});
10161
10162					//Trigger the onExitFullScreen callback
10163					if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui);
10164				}
10165			} else {
10166				if (!vars.isInFullScreen) vars.isInFullScreen = true;
10167				else vars.isInFullScreen = false;
10168			}
10169			iL.repositionPhoto(true);
10170		},
10171
10172		closeAction: function() {
10173			var iL = this,
10174				vars = iL.vars,
10175				opts = iL.options;
10176
10177			$win.unbind('.iLightBox');
10178			$doc.off('.iLightBox');
10179
10180			if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement);
10181
10182			$('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox');
10183
10184			if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() {
10185				vars.overlay.remove();
10186				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
10187			});
10188			else {
10189				vars.overlay.remove();
10190				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
10191			}
10192
10193			var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
10194
10195			$.each(fadeOuts, function(i, element) {
10196				element.removeAttr('style').remove();
10197			});
10198
10199			vars.dontGenerateThumbs = vars.isInFullScreen = false;
10200
10201			window.iLightBox = null;
10202
10203			if (opts.linkId) {
10204				vars.hashLock = true;
10205				removeHash();
10206				setTimeout(function() {
10207					vars.hashLock = false;
10208				}, 55);
10209			}
10210
10211			vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
10212
10213			//Trigger the onHide callback
10214			if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui);
10215		},
10216
10217		repositionPhoto: function() {
10218			var iL = this,
10219				vars = iL.vars,
10220				opts = iL.options,
10221				path = opts.path.toLowerCase(),
10222				viewport = getViewport(),
10223				winWidth = viewport.width,
10224				winHeight = viewport.height;
10225
10226			if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0;
10227
10228			var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()),
10229				thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)),
10230				width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)),
10231				height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)),
10232				offsetW = (path == 'horizontal') ? parseInt((iL.items[vars.next] || iL.items[vars.prev]) ? ((opts.styles.nextOffsetX + opts.styles.prevOffsetX)) * 2 : (((width / 10) <= 30) ? 30 : (width / 10))) : parseInt(((width / 10) <= 30) ? 30 : (width / 10)) + thumbsOffsetW,
10233				offsetH = (path == 'horizontal') ? parseInt(((height / 10) <= 30) ? 30 : (height / 10)) + thumbsOffsetH : parseInt((iL.items[vars.next] || iL.items[vars.prev]) ? ((opts.styles.nextOffsetX + opts.styles.prevOffsetX)) * 2 : (((height / 10) <= 30) ? 30 : (height / 10)));
10234
10235			var elObject = {
10236				type: 'current',
10237				width: width,
10238				height: height,
10239				item: iL.items[vars.current],
10240				offsetW: offsetW,
10241				offsetH: offsetH,
10242				thumbsOffsetW: thumbsOffsetW,
10243				thumbsOffsetH: thumbsOffsetH,
10244				animate: arguments.length,
10245				holder: vars.holder
10246			};
10247
10248			iL.repositionEl(elObject);
10249
10250			if (iL.items[vars.next]) {
10251				elObject = $.extend(elObject, {
10252					type: 'next',
10253					item: iL.items[vars.next],
10254					offsetX: opts.styles.nextOffsetX,
10255					offsetY: opts.styles.nextOffsetY,
10256					holder: vars.nextPhoto
10257				});
10258
10259				iL.repositionEl(elObject);
10260			}
10261
10262			if (iL.items[vars.prev]) {
10263				elObject = $.extend(elObject, {
10264					type: 'prev',
10265					item: iL.items[vars.prev],
10266					offsetX: opts.styles.nextOffsetX,
10267					offsetY: opts.styles.prevOffsetY,
10268					holder: vars.prevPhoto
10269				});
10270
10271				iL.repositionEl(elObject);
10272			}
10273
10274			var loaderCss = (path == "horizontal") ? {
10275				left: parseInt((width / 2) - (vars.loader.outerWidth() / 2))
10276			} : {
10277				top: parseInt((height / 2) - (vars.loader.outerHeight() / 2))
10278			};
10279			vars.loader.css(loaderCss);
10280		},
10281
10282		repositionEl: function(obj) {
10283			var iL = this,
10284				vars = iL.vars,
10285				opts = iL.options,
10286				path = opts.path.toLowerCase(),
10287				widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW),
10288				heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH),
10289				itemParent = obj.item,
10290				item = obj.item.options,
10291				holder = obj.holder,
10292				offsetX = obj.offsetX || 0,
10293				offsetY = obj.offsetY || 0,
10294				//Uncode change ##START##
10295				toolbarHeight = $('.ilightbox-inner-toolbar', holder).length ? parseInt( $('.ilightbox-inner-toolbar', holder).outerHeight() ) : 0,
10296				//Uncode change ##END##
10297				thumbsOffsetW = obj.thumbsOffsetW,
10298				thumbsOffsetH = obj.thumbsOffsetH;
10299
10300			if (obj.type == 'current') {
10301				if (typeof item.width == 'number' && item.width) widthAvail = ((vars.isInFullScreen && opts.fullAlone) && (opts.fullStretchTypes.indexOf(itemParent.type) != -1 || item.fullViewPort || opts.fullViewPort)) ? widthAvail : ((item.width > widthAvail) ? widthAvail : item.width);
10302				if (typeof item.height == 'number' && item.height) heightAvail = ((vars.isInFullScreen && opts.fullAlone) && (opts.fullStretchTypes.indexOf(itemParent.type) != -1 || item.fullViewPort || opts.fullViewPort)) ? heightAvail : ((item.height > heightAvail) ? heightAvail : item.height);
10303			} else {
10304				if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width;
10305				if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height;
10306			}
10307
10308
10309			//Uncode change ##START##
10310			heightAvail = parseInt(heightAvail - toolbarHeight);
10311			// heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight());
10312			//Uncode change ##END##
10313
10314			var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'),
10315				height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight');
10316
10317			var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? {
10318					width: width,
10319					height: height
10320				} : iL.getNewDimenstions(widthAvail, heightAvail, width, height)),
10321				newDims = $.extend({}, dims, {});
10322
10323			if (obj.type == 'prev' || obj.type == 'next')
10324				width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)),
10325				height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale));
10326			else
10327				width = dims.width,
10328				height = dims.height;
10329
10330			var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2),
10331				heightDiff = parseInt((getPixel(holder, 'padding-top') + getPixel(holder, 'padding-bottom') + getPixel(holder, 'border-top-width') + getPixel(holder, 'border-bottom-width') + ($('.ilightbox-inner-toolbar', holder).outerHeight() || 0)) / 2);
10332
10333			switch (obj.type) {
10334				case 'current':
10335					var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)),
10336						left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2));
10337					break;
10338
10339				case 'next':
10340					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)),
10341						left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2));
10342					break;
10343
10344				case 'prev':
10345					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)),
10346						left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2));
10347					break;
10348			}
10349
10350			holder.data('offset', {
10351				top: top,
10352				left: left,
10353				newDims: newDims,
10354				diff: {
10355					W: widthDiff,
10356					H: heightDiff
10357				},
10358				thumbsOffset: {
10359					W: thumbsOffsetW,
10360					H: thumbsOffsetH
10361				},
10362				object: obj
10363			});
10364
10365			var opacityMobile;
10366			if ( isMobile ) {
10367				opacityMobile = {
10368					opacity: 1,
10369					top: top,
10370					left: left
10371				};
10372			} else {
10373				opacityMobile = {
10374					top: top,
10375					left: left
10376				};
10377			}
10378
10379			if (obj.animate > 0 && opts.effects.reposition) {
10380				holder.css(transform, gpuAcceleration).stop().animate(
10381					opacityMobile,
10382					opts.effects.repositionSpeed, 'easeOutCirc', function() {
10383					holder.css(transform, '');
10384				});
10385				$('div.ilightbox-container', holder).stop().animate({
10386					width: width,
10387					height: height
10388				}, opts.effects.repositionSpeed, 'easeOutCirc');
10389				$('div.ilightbox-inner-toolbar', holder).stop().animate({
10390					width: width
10391				}, opts.effects.repositionSpeed, 'easeOutCirc', function() {
10392					$(this).css('overflow', 'visible');
10393				});
10394			} else {
10395				holder.css(opacityMobile);
10396				$('div.ilightbox-container', holder).css({
10397					width: width,
10398					height: height
10399				});
10400				$('div.ilightbox-inner-toolbar', holder).css({
10401					width: width
10402				});
10403			}
10404		},
10405
10406
10407		resume: function(priority) {
10408			var iL = this,
10409				vars = iL.vars,
10410				opts = iL.options;
10411
10412			if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) {
10413				return;
10414			}
10415
10416			vars.isPaused = 0;
10417
10418			if (vars.cycleID) {
10419				vars.cycleID = clearTimeout(vars.cycleID);
10420			}
10421
10422			vars.cycleID = setTimeout(function() {
10423				if (vars.current == vars.total - 1) iL.goTo(0);
10424				else iL.moveTo('next');
10425			}, opts.slideshow.pauseTime);
10426		},
10427
10428		pause: function(priority) {
10429			var iL = this,
10430				vars = iL.vars,
10431				opts = iL.options;
10432
10433			if (priority < vars.isPaused) {
10434				return;
10435			}
10436
10437			vars.isPaused = priority || 100;
10438
10439			if (vars.cycleID) {
10440				vars.cycleID = clearTimeout(vars.cycleID);
10441			}
10442		},
10443
10444		resetCycle: function() {
10445			var iL = this,
10446				vars = iL.vars,
10447				opts = iL.options;
10448
10449			if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) {
10450				iL.resume();
10451			}
10452		},
10453
10454		getNewDimenstions: function(width, height, width_old, height_old, thumb) {
10455			var iL = this;
10456
10457			if (!width) factor = height / height_old;
10458			else if (!height) factor = width / width_old;
10459			else factor = min(width / width_old, height / height_old);
10460
10461			if (!thumb) {
10462				if (factor > iL.options.maxScale) factor = iL.options.maxScale;
10463				else if (factor < iL.options.minScale) factor = iL.options.minScale;
10464			}
10465
10466			var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width,
10467				final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height;
10468
10469			return {
10470				width: final_width,
10471				height: final_height,
10472				ratio: factor
10473			};
10474		},
10475
10476		setOption: function(options) {
10477			var iL = this;
10478
10479			iL.options = $.extend(true, iL.options, options || {});
10480			iL.refresh();
10481		},
10482
10483		availPlugins: function() {
10484			var iL = this,
10485				testEl = document.createElement("video");
10486
10487			iL.plugins = {
10488				flash: !isMobile,
10489				quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false,
10490				html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')),
10491				html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')),
10492				html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')),
10493				html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, ''))
10494			};
10495		},
10496
10497		addContent: function(element, obj) {
10498			var iL = this,
10499				el;
10500
10501			switch (obj.type) {
10502				case 'video':
10503					var HTML5 = false,
10504						videoType = obj.videoType,
10505						html5video = obj.options.html5video;
10506
10507					if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264)
10508						obj.ext = 'mp4',
10509						obj.URL = html5video.h264 || obj.URL;
10510					else if (html5video.webm && iL.plugins.html5WebM)
10511						obj.ext = 'webm',
10512						obj.URL = html5video.webm || obj.URL;
10513					else if (html5video.ogg && iL.plugins.html5Vorbis)
10514						obj.ext = 'ogv',
10515						obj.URL = html5video.ogg || obj.URL;
10516
10517					if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4";
10518					else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm";
10519					else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg";
10520					else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime";
10521
10522					if (HTML5) {
10523						el = $('<video />
10523', {
10524							"width": "100%",
10525							"height": "100%",
10526							"preload": html5video.preload,
10527							"autoplay": html5video.autoplay,
10528							"loop": html5video.loop,
10529							"poster": html5video.poster,
10530							"controls": html5video.controls,
10531							"controlslist": "nodownload"
10532						}).append($('<source />', {
10533							"src": obj.URL,
10534							"type": videoType
10535						}));
10536					} else {
10537						if (!iL.plugins.quicktime) el = $('<span />', {
10538							"class": "ilightbox-alert",
10539							html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime')
10540						});
10541						else {
10542
10543							el = $('<object />', {
10544								"type": "video/quicktime",
10545								"pluginspage": pluginspages.quicktime
10546							}).attr({
10547								"data": obj.URL,
10548								"width": "100%",
10549								"height": "100%"
10550							}).append($('<param />', {
10551								"name": "src",
10552								"value": obj.URL
10553							})).append($('<param />', {
10554								"name": "autoplay",
10555								"value": "false"
10556							})).append($('<param />', {
10557								"name": "loop",
10558								"value": "false"
10559							})).append($('<param />', {
10560								"name": "scale",
10561								"value": "tofit"
10562							}));
10563
10564							if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false');
10565						}
10566					}
10567
10568					break;
10569
10570				case 'flash':
10571					if (!iL.plugins.flash) el = $('<span />', {
10572						"class": "ilightbox-alert",
10573						html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player')
10574					});
10575					else {
10576						var flashvars = "",
10577							i = 0;
10578
10579						if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) {
10580							if (i != 0) flashvars += "&";
10581							flashvars += k + "=" + encodeURIComponent(v);
10582							i++;
10583						});
10584						else flashvars = null;
10585
10586						el = $('<embed />').attr({
10587							"type": "application/x-shockwave-flash",
10588							"src": obj.URL,
10589							"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
10590							"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
10591							"quality": "high",
10592							"bgcolor": "#000000",
10593							"play": "true",
10594							"loop": "true",
10595							"menu": "true",
10596							"wmode": "transparent",
10597							"scale": "showall",
10598							"allowScriptAccess": "always",
10599							"allowFullScreen": "true",
10600							"flashvars": flashvars,
10601							"fullscreen": "yes"
10602						});
10603					}
10604
10605					break;
10606
10607				case 'iframe':
10608					el = $('<iframe />').attr({
10609						"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
10610						"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
10611						src: obj.URL,
10612						frameborder: 0,
10613						'hspace': 0,
10614						'vspace': 0,
10615						'scrolling': supportTouch ? 'auto' : 'scroll',
10616						'webkitAllowFullScreen': '',
10617						'mozallowfullscreen': '',
10618						'allowFullScreen': ''
10619					});
10620
10621					break;
10622
10623				case 'inline':
10624					el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true));
10625
10626					break;
10627
10628				case 'html':
10629					var object = obj.URL,
10630						el;
10631
10632					if (object[0].nodeName) {
10633						el = $('<div class="ilightbox-wrapper"></div>').html(object);
10634					} else {
10635						var dom = $(obj.URL),
10636							html = (dom.selector) ? $('<div>' + dom + '</div>') : dom;
10637						el = $('<div class="ilightbox-wrapper"></div>').html(html);
10638					}
10639
10640					break;
10641			}
10642
10643			$('div.ilightbox-container', element).empty().html(el);
10644
10645			// For fixing Chrome about just playing the video for first time
10646			if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() {
10647				var src = el[0].currentSrc + '?' + floor(random() * 30000);
10648				el[0].currentSrc = src;
10649				el[0].src = src;
10650			});
10651
10652			return el;
10653		},
10654
10655		ogpRecognition: function(obj, callback) {
10656			var iL = this,
10657				url = obj.URL;
10658
10659			iL.showLoader();
10660			doAjax(url, function(data) {
10661				iL.hideLoader();
10662				if (data) {
10663					var object = new Object();
10664
10665					object.length = false,
10666					object.url = data.url;
10667
10668					if (data.status == 200) {
10669						var result = data.results,
10670							type = result.type,
10671							source = result.source;
10672
10673						object.source = source.src,
10674						object.width = source.width && parseInt(source.width) || 0,
10675						object.height = source.height && parseInt(source.height) || 0,
10676						object.type = type,
10677						object.thumbnail = source.thumbnail || result.images && result.images[0],
10678						object.html5video = result.html5video || {},
10679						object.length = true;
10680
10681						if (source.type == 'application/x-shockwave-flash') object.type = "flash";
10682						else if (source.type.indexOf("video/") != -1) object.type = "video";
10683						else if (source.type.indexOf("/html") != -1) object.type = "iframe";
10684						else if (source.type.indexOf("image/") != -1) object.type = "image";
10685
10686					} else if (typeof data.response != 'undefined')
10687						throw data.response;
10688
10689					callback.call(this, object.length ? object : false);
10690				}
10691			});
10692		},
10693
10694		hashChangeHandler: function(url) {
10695			var iL = this,
10696				vars = iL.vars,
10697				opts = iL.options,
10698				URL = url || window.location.href,
10699				hash = parseURI(URL).hash,
10700				split = hash.split('/'),
10701				index = split[1];
10702
10703			if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return;
10704
10705			if (index) {
10706				var target = split[1] || 0;
10707				if (iL.items[target]) {
10708					var overlay = $('.ilightbox-overlay');
10709					if (overlay.length && overlay.attr('linkid') == opts.linkId) {
10710						iL.goTo(target);
10711					} else {
10712						iL.itemsObject[target].trigger(ishybrid ? "itap click" : supportTouch ? 'itap' : 'click');
10713						//iL.goTo(target);
10714					}
10715				} else {
10716					var overlay = $('.ilightbox-overlay');
10717					if (overlay.length) iL.closeAction();
10718				}
10719			} else {
10720				var overlay = $('.ilightbox-overlay');
10721				if (overlay.length) iL.closeAction();
10722			}
10723		}
10724	};
10725
10726	/**
10727	 * Parse style to pixels.
10728	 *
10729	 * @param {Object}   $element   jQuery object with element.
10730	 * @param {Property} property   CSS property to get the pixels from.
10731	 *
10732	 * @return {Int}
10733	 */
10734	function getPixel($element, property) {
10735		return parseInt($element.css(property), 10) || 0;
10736	}
10737
10738	/**
10739	 * Make sure that number is within the limits.
10740	 *
10741	 * @param {Number} number
10742	 * @param {Number} min
10743	 * @param {Number} max
10744	 *
10745	 * @return {Number}
10746	 */
10747	function within(number, min, max) {
10748		return number < min ? min : number > max ? max : number;
10749	}
10750
10751	/**
10752	 * Get viewport/window size (width and height).
10753	 *
10754	 * @return {Object}
10755	 */
10756	function getViewport() {
10757		var e = window,
10758			a = 'inner';
10759		if (!('innerWidth' in window)) {
10760			a = 'client';
10761			e = document.documentElement || document.body;
10762		}
10763		return {
10764			width: e[a + 'Width'],
10765			height: e[a + 'Height']
10766		}
10767	}
10768
10769	/**
10770	 * Remove hash tag from the URL
10771	 *
10772	 * @return {Void}
10773	 */
10774	function removeHash() {
10775		var scroll = getScrollXY();
10776
10777		//UNCODE change
10778		//window.location.hash = "";
10779		history.pushState("", document.title, window.location.pathname + window.location.search);
10780
10781		// Restore the scroll offset, should be flicker free
10782		window.scrollTo(scroll.x, scroll.y);
10783	}
10784
10785	/**
10786	 * Do the ajax requests with callback.
10787	 *
10788	 * @param {String}   url
10789	 * @param {Function} callback
10790	 *
10791	 * @return {Void}
10792	 */
10793	function doAjax(url, callback) {
10794		var url = "//ilightbox.net/getSource/jsonp.php?url=" + encodeURIComponent(url).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A');
10795		$.ajax({
10796			url: url,
10797			dataType: 'jsonp'
10798		});
10799
10800		iLCallback = function(data) {
10801			callback.call(this, data);
10802		};
10803	}
10804
10805	/**
10806	 * Find image from DOM elements
10807	 *
10808	 * @param {Element} element
10809	 *
10810	 * @return {Void}
10811	 */
10812	function findImageInElement(element) {
10813		var elements = $('*', element),
10814			imagesArr = new Array();
10815
10816		elements.each(function() {
10817			var url = "",
10818				element = this;
10819
10820			if ($(element).css("background-image") != "none") {
10821				url = $(element).css("background-image");
10822			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
10823				url = $(element).attr("src");
10824			}
10825
10826			if (url.indexOf("gradient") == -1) {
10827				url = url.replace(/url\(\"/g, "");
10828				url = url.replace(/url\(/g, "");
10829				url = url.replace(/\"\)/g, "");
10830				url = url.replace(/\)/g, "");
10831
10832				var urls = url.split(",");
10833
10834				for (var i = 0; i < urls.length; i++) {
10835					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
10836						var extra = "";
10837						if (browser.msie && browser.version < 9) {
10838							extra = "?" + floor(random() * 3000);
10839						}
10840						imagesArr.push(urls[i] + extra);
10841					}
10842				}
10843			}
10844		});
10845
10846		return imagesArr;
10847	}
10848
10849	/**
10850	 * Get file extension.
10851	 *
10852	 * @param {String} URL
10853	 *
10854	 * @return {String}
10855	 */
10856	function getExtension(URL) {
10857		if (URL !== null) {
10858			//UNCODE: fix issue to detect media type with query strings
10859			var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL;
10860			ext = ext.split('.').pop().toLowerCase();
10861
10862			return ext;
10863		}
10864	}
10865
10866	/**
10867	 * Get type via extension.
10868	 *
10869	 * @param {String} URL
10870	 *
10871	 * @return {String}
10872	 */
10873	function getTypeByExtension(URL) {
10874		var type,
10875			ext = getExtension(URL);
10876
10877		//Uncode addition ##START##
10878		if (URL == undefined) {
10879			return false;
10880		}
10881		//Uncode addition ##END##
10882
10883		if (extensions.image.indexOf(ext) !== -1) type = 'image';
10884		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
10885		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
10886		else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition
10887		else type = 'iframe';
10888
10889		return type;
10890	}
10891
10892	/**
10893	 * Return value from percent of a number.
10894	 *
10895	 * @param {Number} percent
10896	 * @param {Number} total
10897	 *
10898	 * @return {Number}
10899	 */
10900	function percentToValue(percent, total) {
10901		return parseInt((total / 100) * percent);
10902	}
10903
10904	/**
10905	 * A JavaScript equivalent of PHP’s parse_url.
10906	 *
10907	 * @param {String} url           The URL to parse.
10908	 *
10909	 * @return {Mixed}
10910	 */
10911	function parseURI(url) {
10912		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
10913		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
10914		return (m ? {
10915			href: m[0] || '',
10916			protocol: m[1] || '',
10917			authority: m[2] || '',
10918			host: m[3] || '',
10919			hostname: m[4] || '',
10920			port: m[5] || '',
10921			pathname: m[6] || '',
10922			search: m[7] || '',
10923			hash: m[8] || ''
10924		} : null);
10925	}
10926
10927	/**
10928	 * Gets the absolute URI.
10929	 *
10930	 * @param {String} href     The relative URL.
10931	 * @param {String} base     The base URL.
10932	 *
10933	 * @return {String}         The absolute URL.
10934	 */
10935	function absolutizeURI(base, href) { // RFC 3986
10936		var iL = this;
10937
10938		function removeDotSegments(input) {
10939			var output = [];
10940			input.replace(/^(\.\.?(\/|$))+/, '')
10941				.replace(/\/(\.(\/|$))+/g, '/')
10942				.replace(/\/\.\.$/, '/../')
10943				.replace(/\/?[^\/]*/g, function(p) {
10944					if (p === '/..') {
10945						output.pop();
10946					} else {
10947						output.push(p);
10948					}
10949				});
10950			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
10951		}
10952
10953		href = parseURI(href || '');
10954		base = parseURI(base || '');
10955
10956		return !href || !base ? null : (href.protocol || base.protocol) +
10957			(href.protocol || href.authority ? href.authority : base.authority) +
10958			removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
10959			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
10960			href.hash;
10961	}
10962
10963	/**
10964	 * A JavaScript equivalent of PHP’s version_compare.
10965	 *
10966	 * @param {String} v1
10967	 * @param {String} v2
10968	 * @param {String} operator
10969	 *
10970	 * @return {Boolean}
10971	 */
10972	function version_compare(v1, v2, operator) {
10973		this.php_js = this.php_js || {};
10974		this.php_js.ENV = this.php_js.ENV || {};
10975		var i = 0,
10976			x = 0,
10977			compare = 0,
10978			vm = {
10979				'dev': -6,
10980				'alpha': -5,
10981				'a': -5,
10982				'beta': -4,
10983				'b': -4,
10984				'RC': -3,
10985				'rc': -3,
10986				'#': -2,
10987				'p': 1,
10988				'pl': 1
10989			},
10990			prepVersion = function(v) {
10991				v = ('' + v).replace(/[_\-+]/g, '.');
10992				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
10993				return (!v.length ? [-8] : v.split('.'));
10994			},
10995			numVersion = function(v) {
10996				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
10997			};
10998		v1 = prepVersion(v1);
10999		v2 = prepVersion(v2);
11000		x = max(v1.length, v2.length);
11001		for (i = 0; i < x; i++) {
11002			if (v1[i] == v2[i]) {
11003				continue;
11004			}
11005			v1[i] = numVersion(v1[i]);
11006			v2[i] = numVersion(v2[i]);
11007			if (v1[i] < v2[i]) {
11008				compare = -1;
11009				break;
11010			} else if (v1[i] > v2[i]) {
11011				compare = 1;
11012				break;
11013			}
11014		}
11015		if (!operator) {
11016			return compare;
11017		}
11018
11019		switch (operator) {
11020			case '>':
11021			case 'gt':
11022				return (compare > 0);
11023			case '>=':
11024			case 'ge':
11025				return (compare >= 0);
11026			case '<=':
11027			case 'le':
11028				return (compare <= 0);
11029			case '==':
11030			case '=':
11031			case 'eq':
11032				return (compare === 0);
11033			case '<>':
11034			case '!=':
11035			case 'ne':
11036				return (compare !== 0);
11037			case '':
11038			case '<':
11039			case 'lt':
11040				return (compare < 0);
11041			default:
11042				return null;
11043		}
11044	}
11045
11046
11047	// Begin the iLightBox plugin
11048	$.fn.iLightBox = function() {
11049
11050		var args = arguments,
11051			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
11052			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
11053
11054		if (!opt) opt = {};
11055
11056		// Default options. Play carefully.
11057		var options = $.extend(true, {
11058			attr: 'href',
11059			path: 'vertical',
11060			skin: 'dark',
11061			linkId: false,
11062			infinite: false,
11063			startFrom: 0,
11064			randomStart: false,
11065			keepAspectRatio: true,
11066			maxScale: 1,
11067			minScale: .2,
11068			innerToolbar: false,
11069			smartRecognition: false,
11070			mobileOptimizer: true,
11071			fullAlone: true,
11072			fullViewPort: null,
11073			fullStretchTypes: 'flash, video',
11074			overlay: {
11075				blur: true,
11076				opacity: .85
11077			},
11078			controls: {
11079				arrows: false,
11080				slideshow: false,
11081				toolbar: true,
11082				fullscreen: true,
11083				thumbnail: true,
11084				keyboard: true,
11085				mousewheel: true,
11086				swipe: true
11087			},
11088			keyboard: {
11089				left: true, // previous
11090				right: true, // next
11091				up: true, // previous
11092				down: true, // next
11093				esc: true, // close
11094				shift_enter: true // fullscreen
11095			},
11096			show: {
11097				effect: true,
11098				speed: 300,
11099				title: true
11100			},
11101			hide: {
11102				effect: true,
11103				speed: 300
11104			},
11105			caption: {
11106				start: true,
11107				show: 'mouseenter',
11108				hide: 'mouseleave'
11109			},
11110			social: {
11111				start: true,
11112				show: 'mouseenter',
11113				hide: 'mouseleave',
11114				buttons: false
11115			},
11116			styles: {
11117				pageOffsetX: 0,
11118				pageOffsetY: 0,
11119				nextOffsetX: 45,
11120				nextOffsetY: 0,
11121				nextOpacity: 1,
11122				nextScale: 1,
11123				prevOffsetX: 45,
11124				prevOffsetY: 0,
11125				prevOpacity: 1,
11126				prevScale: 1
11127			},
11128			thumbnails: {
11129				maxWidth: 120,
11130				maxHeight: 80,
11131				normalOpacity: 1,
11132				activeOpacity: .6
11133			},
11134			effects: {
11135				reposition: true,
11136				repositionSpeed: 200,
11137				switchSpeed: 500,
11138				loadedFadeSpeed: 180,
11139				fadeSpeed: 200
11140			},
11141			slideshow: {
11142				pauseTime: 5000,
11143				pauseOnHover: false,
11144				startPaused: true
11145			},
11146			text: {
11147				close: "Press Esc to close",
11148				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
11149				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
11150				slideShow: "Slideshow",
11151				next: "Next",
11152				previous: "Previous"
11153			},
11154			errors: {
11155				loadImage: "An error occurred when trying to load photo.",
11156				loadContents: "An error occurred when trying to load contents.",
11157				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
11158			},
11159			ajaxSetup: {
11160				url: '',
11161				beforeSend: function(jqXHR, settings) {},
11162				cache: false,
11163				complete: function(jqXHR, textStatus) {},
11164				crossDomain: false,
11165				error: function(jqXHR, textStatus, errorThrown) {},
11166				success: function(data, textStatus, jqXHR) {},
11167				global: true,
11168				ifModified: false,
11169				username: null,
11170				password: null,
11171				type: 'GET'
11172			},
11173			callback: {}
11174		}, opt);
11175
11176		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
11177
11178		items = $.isArray(items) ? items : new Array();
11179
11180		if (typeof args[0] == 'string') items[0] = args[0];
11181
11182		if (version_compare($.fn.jquery, '1.8', '>=')) {
11183			var iLB = new iLightBox($(this), options, items, instant);
11184			return {
11185				close: function() {
11186					iLB.closeAction();
11187				},
11188				fullscreen: function() {
11189					iLB.fullScreenAction();
11190				},
11191				moveNext: function() {
11192					iLB.moveTo('next');
11193				},
11194				movePrev: function() {
11195					iLB.moveTo('prev');
11196				},
11197				goTo: function(index) {
11198					iLB.goTo(index);
11199				},
11200				refresh: function() {
11201					iLB.refresh();
11202				},
11203				reposition: function() {
11204					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
11205				},
11206				setOption: function(options) {
11207					iLB.setOption(options);
11208				},
11209				destroy: function() {
11210					iLB.closeAction();
11211					iLB.dispatchItemsEvents();
11212				}
11213			};
11214		} else {
11215			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
11216		}
11217
11218	};
11219
11220
11221	$.iLightBox = function() {
11222		return $.fn.iLightBox(arguments[0], arguments[1]);
11223	};
11224
11225	function getScrollXY() {
11226		var scrOfX = 0,
11227			scrOfY = 0;
11228		if (typeof(window.pageYOffset) == 'number') {
11229			//Netscape compliant
11230			scrOfY = window.pageYOffset;
11231			scrOfX = window.pageXOffset;
11232		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
11233			//DOM compliant
11234			scrOfY = document.body.scrollTop;
11235			scrOfX = document.body.scrollLeft;
11236		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
11237			//IE6 standards compliant mode
11238			scrOfY = document.documentElement.scrollTop;
11239			scrOfX = document.documentElement.scrollLeft;
11240		}
11241		return {
11242			x: scrOfX,
11243			y: scrOfY
11244		};
11245	}
11246
11247	(function() {
11248		// add new event shortcuts
11249		$.each(("touchstart touchmove touchend " +
11250			"tap taphold " +
11251			"swipe swipeleft swiperight " +
11252			"scrollstart scrollstop").split(" "), function(i, name) {
11253
11254			$.fn[name] = function(fn) {
11255				return fn ? this.bind(name, fn) : this.trigger(name);
11256			};
11257
11258			// jQuery < 1.8
11259			// if ($.attrFn) {
11260			// 	$.attrFn[name] = true;
11261			// }
11262		});
11263
11264		var tapSettings = {
11265			startEvent: 'touchstart.iTap',
11266			endEvent: 'touchend.iTap'
11267		};
11268
11269		// tap Event:
11270		$.event.special.itap = {
11271			setup: function() {
11272
11273				var self = this,
11274					$self = $(this),
11275					start, stop;
11276
11277				$self.bind(tapSettings.startEvent, function(event) {
11278					start = getScrollXY();
11279
11280					$self.one(tapSettings.endEvent, function(event) {
11281						stop = getScrollXY();
11282
11283						var orgEvent = event || window.event;
11284						event = $.event.fix(orgEvent);
11285						event.type = "itap";
11286
11287						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
11288
11289						start = stop = undefined;
11290					});
11291				});
11292			},
11293
11294			teardown: function() {
11295				$(this).unbind(tapSettings.startEvent);
11296			}
11297		};
11298	}());
11299
11300
11301	//Fullscreen API
11302	(function() {
11303		fullScreenApi = {
11304				supportsFullScreen: false,
11305				isFullScreen: function() {
11306					return false;
11307				},
11308				requestFullScreen: function() {},
11309				cancelFullScreen: function() {},
11310				fullScreenEventName: '',
11311				prefix: ''
11312			},
11313			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
11314
11315		// check for native support
11316		if (typeof document.cancelFullScreen != 'undefined') {
11317			fullScreenApi.supportsFullScreen = true;
11318		} else {
11319			// check for fullscreen support by vendor prefix
11320			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
11321				fullScreenApi.prefix = browserPrefixes[i];
11322
11323				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
11324					fullScreenApi.supportsFullScreen = true;
11325
11326					break;
11327				}
11328			}
11329		}
11330
11331		// update methods to do something useful
11332		if (fullScreenApi.supportsFullScreen) {
11333			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
11334
11335			fullScreenApi.isFullScreen = function() {
11336				switch (this.prefix) {
11337					case '':
11338						return document.fullScreen;
11339					case 'webkit':
11340						return document.webkitIsFullScreen;
11341					default:
11342						return document[this.prefix + 'FullScreen'];
11343				}
11344			}
11345			fullScreenApi.requestFullScreen = function(el) {
11346				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
11347			}
11348			fullScreenApi.cancelFullScreen = function(el) {
11349				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
11350			}
11351		}
11352	}());
11353
11354	// Browser detect
11355	(function() {
11356		function uaMatch(ua) {
11357			ua = ua.toLowerCase();
11358
11359			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
11360				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
11361				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
11362				/(msie) ([\w.]+)/.exec(ua) ||
11363				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
11364
11365			return {
11366				browser: match[1] || "",
11367				version: match[2] || "0"
11368			};
11369		}
11370
11371		var matched = uaMatch(navigator.userAgent);
11372		browser = {};
11373
11374		if (matched.browser) {
11375			browser[matched.browser] = true;
11376			browser.version = matched.version;
11377		}
11378
11379		// Chrome is Webkit, but Webkit is also Safari.
11380		if (browser.chrome) {
11381			browser.webkit = true;
11382		} else if (browser.webkit) {
11383			browser.safari = true;
11384		}
11385	}());
11386
11387	// Feature detects
11388	(function() {
11389		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
11390		var el = document.createElement('div');
11391
11392		function testProp(prop) {
11393			for (var p = 0, pl = prefixes.length; p < pl; p++) {
11394				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
11395				if (el.style[prefixedProp] !== undefined) {
11396					return prefixedProp;
11397				}
11398			}
11399		}
11400
11401		// Global support indicators
11402		transform = testProp('transform') || '';
11403		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
11404	}());
11405
11406
11407	/*
11408		PluginDetect v0.7.9
11409		www.pinlady.net/PluginDetect/license/
11410		[ getVersion onWindowLoaded BetterIE ]
11411		[ Flash QuickTime Shockwave ]
11412	*/
11413	var PluginDetect={version:"0.7.9",name:"PluginDetect",handler:function(c,b,a){return function(){c(b,a)}},openTag:"<",isDefined:function(b){return typeof b!="undefined"},isArray:function(b){return(/array/i).test(Object.prototype.toString.call(b))},isFunc:function(b){return typeof b=="function"},isString:function(b){return typeof b=="string"},isNum:function(b){return typeof b=="number"},isStrNum:function(b){return(typeof b=="string"&&(/\d/).test(b))},getNumRegx:/[\d][\d\.\_,-]*/,splitNumRegx:/[\.\_,-]/g,getNum:function(b,c){var d=this,a=d.isStrNum(b)?(d.isDefined(c)?new RegExp(c):d.getNumRegx).exec(b):null;return a?a[0]:null},compareNums:function(h,f,d){var e=this,c,b,a,g=parseInt;if(e.isStrNum(h)&&e.isStrNum(f)){if(e.isDefined(d)&&d.compareNums){return d.compareNums(h,f)}c=h.split(e.splitNumRegx);b=f.split(e.splitNumRegx);for(a=0;a<min(c.length,b.length);a++){if(g(c[a],10)>g(b[a],10)){return 1}if(g(c[a],10)<g(b[a],10)){return -1}}}return 0},formatNum:function(b,c){var d=this,a,e;if(!d.isStrNum(b)){return null}if(!d.isNum(c)){c=4}c--;e=b.replace(/\s/g,"").split(d.splitNumRegx).concat(["0","0","0","0"]);for(a=0;a<4;a++){if(/^(0+)(.+)$/.test(e[a])){e[a]=RegExp.$2}if(a>c||!(/\d/).test(e[a])){e[a]="0"}}return e.slice(0,4).join(",")},$$hasMimeType:function(a){return function(c){if(!a.isIE&&c){var f,e,b,d=a.isArray(c)?c:(a.isString(c)?[c]:[]);for(b=0;b<d.length;b++){if(a.isString(d[b])&&/[^\s]/.test(d[b])){f=navigator.mimeTypes[d[b]];e=f?f.enabledPlugin:0;if(e&&(e.name||e.description)){return f}}}}return null}},findNavPlugin:function(l,e,c){var j=this,h=new RegExp(l,"i"),d=(!j.isDefined(e)||e)?/\d/:0,k=c?new RegExp(c,"i"):0,a=navigator.plugins,g="",f,b,m;for(f=0;f<a.length;f++){m=a[f].description||g;b=a[f].name||g;if((h.test(m)&&(!d||d.test(RegExp.leftContext+RegExp.rightContext)))||(h.test(b)&&(!d||d.test(RegExp.leftContext+RegExp.rightContext)))){if(!k||!(k.test(m)||k.test(b))){return a[f]}}}return null},getMimeEnabledPlugin:function(k,m,c){var e=this,f,b=new RegExp(m,"i"),h="",g=c?new RegExp(c,"i"):0,a,l,d,j=e.isString(k)?[k]:k;for(d=0;d<j.length;
11413d++){if((f=e.hasMimeType(j[d]))&&(f=f.enabledPlugin)){l=f.description||h;a=f.name||h;if(b.test(l)||b.test(a)){if(!g||!(g.test(l)||g.test(a))){return f}}}}return 0},getPluginFileVersion:function(f,b){var h=this,e,d,g,a,c=-1;if(h.OS>2||!f||!f.version||!(e=h.getNum(f.version))){return b}if(!b){return e}e=h.formatNum(e);b=h.formatNum(b);d=b.split(h.splitNumRegx);g=e.split(h.splitNumRegx);for(a=0;a<d.length;a++){if(c>-1&&a>c&&d[a]!="0"){return b}if(g[a]!=d[a]){if(c==-1){c=a}if(d[a]!="0"){return b}}}return e},AXO:window.ActiveXObject,getAXO:function(a){var f=null,d,b=this,c={};try{f=new b.AXO(a)}catch(d){}return f},convertFuncs:function(f){var a,g,d,b=/^[\$][\$]/,c=this;for(a in f){if(b.test(a)){try{g=a.slice(2);if(g.length>0&&!f[g]){f[g]=f[a](f);delete f[a]}}catch(d){}}}},initObj:function(e,b,d){var a,c;if(e){if(e[b[0]]==1||d){for(a=0;a<b.length;a=a+2){e[b[a]]=b[a+1]}}for(a in e){c=e[a];if(c&&c[b[0]]==1){this.initObj(c,b)}}}},initScript:function(){var d=this,a=navigator,h,i=document,l=a.userAgent||"",j=a.vendor||"",b=a.platform||"",k=a.product||"";d.initObj(d,["$",d]);for(h in d.Plugins){if(d.Plugins[h]){d.initObj(d.Plugins[h],["$",d,"$$",d.Plugins[h]],1)}}d.convertFuncs(d);d.OS=100;if(b){var g=["Win",1,"Mac",2,"Linux",3,"FreeBSD",4,"iPhone",21.1,"iPod",21.2,"iPad",21.3,"Win.*CE",22.1,"Win.*Mobile",22.2,"Pocket\\s*PC",22.3,"",100];for(h=g.length-2;h>=0;h=h-2){if(g[h]&&new RegExp(g[h],"i").test(b)){d.OS=g[h+1];break}}};d.head=i.getElementsByTagName("head")[0]||i.getElementsByTagName("body")[0]||i.body||null;d.isIE=new Function("return/*@cc_on!@*/!1")();d.verIE=d.isIE&&(/MSIE\s*(\d+\.?\d*)/i).test(l)?parseFloat(RegExp.$1,10):null;d.verIEfull=null;d.docModeIE=null;if(d.isIE){var f,n,c=document.createElement("div");try{c.style.behavior="url(#default#clientcaps)";d.verIEfull=(c.getComponentVersion("{89820200-ECBD-11CF-8B85-00AA005B4383}","componentid")).replace(/,/g,".")}catch(f){}n=parseFloat(d.verIEfull||"0",10);d.docModeIE=i.documentMode||((/back/i).test(i.compatMode||"")?5:n)||d.verIE;d.verIE=n||d.docModeIE};d.ActiveXEnabled=false;if(d.isIE){var h,m=["Msxml2.XMLHTTP","Msxml2.DOMDocument","Microsoft.XMLDOM","ShockwaveFlash.ShockwaveFlash","TDCCtl.TDCCtl","Shell.UIHelper","Scripting.Dictionary","wmplayer.ocx"];for(h=0;h<m.length;h++){if(d.getAXO(m[h])){d.ActiveXEnabled=true;break}}};d.isGecko=(/Gecko/i).test(k)&&(/Gecko\s*\/\s*\d/i).test(l);
11413d.verGecko=d.isGecko?d.formatNum((/rv\s*\:\s*([\.\,\d]+)/i).test(l)?RegExp.$1:"0.9"):null;d.isChrome=(/Chrome\s*\/\s*(\d[\d\.]*)/i).test(l);d.verChrome=d.isChrome?d.formatNum(RegExp.$1):null;d.isSafari=((/Apple/i).test(j)||(!j&&!d.isChrome))&&(/Safari\s*\/\s*(\d[\d\.]*)/i).test(l);d.verSafari=d.isSafari&&(/Version\s*\/\s*(\d[\d\.]*)/i).test(l)?d.formatNum(RegExp.$1):null;d.isOpera=(/Opera\s*[\/]?\s*(\d+\.?\d*)/i).test(l);d.verOpera=d.isOpera&&((/Version\s*\/\s*(\d+\.?\d*)/i).test(l)||1)?parseFloat(RegExp.$1,10):null;d.addWinEvent("load",d.handler(d.runWLfuncs,d))},init:function(d){var c=this,b,d,a={status:-3,plugin:0};if(!c.isString(d)){return a}if(d.length==1){c.getVersionDelimiter=d;return a}d=d.toLowerCase().replace(/\s/g,"");b=c.Plugins[d];if(!b||!b.getVersion){return a}a.plugin=b;if(!c.isDefined(b.installed)){b.installed=null;b.version=null;b.version0=null;b.getVersionDone=null;b.pluginName=d}c.garbage=false;if(c.isIE&&!c.ActiveXEnabled&&d!=="java"){a.status=-2;return a}a.status=1;return a},fPush:function(b,a){var c=this;if(c.isArray(a)&&(c.isFunc(b)||(c.isArray(b)&&b.length>0&&c.isFunc(b[0])))){a.push(b)}},callArray:function(b){var c=this,a;if(c.isArray(b)){for(a=0;a<b.length;a++){if(b[a]===null){return}c.call(b[a]);b[a]=null}}},call:function(c){var b=this,a=b.isArray(c)?c.length:-1;if(a>0&&b.isFunc(c[0])){c[0](b,a>1?c[1]:0,a>2?c[2]:0,a>3?c[3]:0)}else{if(b.isFunc(c)){c(b)}}},getVersionDelimiter:",",$$getVersion:function(a){return function(g,d,c){var e=a.init(g),f,b,h={};if(e.status<0){return null};f=e.plugin;if(f.getVersionDone!=1){f.getVersion(null,d,c);if(f.getVersionDone===null){f.getVersionDone=1}}a.cleanup();b=(f.version||f.version0);b=b?b.replace(a.splitNumRegx,a.getVersionDelimiter):b;return b}},cleanup:function(){var a=this;if(a.garbage&&a.isDefined(window.CollectGarbage)){window.CollectGarbage()}},isActiveXObject:function(d,b){var f=this,a=false,g,c='<object width="1" height="1" style="display:none" '+d.getCodeBaseVersion(b)+">"+d.HTML+f.openTag+"/object>";if(!f.head){return a}f.head.insertBefore(document.createElement("object"),f.head.firstChild);f.head.firstChild.outerHTML=c;try{f.head.firstChild.classid=d.classID}catch(g){}try{if(f.head.firstChild.object){a=true}}catch(g){}try{if(a&&f.head.firstChild.readyState<4){f.garbage=true}}catch(g){}f.head.removeChild(f.head.firstChild);return a},codebaseSearch:function(f,b){var c=this;if(!c.ActiveXEnabled||!f){return null}if(f.BIfuncs&&f.BIfuncs.length&&f.BIfuncs[f.BIfuncs.length-1]!==null){c.callArray(f.BIfuncs)}var d,o=f.SEARCH,k={};if(c.isStrNum(b)){if(o.match&&o.min&&c.compareNums(b,o.min)<=0){return true}if(o.match&&o.max&&c.compareNums(b,o.max)>=0){return false}d=c.isActiveXObject(f,b);if(d&&(!o.min||c.compareNums(b,o.min)>0)){o.min=b}if(!d&&(!o.max||c.compareNums(b,o.max)<0)){o.max=b}return d};var e=[0,0,0,0],l=[].concat(o.digits),a=o.min?1:0,j,i,h,g,m,n=function(p,r){var q=[].concat(e);q[p]=r;return c.isActiveXObject(f,q.join(","))};if(o.max){g=o.max.split(c.splitNumRegx);for(j=0;j<g.length;j++){g[j]=parseInt(g[j],10)}if(g[0]<l[0]){l[0]=g[0]}}if(o.min){m=o.min.split(c.splitNumRegx);for(j=0;j<m.length;j++){m[j]=parseInt(m[j],10)}if(m[0]>e[0]){e[0]=m[0]}}if(m&&g){for(j=1;j<m.length;j++){if(m[j-1]!=g[j-1]){break}if(g[j]<l[j]){l[j]=g[j]}if(m[j]>e[j]){e[j]=m[j]}}}if(o.max){for(j=1;j<l.length;j++){if(g[j]>0&&l[j]==0&&l[j-1]<o.digits[j-1]){l[j-1]+=1;break}}};for(j=0;j<l.length;j++){h={};for(i=0;i<20;i++){if(l[j]-e[j]<1){break}d=round((l[j]+e[j])/2);if(h["a"+d]){break}h["a"+d]=1;if(n(j,d)){e[j]=d;a=1}else{l[j]=d}}l[j]=e[j];if(!a&&n(j,e[j])){a=1};if(!a){break}};return a?e.join(","):null},addWinEvent:function(d,c){var e=this,a=window,b;if(e.isFunc(c)){if(a.addEventListener){a.addEventListener(d,c,false)}else{if(a.attachEvent){a.attachEvent("on"+d,c)}else{b=a["on"+d];a["on"+d]=e.winHandler(c,b)}}}},winHandler:function(d,c){return function(){d();if(typeof c=="function"){c()}}},WLfuncs0:[],WLfuncs:[],runWLfuncs:function(a){var b={};a.winLoaded=true;a.callArray(a.WLfuncs0);a.callArray(a.WLfuncs);if(a.onDoneEmptyDiv){a.onDoneEmptyDiv()}},winLoaded:false,$$onWindowLoaded:function(a){return function(b){if(a.winLoaded){a.call(b)}else{a.fPush(b,a.WLfuncs)}}},div:null,divID:"plugindetect",divWidth:50,pluginSize:1,emptyDiv:function(){var d=this,b,h,c,a,f,g;if(d.div&&d.div.childNodes){for(b=d.div.childNodes.length-1;b>=0;b--){c=d.div.childNodes[b];if(c&&c.childNodes){for(h=c.childNodes.length-1;h>=0;h--){g=c.childNodes[h];try{c.removeChild(g)}catch(f){}}}if(c){try{d.div.removeChild(c)}catch(f){}}}}if(!d.div){a=document.getElementById(d.divID);if(a){d.div=a}}if(d.div&&d.div.parentNode){try{d.div.parentNode.removeChild(d.div)}catch(f){}d.div=null}},DONEfuncs:[],onDoneEmptyDiv:function(){var c=this,a,b;if(!c.winLoaded){return}if(c.WLfuncs&&c.WLfuncs.length&&c.WLfuncs[c.WLfuncs.length-1]!==null){return}for(a in c){b=c[a];if(b&&b.funcs){if(b.OTF==3){return}if(b.funcs.length&&b.funcs[b.funcs.length-1]!==null){return}}}for(a=0;a<c.DONEfuncs.length;a++){c.callArray(c.DONEfuncs)}
11413c.emptyDiv()},getWidth:function(c){if(c){var a=c.scrollWidth||c.offsetWidth,b=this;if(b.isNum(a)){return a}}return -1},getTagStatus:function(m,g,a,b){var c=this,f,k=m.span,l=c.getWidth(k),h=a.span,j=c.getWidth(h),d=g.span,i=c.getWidth(d);if(!k||!h||!d||!c.getDOMobj(m)){return -2}if(j<i||l<0||j<0||i<0||i<=c.pluginSize||c.pluginSize<1){return 0}if(l>=i){return -1}try{if(l==c.pluginSize&&(!c.isIE||c.getDOMobj(m).readyState==4)){if(!m.winLoaded&&c.winLoaded){return 1}if(m.winLoaded&&c.isNum(b)){if(!c.isNum(m.count)){m.count=b}if(b-m.count>=10){return 1}}}}catch(f){}return 0},getDOMobj:function(g,a){var f,d=this,c=g?g.span:0,b=c&&c.firstChild?1:0;try{if(b&&a){d.div.focus()}}catch(f){}return b?c.firstChild:null},setStyle:function(b,g){var f=b.style,a,d,c=this;if(f&&g){for(a=0;a<g.length;a=a+2){try{f[g[a]]=g[a+1]}catch(d){}}}},insertDivInBody:function(i,g){var f,c=this,h="pd33993399",b=null,d=g?window.top.document:window.document,a=d.getElementsByTagName("body")[0]||d.body;if(!a){try{d.write('<div id="'+h+'">.'+c.openTag+"/div>");b=d.getElementById(h)}catch(f){}}a=d.getElementsByTagName("body")[0]||d.body;if(a){a.insertBefore(i,a.firstChild);if(b){a.removeChild(b)}}},insertHTML:function(f,b,g,a,k){var l,m=document,j=this,p,o=m.createElement("span"),n,i;var c=["outlineStyle","none","borderStyle","none","padding","0px","margin","0px","visibility","visible"];var h="outline-style:none;border-style:none;padding:0px;margin:0px;visibility:visible;";if(!j.isDefined(a)){a=""}if(j.isString(f)&&(/[^\s]/).test(f)){f=f.toLowerCase().replace(/\s/g,"");p=j.openTag+f+' width="'+j.pluginSize+'" height="'+j.pluginSize+'" ';p+='style="'+h+'display:inline;" ';for(n=0;n<b.length;n=n+2){if(/[^\s]/.test(b[n+1])){p+=b[n]+'="'+b[n+1]+'" '}}p+=">";for(n=0;n<g.length;n=n+2){if(/[^\s]/.test(g[n+1])){p+=j.openTag+'param name="'+g[n]+'" value="'+g[n+1]+'" />'}}p+=a+j.openTag+"/"+f+">"}else{p=a}if(!j.div){i=m.getElementById(j.divID);if(i){j.div=i}else{j.div=m.createElement("div");j.div.id=j.divID}j.setStyle(j.div,c.concat(["width",j.divWidth+"px","height",(j.pluginSize+3)+"px","fontSize",(j.pluginSize+3)+"px","lineHeight",(j.pluginSize+3)+"px","verticalAlign","baseline","display","block"]));if(!i){j.setStyle(j.div,["position","absolute","right","0px","top","0px"]);j.insertDivInBody(j.div)}}if(j.div&&j.div.parentNode){j.setStyle(o,c.concat(["fontSize",(j.pluginSize+3)+"px","lineHeight",(j.pluginSize+3)+"px","verticalAlign","baseline","display","inline"]));try{o.innerHTML=p}catch(l){};try{j.div.appendChild(o)}catch(l){};return{span:o,winLoaded:j.winLoaded,tagName:f,outerHTML:p}}return{span:null,winLoaded:j.winLoaded,tagName:"",outerHTML:p}},Plugins:{quicktime:{mimeType:["video/quicktime","application/x-quicktimeplayer","image/x-macpaint","image/x-quicktime"],progID:"QuickTimeCheckObject.QuickTimeCheck.1",progID0:"QuickTime.QuickTime",classID:"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",minIEver:7,HTML:'<param name="src" value="" /><param name="controller" value="false" />',getCodeBaseVersion:function(a){return'codebase="#version='+a+'"'},SEARCH:{min:0,max:0,match:0,digits:[16,128,128,0]},getVersion:function(c){var f=this,d=f.$,a=null,e=null,b;if(!d.isIE){if(d.hasMimeType(f.mimeType)){e=d.OS!=3?d.findNavPlugin("QuickTime.*Plug-?in",0):null;if(e&&e.name){a=d.getNum(e.name)}}}else{if(d.isStrNum(c)){b=c.split(d.splitNumRegx);if(b.length>3&&parseInt(b[3],10)>0){b[3]="9999"}c=b.join(",")}if(d.isStrNum(c)&&d.verIE>=f.minIEver&&f.canUseIsMin()>0){f.installed=f.isMin(c);f.getVersionDone=0;return}f.getVersionDone=1;if(!a&&d.verIE>=f.minIEver){a=f.CDBASE2VER(d.codebaseSearch(f))}if(!a){e=d.getAXO(f.progID);if(e&&e.QuickTimeVersion){a=e.QuickTimeVersion.toString(16);a=parseInt(a.charAt(0),16)+"."+parseInt(a.charAt(1),16)+"."+parseInt(a.charAt(2),16)}}}f.installed=a?1:(e?0:-1);f.version=d.formatNum(a,3)},cdbaseUpper:["7,60,0,0","0,0,0,0"],cdbaseLower:["7,50,0,0",null],cdbase2ver:[function(c,b){var a=b.split(c.$.splitNumRegx);return[a[0],a[1].charAt(0),a[1].charAt(1),a[2]].join(",")},null],CDBASE2VER:function(f){var e=this,c=e.$,b,a=e.cdbaseUpper,d=e.cdbaseLower;
11413if(f){f=c.formatNum(f);for(b=0;b<a.length;b++){if(a[b]&&c.compareNums(f,a[b])<0&&d[b]&&c.compareNums(f,d[b])>=0&&e.cdbase2ver[b]){return e.cdbase2ver[b](e,f)}}}return f},canUseIsMin:function(){var f=this,d=f.$,b,c=f.canUseIsMin,a=f.cdbaseUpper,e=f.cdbaseLower;if(!c.value){c.value=-1;for(b=0;b<a.length;b++){if(a[b]&&d.codebaseSearch(f,a[b])){c.value=1;break}if(e[b]&&d.codebaseSearch(f,e[b])){c.value=-1;break}}}f.SEARCH.match=c.value==1?1:0;return c.value},isMin:function(c){var b=this,a=b.$;return a.codebaseSearch(b,c)?0.7:-1}},flash:{mimeType:"application/x-shockwave-flash",progID:"ShockwaveFlash.ShockwaveFlash",classID:"clsid:D27CDB6E-AE6D-11CF-96B8-444553540000",getVersion:function(){var b=function(i){if(!i){return null}var e=/[\d][\d\,\.\s]*[rRdD]{0,1}[\d\,]*/.exec(i);return e?e[0].replace(/[rRdD\.]/g,",").replace(/\s/g,""):null};var j=this,g=j.$,k,h,l=null,c=null,a=null,f,m,d;if(!g.isIE){m=g.hasMimeType(j.mimeType);if(m){f=g.getDOMobj(g.insertHTML("object",["type",j.mimeType],[],"",j));try{l=g.getNum(f.GetVariable("$version"))}catch(k){}}if(!l){d=m?m.enabledPlugin:null;if(d&&d.description){l=b(d.description)}if(l){l=g.getPluginFileVersion(d,l)}}}else{for(h=15;h>2;h--){c=g.getAXO(j.progID+"."+h);if(c){a=h.toString();break}}if(!c){c=g.getAXO(j.progID)}if(a=="6"){try{c.AllowScriptAccess="always"}catch(k){return"6,0,21,0"}}try{l=b(c.GetVariable("$version"))}catch(k){}if(!l&&a){l=a}}j.installed=l?1:-1;j.version=g.formatNum(l);return true}},shockwave:{mimeType:"application/x-director",progID:"SWCtl.SWCtl",classID:"clsid:166B1BCA-3F9C-11CF-8075-444553540000",getVersion:function(){var a=null,b=null,g,f,d=this,c=d.$;if(!c.isIE){f=c.findNavPlugin("Shockwave\\s*for\\s*Director");if(f&&f.description&&c.hasMimeType(d.mimeType)){a=c.getNum(f.description)}if(a){a=c.getPluginFileVersion(f,a)}}else{try{b=c.getAXO(d.progID).ShockwaveVersion("")}catch(g){}if(c.isString(b)&&b.length>0){a=c.getNum(b)}else{if(c.getAXO(d.progID+".8")){a="8"}else{if(c.getAXO(d.progID+".7")){a="7"}else{if(c.getAXO(d.progID+".1")){a="6"}}}}}d.installed=a?1:-1;d.version=c.formatNum(a)}},zz:0}};PluginDetect.initScript();
11414
11415	var gArgCountErr='The "%%" function requires an even number of arguments.\nArguments should be in the form "atttributeName", "attributeValue", ...',gTagAttrs=null,gQTGeneratorVersion=1;function AC_QuickTimeVersion(){return gQTGeneratorVersion}function _QTComplain(a,b){b=b.replace("%%",a);alert(b)}function _QTAddAttribute(a,b,c){var d;d=gTagAttrs[a+b];null==d&&(d=gTagAttrs[b]);return null!=d?(0==b.indexOf(a)&&null==c&&(c=b.substring(a.length)),null==c&&(c=b),c+'="'+d+'" '):""}function _QTAddObjectAttr(a,b){if(0==a.indexOf("emb#"))return"";0==a.indexOf("obj#")&&null==b&&(b=a.substring(4));return _QTAddAttribute("obj#",a,b)}function _QTAddEmbedAttr(a,b){if(0==a.indexOf("obj#"))return"";0==a.indexOf("emb#")&&null==b&&(b=a.substring(4));return _QTAddAttribute("emb#",a,b)}function _QTAddObjectParam(a,b){var c,d="",e=b?" />":">";-1==a.indexOf("emb#")&&(c=gTagAttrs["obj#"+a],null==c&&(c=gTagAttrs[a]),0==a.indexOf("obj#")&&(a=a.substring(4)),null!=c&&(d='  <param name="'+a+'" value="'+c+'"'+e+"\n"));return d}function _QTDeleteTagAttrs(){for(var a=0;a<arguments.length;a++){var b=arguments[a];delete gTagAttrs[b];delete gTagAttrs["emb#"+b];delete gTagAttrs["obj#"+b]}}function _QTGenerate(a,b,c){if(4>c.length||0!=c.length%2)return _QTComplain(a,gArgCountErr),"";gTagAttrs=[];gTagAttrs.src=c[0];gTagAttrs.width=c[1];gTagAttrs.height=c[2];gTagAttrs.classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B";gTagAttrs.pluginspage="http://www.apple.com/quicktime/download/";a=c[3];if(null==a||""==a)a="6,0,2,0";gTagAttrs.codebase="http://www.apple.com/qtactivex/qtplugin.cab#version="+a;for(var d,e=4;e<c.length;e+=2)d=c[e].toLowerCase(),a=c[e+1],"name"==d||"id"==d?gTagAttrs.name=a:gTagAttrs[d]=a;c="<object "+_QTAddObjectAttr("classid")+_QTAddObjectAttr("width")+_QTAddObjectAttr("height")+_QTAddObjectAttr("codebase")+_QTAddObjectAttr("name","id")+_QTAddObjectAttr("tabindex")+_QTAddObjectAttr("hspace")+_QTAddObjectAttr("vspace")+_QTAddObjectAttr("border")+_QTAddObjectAttr("align")+_QTAddObjectAttr("class")+_QTAddObjectAttr("title")+_QTAddObjectAttr("accesskey")+_QTAddObjectAttr("noexternaldata")+">\n"+_QTAddObjectParam("src",b);e="  <embed "+_QTAddEmbedAttr("src")+_QTAddEmbedAttr("width")+_QTAddEmbedAttr("height")+_QTAddEmbedAttr("pluginspage")+_QTAddEmbedAttr("name")+_QTAddEmbedAttr("align")+_QTAddEmbedAttr("tabindex");_QTDeleteTagAttrs("src","width","height","pluginspage","classid","codebase","name","tabindex","hspace","vspace","border","align","noexternaldata","class","title","accesskey");for(d in gTagAttrs)a=gTagAttrs[d],null!=a&&(e+=_QTAddEmbedAttr(d),c+=_QTAddObjectParam(d,b));return c+e+"> </embed>\n</object>"}function QT_GenerateOBJECTText(){return _QTGenerate("QT_GenerateOBJECTText",!1,arguments)};
11416
11417
11418	/*
11419		jQuery hashchange event v1.3
11420		https://github.com/cowboy/jquery-hashchange
11421		Copyright (c) 2010 "Cowboy" Ben Alman
11422		Dual licensed under the MIT and GPL licenses.
11423	*/
11424	(function(){function e(a){a=a||location.href;return"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var k=document,b,f=$.event.special,p=k.documentMode,m="oniLightBoxHashChange"in window&&(void 0===p||7<p);$.fn.iLightBoxHashChange=function(a){return a?this.bind("iLightBoxHashChange",a):this.trigger("iLightBoxHashChange")};$.fn.iLightBoxHashChange.delay=50;f.iLightBoxHashChange=$.extend(f.iLightBoxHashChange,{setup:function(){if(m)return!1;$(b.start)},teardown:function(){if(m)return!1;$(b.stop)}});b=function(){function a(){var c=
11425	e(),d=f(l);c!==l?(n(l=c,d),$(window).trigger("iLightBoxHashChange")):d!==l&&(location.href=location.href.replace(/#.*/,"")+d);g=setTimeout(a,$.fn.iLightBoxHashChange.delay)}var h={},g,l=e(),b=function(c){return c},n=b,f=b;h.start=function(){g||a()};h.stop=function(){g&&clearTimeout(g);g=void 0};browser.msie&&!m&&function(){var c,d;h.start=function(){c||(d=(d=$.fn.iLightBoxHashChange.src)&&d+e(),c=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){d||n(e());a()}).attr("src",d||
11426	"javascript:0").insertAfter("body")[0].contentWindow,k.onpropertychange=function(){try{"title"===event.propertyName&&(c.document.title=k.title)}catch(a){}})};h.stop=b;f=function(){return e(c.location.href)};n=function(a,d){var b=c.document,e=$.fn.iLightBoxHashChange.domain;
11426a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
11427
11428	if (!Array.prototype.filter) {
11429		Array.prototype.filter = function(fun /*, thisp */ ) {
11430			"use strict";
11431
11432			if (this == null)
11433				throw new TypeError();
11434
11435			var t = Object(this);
11436			var len = t.length >>> 0;
11437			if (typeof fun != "function")
11438				throw new TypeError();
11439
11440			var res = [];
11441			var thisp = arguments[1];
11442			for (var i = 0; i < len; i++) {
11443				if (i in t) {
11444					var val = t[i]; // in case fun mutates this
11445					if (fun.call(thisp, val, i, t))
11446						res.push(val);
11447				}
11448			}
11449
11450			return res;
11451		};
11452	}
11453
11454	if (!Array.prototype.indexOf) {
11455		Array.prototype.indexOf = function(searchElement, fromIndex) {
11456			var k;
11457
11458			if (this == null) {
11459				throw new TypeError('"this" is null or not defined');
11460			}
11461
11462			var O = Object(this);
11463
11464			var len = O.length >>> 0;
11465
11466			if (len === 0) {
11467				return -1;
11468			}
11469
11470			var n = +fromIndex || 0;
11471
11472			if (abs(n) === Infinity) {
11473				n = 0;
11474			}
11475
11476			if (n >= len) {
11477				return -1;
11478			}
11479
11480			k = max(n >= 0 ? n : len - abs(n), 0);
11481
11482			while (k < len) {
11483				var kValue;
11484				if (k in O && O[k] === searchElement) {
11485					return k;
11486				}
11487				k++;
11488			}
11489			return -1;
11490		};
11491	}
11492
11493	if (!Array.prototype.lastIndexOf) {
11494		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
11495			"use strict";
11496
11497			if (this == null)
11498				throw new TypeError();
11499
11500			var t = Object(this);
11501			var len = t.length >>> 0;
11502			if (len === 0)
11503				return -1;
11504
11505			var n = len;
11506			if (arguments.length > 1) {
11507				n = Number(arguments[1]);
11508				if (n != n)
11509					n = 0;
11510				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
11511					n = (n > 0 || -1) * floor(abs(n));
11512			}
11513
11514			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
11515
11516			for (; k >= 0; k--) {
11517				if (k in t && t[k] === searchElement)
11518					return k;
11519			}
11520			return -1;
11521		};
11522	}
11523})(jQuery, this);
11524
11525/**
11526 * Owl carousel
vendor: 12,108 bytes, lines 11527-12033
11527 * @version 2.0.0-beta.3
11528 * @author Bartosz Wojciechowski
11529 * @license The MIT License (MIT)
11530 * @todo Lazy Load Icon
11531 * @todo prevent animationend bubling
11532 * @todo itemsScaleUp
11533 * @todo Test Zepto
11534 * @todo stagePadding calculate wrong active classes
11535 */
11536;(function($, window, document, undefined) {
11537
11538	/**
11539	 * Creates a carousel.
11540	 * @class The Owl Carousel.
11541	 * @public
11542	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
11543	 * @param {Object} [options] - The options
11544	 */
11545	function Owl(element, options) {
11546
11547		/**
11548		 * Current settings for the carousel.
11549		 * @public
11550		 */
11551		this.settings = null;
11552
11553		/**
11554		 * Current options set by the caller including defaults.
11555		 * @public
11556		 */
11557		this.options = $.extend({}, Owl.Defaults, options);
11558
11559		/**
11560		 * Plugin element.
11561		 * @public
11562		 */
11563		this.$element = $(element);
11564
11565		/**
11566		 * Proxied event handlers.
11567		 * @protected
11568		 */
11569		this._handlers = {};
11570
11571		/**
11572		 * References to the running plugins of this carousel.
11573		 * @protected
11574		 */
11575		this._plugins = {};
11576
11577		/**
11578		 * Currently suppressed events to prevent them from beeing retriggered.
11579		 * @protected
11580		 */
11581		this._supress = {};
11582
11583		/**
11584		 * Absolute current position.
11585		 * @protected
11586		 */
11587		this._current = null;
11588
11589		/**
11590		 * Animation speed in milliseconds.
11591		 * @protected
11592		 */
11593		this._speed = null;
11594
11595		/**
11596		 * Coordinates of all items in pixel.
11597		 * @todo The name of this member is missleading.
11598		 * @protected
11599		 */
11600		this._coordinates = [];
11601
11602		/**
11603		 * Current breakpoint.
11604		 * @todo Real media queries would be nice.
11605		 * @protected
11606		 */
11607		this._breakpoint = null;
11608
11609		/**
11610		 * Current width of the plugin element.
11611		 */
11612		this._width = null;
11613
11614		/**
11615		 * All real items.
11616		 * @protected
11617		 */
11618		this._items = [];
11619
11620		/**
11621		 * All cloned items.
11622		 * @protected
11623		 */
11624		this._clones = [];
11625
11626		/**
11627		 * Merge values of all items.
11628		 * @todo Maybe this could be part of a plugin.
11629		 * @protected
11630		 */
11631		this._mergers = [];
11632
11633		/**
11634		 * Widths of all items.
11635		 */
11636		this._widths = [];
11637
11638		/**
11639		 * Invalidated parts within the update process.
11640		 * @protected
11641		 */
11642		this._invalidated = {};
11643
11644		/**
11645		 * Ordered list of workers for the update process.
11646		 * @protected
11647		 */
11648		this._pipe = [];
11649
11650		/**
11651		 * Current state information for the drag operation.
11652		 * @todo #261
11653		 * @protected
11654		 */
11655		this._drag = {
11656			time: null,
11657			target: null,
11658			pointer: null,
11659			stage: {
11660				start: null,
11661				current: null
11662			},
11663			direction: null
11664		};
11665
11666		/**
11667		 * Current state information and their tags.
11668		 * @type {Object}
11669		 * @protected
11670		 */
11671		this._states = {
11672			current: {},
11673			tags: {
11674				'initializing': [ 'busy' ],
11675				'animating': [ 'busy' ],
11676				'dragging': [ 'interacting' ]
11677			}
11678		};
11679
11680		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
11681			this._handlers[handler] = $.proxy(this[handler], this);
11682		}, this));
11683
11684		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
11685			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
11686				= new plugin(this);
11687		}, this));
11688
11689		$.each(Owl.Workers, $.proxy(function(priority, worker) {
11690			this._pipe.push({
11691				'filter': worker.filter,
11692				'run': $.proxy(worker.run, this)
11693			});
11694		}, this));
11695
11696		this.setup();
11697		this.initialize();
11698	}
11699
11700	/**
11701	 * Default options for the carousel.
11702	 * @public
11703	 */
11704	Owl.Defaults = {
11705		items: 3,
11706		loop: false,
11707		center: false,
11708		rewind: false,
11709
11710		mouseDrag: true,
11711		touchDrag: true,
11712		pullDrag: true,
11713		freeDrag: false,
11714
11715		margin: 0,
11716		stagePadding: 0,
11717
11718		merge: false,
11719		mergeFit: true,
11720		autoWidth: false,
11721
11722		startPosition: 0,
11723		rtl: false,
11724
11725		smartSpeed: 250,
11726		fluidSpeed: false,
11727		dragEndSpeed: false,
11728
11729		responsive: {},
11730		responsiveRefreshRate: 200,
11731		responsiveBaseElement: window,
11732
11733		fallbackEasing: 'swing',
11734
11735		info: false,
11736
11737		nestedItemSelector: false,
11738		itemElement: 'div',
11739		stageElement: 'div',
11740
11741		refreshClass: 'owl-refresh',
11742		loadedClass: 'owl-loaded',
11743		loadingClass: 'owl-loading',
11744		rtlClass: 'owl-rtl',
11745		responsiveClass: 'owl-responsive',
11746		dragClass: 'owl-drag',
11747		itemClass: 'owl-item',
11748		stageClass: 'owl-stage',
11749		stageOuterClass: 'owl-stage-outer',
11750		grabClass: 'owl-grab'
11751	};
11752
11753	/**
11754	 * Enumeration for width.
11755	 * @public
11756	 * @readonly
11757	 * @enum {String}
11758	 */
11759	Owl.Width = {
11760		Default: 'default',
11761		Inner: 'inner',
11762		Outer: 'outer'
11763	};
11764
11765	/**
11766	 * Enumeration for types.
11767	 * @public
11768	 * @readonly
11769	 * @enum {String}
11770	 */
11771	Owl.Type = {
11772		Event: 'event',
11773		State: 'state'
11774	};
11775
11776	/**
11777	 * Contains all registered plugins.
11778	 * @public
11779	 */
11780	Owl.Plugins = {};
11781
11782	/**
11783	 * List of workers involved in the update process.
11784	 */
11785	Owl.Workers = [ {
11786		filter: [ 'width', 'settings' ],
11787		run: function() {
11788			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
11789			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
11790		}
11791	}, {
11792		filter: [ 'width', 'items', 'settings' ],
11793		run: function(cache) {
11794			cache.current = this._items && this._items[this.relative(this._current)];
11795		}
11796	}, {
11797		filter: [ 'items', 'settings' ],
11798		run: function() {
11799			this.$stage.children('.cloned').remove();
11800		}
11801	}, {
11802		filter: [ 'width', 'items', 'settings' ],
11803		run: function(cache) {
11804			var margin = this.settings.margin || '',
11805				grid = !this.settings.autoWidth,
11806				rtl = this.settings.rtl,
11807				css = {
11808					'width': 'auto',
11809					'margin-left': rtl ? margin : '',
11810					'margin-right': rtl ? '' : margin
11811				};
11812
11813			!grid && this.$stage.children().css(css);
11814
11815			cache.css = css;
11816		}
11817	}, {
11818		filter: [ 'width', 'items', 'settings' ],
11819		run: function(cache) {
11820			//UNCODE edit to fix Chrome stage padding issue
11821			var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin),
11822				merge = null,
11823				iterator = this._items.length,
11824				grid = !this.settings.autoWidth,
11825				widths = [];
11826
11827			cache.items = {
11828				merge: false,
11829				width: width
11830			};
11831
11832			while (iterator--) {
11833				merge = this._mergers[iterator];
11834				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
11835
11836				cache.items.merge = merge > 1 || cache.items.merge;
11837
11838				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
11839			}
11840
11841			this._widths = widths;
11842		}
11843	}, {
11844		filter: [ 'items', 'settings' ],
11845		run: function() {
11846			var clones = [],
11847				items = this._items,
11848				settings = this.settings,
11849				view = Math.max(settings.items * 2, 4),
11850				size = Math.ceil(items.length / 2) * 2,
11851				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
11852				append = '',
11853				prepend = '';
11854
11855			repeat /= 2;
11856
11857			while (repeat--) {
11858				clones.push(this.normalize(clones.length / 2, true));
11859				append = append + items[clones[clones.length - 1]][0].outerHTML;
11860				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
11861				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
11862			}
11863
11864			this._clones = clones;
11865
11866			// var appendVideo = $(append).find('.uncode-video-container');
11867			// if (appendVideo.length) {
11868			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
11869			// }
11870			// var prependVideo = $(prepend).find('.uncode-video-container');
11871			// if (prependVideo.length) {
11872			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
11873			// }
11874			$(append).addClass('cloned').appendTo(this.$stage);
11875			$(prepend).addClass('cloned').prependTo(this.$stage);
11876		}
11877	}, {
11878		filter: [ 'width', 'items', 'settings' ],
11879		run: function() {
11880			var rtl = this.settings.rtl ? 1 : -1,
11881				size = this._clones.length + this._items.length,
11882				iterator = -1,
11883				previous = 0,
11884				current = 0,
11885				coordinates = [];
11886
11887			while (++iterator < size) {
11888				previous = coordinates[iterator - 1] || 0;
11889				current = this._widths[this.relative(iterator)] + this.settings.margin;
11890				coordinates.push(previous + current * rtl);
11891			}
11892
11893			this._coordinates = coordinates;
11894		}
11895	}, {
11896		filter: [ 'width', 'items', 'settings' ],
11897		run: function() {
11898			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
11899				padding = stagePadding,
11900				coordinates = this._coordinates,
11901				css = {
11902					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
11903					'padding-left': padding || '',
11904					'padding-right': padding || ''
11905				};
11906
11907			this.$stage.css(css);
11908		}
11909	}, {
11910		filter: [ 'width', 'items', 'settings' ],
11911		run: function(cache) {
11912			var iterator = this._coordinates.length,
11913				grid = !this.settings.autoWidth,
11914				items = this.$stage.children();
11915
11916			if (grid && cache.items.merge) {
11917				while (iterator--) {
11918					cache.css.width = this._widths[this.relative(iterator)];
11919					items.eq(iterator).css(cache.css);
11920				}
11921			} else if (grid) {
11922				cache.css.width = cache.items.width;
11923				items.css(cache.css);
11924			}
11925		}
11926	}, {
11927		filter: [ 'items' ],
11928		run: function() {
11929			this._coordinates.length < 1 && this.$stage.removeAttr('style');
11930		}
11931	}, {
11932		filter: [ 'width', 'items', 'settings' ],
11933		run: function(cache) {
11934			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
11935			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
11936			this.reset(cache.current);
11937		}
11938	}, {
11939		filter: [ 'position' ],
11940		run: function() {
11941			this.animate(this.coordinates(this._current));
11942		}
11943	}, {
11944		filter: [ 'width', 'position', 'items', 'settings' ],
11945		run: function() {
11946			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
11947				rtl = this.settings.rtl ? 1 : -1,
11948				padding = this.settings.stagePadding * 2,
11949				begin = this.coordinates(this.current()) + padding,
11950				end = begin + this.width() * rtl,
11951				inner, outer, matches = [], i, n;
11952
11953			for (i = 0, n = this._coordinates.length; i < n; i++) {
11954				inner = this._coordinates[i - 1] || 0;
11955				outer = Math.abs(this._coordinates[i]) + padding * rtl;
11956
11957				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
11958					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
11959					matches.push(i);
11960				}
11961			}
11962
11963			this.$stage.children('.active').removeClass('active');
11964			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
11965
11966			if (this.settings.center) {
11967				this.$stage.children('.center').removeClass('center');
11968				this.$stage.children().eq(this.current()).addClass('center');
11969			}
11970		}
11971	} ];
11972
11973	/**
11974	 * Initializes the carousel.
11975	 * @protected
11976	 */
11977	Owl.prototype.initialize = function() {
11978		this.enter('initializing');
11979		this.trigger('initialize');
11980
11981		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
11982
11983		if (this.settings.autoWidth && !this.is('pre-loading')) {
11984			var imgs, nestedSelector, width;
11985			imgs = this.$element.find('img');
11986			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
11987			width = this.$element.children(nestedSelector).width();
11988
11989			if (imgs.length && width <= 0) {
11990				this.preloadAutoWidthImages(imgs);
11991			}
11992		}
11993
11994		this.$element.addClass(this.options.loadingClass);
11995
11996		// create stage
11997		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
11998			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
11999
12000		// append stage
12001		this.$element.append(this.$stage.parent());
12002
12003		// append content
12004		this.replace(this.$element.children().not(this.$stage.parent()));
12005
12006		// check visibility
12007		if (this.$element.is(':visible')) {
12008			// update view
12009			this.refresh();
12010		} else {
12011			// invalidate width
12012			this.invalidate('width');
12013		}
12014
12015		this.$element
12016			.removeClass(this.options.loadingClass)
12017			.addClass(this.options.loadedClass);
12018
12019		// register event handlers
12020		this.registerEventHandlers();
12021
12022		this.leave('initializing');
12023		this.trigger('initialized');
12024	};
12025
12026	/**
12027	 * Setups the current settings.
12028	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
12029	 * @todo Support for media queries by using `matchMedia` would be nice.
12030	 * @public
12031	 */
12032	Owl.prototype.setup = function() {
12033		var viewport = this.viewport(),
12034			overwrites = this.options.responsive,
12035			match = -1,
12036			settings = null;
12037
12038		if (!overwrites) {
12039			settings = $.extend({}, this.options);
12040		} else {
12041			$.each(overwrites, function(breakpoint) {
12042				if (breakpoint <= viewport && breakpoint > match) {
12043					match = Number(breakpoint);
12044				}
12045			});
12046
12047			settings = $.extend({}, this.options, overwrites[match]);
12048			delete settings.responsive;
12049
12050			// responsive class
12051			if (settings.responsiveClass) {
12052				this.$element.attr('class',
12053					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
12054				);
12055			}
12056		}
12057
12058		if (this.settings === null || this._breakpoint !== match) {
12059			this.trigger('change', { property: { name: 'settings', value: settings } });
12060			this._breakpoint = match;
12061			this.settings = settings;
12062			this.invalidate('settings');
12063			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
12064		}
12065	};
12066
12067	/**
12068	 * Updates option logic if necessery.
12069	 * @protected
12070	 */
12071	Owl.prototype.optionsLogic = function() {
12072		if (this.settings.autoWidth) {
12073			this.settings.stagePadding = false;
12074			this.settings.merge = false;
12075		}
12076	};
12077
12078	/**
12079	 * Prepares an item before add.
12080	 * @todo Rename event parameter `content` to `item`.
12081	 * @protected
12082	 * @returns {jQuery|HTMLElement} - The item container.
12083	 */
12084	Owl.prototype.prepare = function(item, index) {
12085		var event = this.trigger('prepare', { content: item });
12086		if (!event.data) {
12087			event.data = $('<' + this.settings.itemElement + '/>')
12088				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
12089		}
12090
12091		this.trigger('prepared', { content: event.data });
12092
12093		return event.data;
12094	};
12095
12096	/**
12097	 * Updates the view.
12098	 * @public
12099	 */
12100	Owl.prototype.update = function() {
12101		var i = 0,
12102			n = this._pipe.length,
12103			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
12104			cache = {};
12105
12106		while (i < n) {
12107			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
12108				this._pipe[i].run(cache);
12109			}
12110			i++;
12111		}
12112
12113		this._invalidated = {};
12114
12115		!this.is('valid') && this.enter('valid');
12116	};
12117
12118	/**
12119	 * Gets the width of the view.
12120	 * @public
12121	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
12122	 * @returns {Number} - The width of the view in pixel.
12123	 */
12124	Owl.prototype.width = function(dimension) {
12125		dimension = dimension || Owl.Width.Default;
12126		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
12127		switch (dimension) {
12128			case Owl.Width.Inner:
12129			case Owl.Width.Outer:
12130				return this._width;
12131			default:
12132				return this._width - stagePadding * 2 + this.settings.margin;
12133		}
12134	};
12135
12136	/**
12137	 * Refreshes the carousel primarily for adaptive purposes.
12138	 * @public
12139	 */
12140	Owl.prototype.refresh = function() {
12141		this.enter('refreshing');
12142		this.trigger('refresh');
12143
12144		this.setup();
12145
12146		this.optionsLogic();
12147
12148		this.$element.addClass(this.options.refreshClass);
12149
12150		this.update();
12151
12152		this.$element.removeClass(this.options.refreshClass);
12153
12154		this.leave('refreshing');
12155		this.trigger('refreshed');
12156	};
12157
12158	/**
12159	 * Checks window `resize` event.
12160	 * @protected
12161	 */
12162	Owl.prototype.onThrottledResize = function() {
12163		window.clearTimeout(this.resizeTimer);
12164		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
12165	};
12166
12167	/**
12168	 * Checks window `resize` event.
12169	 * @protected
12170	 */
12171	Owl.prototype.onResize = function() {
12172		if (!this._items.length) {
12173			return false;
12174		}
12175
12176		if (this._width === this.$element.width()) {
12177			return false;
12178		}
12179
12180		if (!this.$element.is(':visible')) {
12181			return false;
12182		}
12183
12184		this.enter('resizing');
12185
12186		if (this.trigger('resize').isDefaultPrevented()) {
12187			this.leave('resizing');
12188			return false;
12189		}
12190
12191		this.invalidate('width');
12192
12193		this.refresh();
12194
12195		this.leave('resizing');
12196		this.trigger('resized');
12197	};
12198
12199	/**
12200	 * Registers event handlers.
12201	 * @todo Check `msPointerEnabled`
12202	 * @todo #261
12203	 * @protected
12204	 */
12205	Owl.prototype.registerEventHandlers = function() {
12206		if ($.support.transition) {
12207			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
12208		}
12209
12210		if (this.settings.responsive !== false) {
12211			this.on(window, 'resize', this._handlers.onThrottledResize);
12212		}
12213
12214		if (this.settings.mouseDrag) {
12215			this.$element.addClass(this.options.dragClass);
12216			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
12217			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
12218		}
12219
12220		if (this.settings.touchDrag){
12221			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
12222			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
12223		}
12224	};
12225
12226	/**
12227	 * Handles `touchstart` and `mousedown` events.
12228	 * @todo Horizontal swipe threshold as option
12229	 * @todo #261
12230	 * @protected
12231	 * @param {Event} event - The event arguments.
12232	 */
12233	Owl.prototype.onDragStart = function(event) {
12234		var stage = null;
12235
12236		if (event.which === 3) {
12237			return;
12238		}
12239
vendor: 9,106 bytes, lines 12240-12555
12240		if ($.support.transform) {
12241			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
12242			stage = {
12243				x: stage[stage.length === 16 ? 12 : 4],
12244				y: stage[stage.length === 16 ? 13 : 5]
12245			};
12246		} else {
12247			stage = this.$stage.position();
12248			stage = {
12249				x: this.settings.rtl ?
12250					stage.left + this.$stage.width() - this.width() + this.settings.margin :
12251					stage.left,
12252				y: stage.top
12253			};
12254		}
12255
12256		if (this.is('animating')) {
12257			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
12258			this.invalidate('position');
12259		}
12260
12261		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
12262
12263		this.speed(0);
12264
12265		this._drag.time = new Date().getTime();
12266		this._drag.target = $(event.target);
12267		this._drag.stage.start = stage;
12268		this._drag.stage.current = stage;
12269		this._drag.pointer = this.pointer(event);
12270
12271		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
12272
12273		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
12274			var delta = this.difference(this._drag.pointer, this.pointer(event));
12275
12276			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
12277
12278			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
12279				return;
12280			}
12281
12282			event.preventDefault();
12283
12284			this.enter('dragging');
12285			this.trigger('drag');
12286		}, this));
12287	};
12288
12289	/**
12290	 * Handles the `touchmove` and `mousemove` events.
12291	 * @todo #261
12292	 * @protected
12293	 * @param {Event} event - The event arguments.
12294	 */
12295	Owl.prototype.onDragMove = function(event) {
12296		var minimum = null,
12297			maximum = null,
12298			pull = null,
12299			delta = this.difference(this._drag.pointer, this.pointer(event)),
12300			stage = this.difference(this._drag.stage.start, delta);
12301
12302		if (!this.is('dragging')) {
12303			return;
12304		}
12305
12306		event.preventDefault();
12307
12308		if (this.settings.loop) {
12309			minimum = this.coordinates(this.minimum());
12310			maximum = this.coordinates(this.maximum() + 1) - minimum;
12311			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
12312		} else {
12313			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
12314			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
12315			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
12316			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
12317		}
12318
12319		this._drag.stage.current = stage;
12320
12321		this.animate(stage.x);
12322	};
12323
12324	/**
12325	 * Handles the `touchend` and `mouseup` events.
12326	 * @todo #261
12327	 * @todo Threshold for click event
12328	 * @protected
12329	 * @param {Event} event - The event arguments.
12330	 */
12331	Owl.prototype.onDragEnd = function(event) {
12332		var delta = this.difference(this._drag.pointer, this.pointer(event)),
12333			stage = this._drag.stage.current,
12334			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
12335
12336		$(document).off('.owl.core');
12337
12338		this.$element.removeClass(this.options.grabClass);
12339
12340		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
12341			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
12342			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
12343			this.invalidate('position');
12344			this.update();
12345
12346			this._drag.direction = direction;
12347
12348			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
12349				this._drag.target.one('click.owl.core', function() { return false; });
12350			}
12351		}
12352
12353		if (!this.is('dragging')) {
12354			return;
12355		}
12356
12357		this.leave('dragging');
12358		this.trigger('dragged');
12359	};
12360
12361	/**
12362	 * Gets absolute position of the closest item for a coordinate.
12363	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
12364	 * @protected
12365	 * @param {Number} coordinate - The coordinate in pixel.
12366	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
12367	 * @return {Number} - The absolute position of the closest item.
12368	 */
12369	Owl.prototype.closest = function(coordinate, direction) {
12370		var position = -1,
12371			pull = 30,
12372			width = this.width(),
12373			coordinates = this.coordinates();
12374
12375		if (!this.settings.freeDrag) {
12376			// check closest item
12377			$.each(coordinates, $.proxy(function(index, value) {
12378				if (coordinate > value - pull && coordinate < value + pull) {
12379					position = index;
12380				} else if (this.op(coordinate, '<', value)
12381					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
12382					position = direction === 'left' ? index + 1 : index;
12383				}
12384				return position === -1;
12385			}, this));
12386		}
12387
12388		if (!this.settings.loop) {
12389			// non loop boundries
12390			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
12391				position = coordinate = this.minimum();
12392			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
12393				position = coordinate = this.maximum();
12394			}
12395		}
12396
12397		return position;
12398	};
12399
12400	/**
12401	 * Animates the stage.
12402	 * @todo #270
12403	 * @public
12404	 * @param {Number} coordinate - The coordinate in pixels.
12405	 */
12406	Owl.prototype.animate = function(coordinate) {
12407		var animate = this.speed() > 0;
12408
12409		this.is('animating') && this.onTransitionEnd();
12410
12411		if (animate) {
12412			this.enter('animating');
12413			this.trigger('translate');
12414		}
12415
12416		if ($.support.transform3d && $.support.transition) {
12417			this.$stage.css({
12418				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
12419				transition: (this.speed() / 1000) + 's'
12420			});
12421		} else if (animate) {
12422			this.$stage.animate({
12423				left: coordinate + 'px'
12424			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
12425		} else {
12426			this.$stage.css({
12427				left: coordinate + 'px'
12428			});
12429		}
12430	};
12431
12432	/**
12433	 * Checks whether the carousel is in a specific state or not.
12434	 * @param {String} state - The state to check.
12435	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
12436	 */
12437	Owl.prototype.is = function(state) {
12438		return this._states.current[state] && this._states.current[state] > 0;
12439	};
12440
12441	/**
12442	 * Sets the absolute position of the current item.
12443	 * @public
12444	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
12445	 * @returns {Number} - The absolute position of the current item.
12446	 */
12447	Owl.prototype.current = function(position) {
12448		if (position === undefined) {
12449			return this._current;
12450		}
12451
12452		if (this._items.length === 0) {
12453			return undefined;
12454		}
12455
12456		position = this.normalize(position);
12457
12458		if (this._current !== position) {
12459			var event = this.trigger('change', { property: { name: 'position', value: position } });
12460
12461			if (event.data !== undefined) {
12462				position = this.normalize(event.data);
12463			}
12464
12465			this._current = position;
12466
12467			this.invalidate('position');
12468
12469			this.trigger('changed', { property: { name: 'position', value: this._current } });
12470		}
12471
12472		return this._current;
12473	};
12474
12475	/**
12476	 * Invalidates the given part of the update routine.
12477	 * @param {String} [part] - The part to invalidate.
12478	 * @returns {Array.<String>} - The invalidated parts.
12479	 */
12480	Owl.prototype.invalidate = function(part) {
12481		if ($.type(part) === 'string') {
12482			this._invalidated[part] = true;
12483			this.is('valid') && this.leave('valid');
12484		}
12485		return $.map(this._invalidated, function(v, i) { return i });
12486	};
12487
12488	/**
12489	 * Resets the absolute position of the current item.
12490	 * @public
12491	 * @param {Number} position - The absolute position of the new item.
12492	 */
12493	Owl.prototype.reset = function(position) {
12494		position = this.normalize(position);
12495
12496		if (position === undefined) {
12497			return;
12498		}
12499
12500		this._speed = 0;
12501		this._current = position;
12502
12503		this.suppress([ 'translate', 'translated' ]);
12504
12505		this.animate(this.coordinates(position));
12506
12507		this.release([ 'translate', 'translated' ]);
12508	};
12509
12510	/**
12511	 * Normalizes an absolute or a relative position of an item.
12512	 * @public
12513	 * @param {Number} position - The absolute or relative position to normalize.
12514	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
12515	 * @returns {Number} - The normalized position.
12516	 */
12517	Owl.prototype.normalize = function(position, relative) {
12518		var n = this._items.length,
12519			m = relative ? 0 : this._clones.length;
12520
12521		if (!$.isNumeric(position) || n < 1) {
12522			position = undefined;
12523		} else if (position < 0 || position >= n + m) {
12524			position = ((position - m / 2) % n + n) % n + m / 2;
12525		}
12526
12527		return position;
12528	};
12529
12530	/**
12531	 * Converts an absolute position of an item into a relative one.
12532	 * @public
12533	 * @param {Number} position - The absolute position to convert.
12534	 * @returns {Number} - The converted position.
12535	 */
12536	Owl.prototype.relative = function(position) {
12537		position -= this._clones.length / 2;
12538		return this.normalize(position, true);
12539	};
12540
12541	/**
12542	 * Gets the maximum position for the current item.
12543	 * @public
12544	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
12545	 * @returns {Number}
12546	 */
12547	Owl.prototype.maximum = function(relative) {
12548		var settings = this.settings,
12549			maximum = this._coordinates.length,
12550			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
12551			i = -1, j;
12552
12553		if (settings.loop) {
12554			maximum = this._clones.length / 2 + this._items.length - 1;
12555		} else if (settings.autoWidth || settings.merge) {
12556			// binary search
12557			while (maximum - i > 1) {
12558				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
12559					? i = j : maximum = j;
12560			}
12561		} else if (settings.center) {
12562			maximum = this._items.length - 1;
12563		} else {
12564			maximum = this._items.length - settings.items;
12565		}
12566
12567		if (relative) {
12568			maximum -= this._clones.length / 2;
12569		}
12570
12571		return Math.max(maximum, 0);
12572	};
12573
12574	/**
12575	 * Gets the minimum position for the current item.
12576	 * @public
12577	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
12578	 * @returns {Number}
12579	 */
12580	Owl.prototype.minimum = function(relative) {
12581		return relative ? 0 : this._clones.length / 2;
12582	};
12583
12584	/**
12585	 * Gets an item at the specified relative position.
12586	 * @public
12587	 * @param {Number} [position] - The relative position of the item.
12588	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
12589	 */
12590	Owl.prototype.items = function(position) {
12591		if (position === undefined) {
12592			return this._items.slice();
12593		}
12594
12595		position = this.normalize(position, true);
12596		return this._items[position];
12597	};
12598
12599	/**
12600	 * Gets an item at the specified relative position.
12601	 * @public
12602	 * @param {Number} [position] - The relative position of the item.
12603	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
12604	 */
12605	Owl.prototype.mergers = function(position) {
12606		if (position === undefined) {
12607			return this._mergers.slice();
12608		}
12609
12610		position = this.normalize(position, true);
12611		return this._mergers[position];
12612	};
12613
12614	/**
12615	 * Gets the absolute positions of clones for an item.
12616	 * @public
12617	 * @param {Number} [position] - The relative position of the item.
12618	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
12619	 */
12620	Owl.prototype.clones = function(position) {
12621		var odd = this._clones.length / 2,
12622			even = odd + this._items.length,
12623			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
12624
12625		if (position === undefined) {
12626			return $.map(this._clones, function(v, i) { return map(i) });
12627		}
12628
12629		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
12630	};
12631
12632	/**
12633	 * Sets the current animation speed.
12634	 * @public
12635	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
12636	 * @returns {Number} - The current animation speed in milliseconds.
12637	 */
12638	Owl.prototype.speed = function(speed) {
12639		if (speed !== undefined) {
12640			this._speed = speed;
12641		}
12642
12643		return this._speed;
12644	};
12645
12646	/**
12647	 * Gets the coordinate of an item.
12648	 * @todo The name of this method is missleanding.
12649	 * @public
12650	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
12651	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
12652	 */
12653	Owl.prototype.coordinates = function(position) {
12654		var coordinate = null;
12655
12656		if (position === undefined) {
12657			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
12658				return this.coordinates(index);
12659			}, this));
12660		}
12661
12662		if (this.settings.center) {
12663			coordinate = this._coordinates[position];
12664			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
12665		} else {
12666			coordinate = this._coordinates[position - 1] || 0;
12667		}
12668
12669		return coordinate;
12670	};
12671
12672	/**
12673	 * Calculates the speed for a translation.
12674	 * @protected
12675	 * @param {Number} from - The absolute position of the start item.
12676	 * @param {Number} to - The absolute position of the target item.
12677	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
12678	 * @returns {Number} - The time in milliseconds for the translation.
12679	 */
12680	Owl.prototype.duration = function(from, to, factor) {
12681		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
12682	};
12683
12684	/**
12685	 * Slides to the specified item.
12686	 * @public
12687	 * @param {Number} position - The position of the item.
12688	 * @param {Number} [speed] - The time in milliseconds for the transition.
12689	 */
12690	Owl.prototype.to = function(position, speed) {
12691		var current = this.current(),
12692			revert = null,
12693			distance = position - this.relative(current),
12694			direction = (distance > 0) - (distance < 0),
12695			items = this._items.length,
12696			minimum = this.minimum(),
12697			maximum = this.maximum();
12698
12699		if (this.settings.loop) {
12700			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
12701				distance += direction * -1 * items;
12702			}
12703
12704			position = current + distance;
12705			revert = ((position - minimum) % items + items) % items + minimum;
12706
12707			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
12708				current = revert - distance;
12709				position = revert;
12710				this.reset(current);
12711			}
12712		} else if (this.settings.rewind) {
12713			maximum += 1;
12714			position = (position % maximum + maximum) % maximum;
12715		} else {
12716			position = Math.max(minimum, Math.min(maximum, position));
12717		}
12718
12719		this.speed(this.duration(current, position, speed));
12720		this.current(position);
12721
12722		if (this.$element.is(':visible')) {
12723			this.update();
12724		}
12725	};
12726
12727	/**
12728	 * Slides to the next item.
12729	 * @public
12730	 * @param {Number}
vendor: 12,284 bytes, lines 12730-13150
12730 [speed] - The time in milliseconds for the transition.
12731	 */
12732	Owl.prototype.next = function(speed) {
12733		speed = speed || false;
12734		this.to(this.relative(this.current()) + 1, speed);
12735	};
12736
12737	/**
12738	 * Slides to the previous item.
12739	 * @public
12740	 * @param {Number} [speed] - The time in milliseconds for the transition.
12741	 */
12742	Owl.prototype.prev = function(speed) {
12743		speed = speed || false;
12744		this.to(this.relative(this.current()) - 1, speed);
12745	};
12746
12747	/**
12748	 * Handles the end of an animation.
12749	 * @protected
12750	 * @param {Event} event - The event arguments.
12751	 */
12752	Owl.prototype.onTransitionEnd = function(event) {
12753
12754		// if css2 animation then event object is undefined
12755		if (event !== undefined) {
12756			event.stopPropagation();
12757
12758			// Catch only owl-stage transitionEnd event
12759			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
12760				return false;
12761			}
12762		}
12763
12764		this.leave('animating');
12765		this.trigger('translated');
12766	};
12767
12768	/**
12769	 * Gets viewport width.
12770	 * @protected
12771	 * @return {Number} - The width in pixel.
12772	 */
12773	Owl.prototype.viewport = function() {
12774		var width;
12775		if (this.options.responsiveBaseElement !== window) {
12776			width = $(this.options.responsiveBaseElement).width();
12777		} else if (window.innerWidth) {
12778			width = window.innerWidth;
12779		} else if (document.documentElement && document.documentElement.clientWidth) {
12780			width = document.documentElement.clientWidth;
12781		} else {
12782			throw 'Can not detect viewport width.';
12783		}
12784
12785		return width;
12786	};
12787
12788	/**
12789	 * Replaces the current content.
12790	 * @public
12791	 * @param {HTMLElement|jQuery|String} content - The new content.
12792	 */
12793	Owl.prototype.replace = function(content) {
12794		this.$stage.empty();
12795		this._items = [];
12796
12797		if (content) {
12798			content = (content instanceof jQuery) ? content : $(content);
12799		}
12800
12801		if (this.settings.nestedItemSelector) {
12802			content = content.find('.' + this.settings.nestedItemSelector);
12803		}
12804
12805		content.filter(function() {
12806			return this.nodeType === 1;
12807		}).each($.proxy(function(index, item) {
12808			item = this.prepare(item, index);
12809			this.$stage.append(item);
12810			this._items.push(item);
12811			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
12812		}, this));
12813
12814		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
12815
12816		this.invalidate('items');
12817	};
12818
12819	/**
12820	 * Adds an item.
12821	 * @todo Use `item` instead of `content` for the event arguments.
12822	 * @public
12823	 * @param {HTMLElement|jQuery|String} content - The item content to add.
12824	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
12825	 */
12826	Owl.prototype.add = function(content, position) {
12827		var current = this.relative(this._current);
12828
12829		position = position === undefined ? this._items.length : this.normalize(position, true);
12830		content = content instanceof jQuery ? content : $(content);
12831
12832		this.trigger('add', { content: content, position: position });
12833
12834		content = this.prepare(content, this._items[current].index());
12835
12836		if (this._items.length === 0 || position === this._items.length) {
12837			this._items.length === 0 && this.$stage.append(content);
12838			this._items.length !== 0 && this._items[position - 1].after(content);
12839			this._items.push(content);
12840			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
12841		} else {
12842			this._items[position].before(content);
12843			this._items.splice(position, 0, content);
12844			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
12845		}
12846
12847		this._items[current] && this.reset(this._items[current].index());
12848
12849		this.invalidate('items');
12850
12851		this.trigger('added', { content: content, position: position });
12852	};
12853
12854	/**
12855	 * Removes an item by its position.
12856	 * @todo Use `item` instead of `content` for the event arguments.
12857	 * @public
12858	 * @param {Number} position - The relative position of the item to remove.
12859	 */
12860	Owl.prototype.remove = function(position) {
12861		position = this.normalize(position, true);
12862
12863		if (position === undefined) {
12864			return;
12865		}
12866
12867		this.trigger('remove', { content: this._items[position], position: position });
12868
12869		this._items[position].remove();
12870		this._items.splice(position, 1);
12871		this._mergers.splice(position, 1);
12872
12873		this.invalidate('items');
12874
12875		this.trigger('removed', { content: null, position: position });
12876	};
12877
12878	/**
12879	 * Preloads images with auto width.
12880	 * @todo Replace by a more generic approach
12881	 * @protected
12882	 */
12883	Owl.prototype.preloadAutoWidthImages = function(images) {
12884		images.each($.proxy(function(i, element) {
12885			this.enter('pre-loading');
12886			element = $(element);
12887			$(new Image()).one('load', $.proxy(function(e) {
12888				element.attr('src', e.target.src);
12889				element.css('opacity', 1);
12890				this.leave('pre-loading');
12891				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
12892			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
12893		}, this));
12894	};
12895
12896	/**
12897	 * Destroys the carousel.
12898	 * @public
12899	 */
12900	Owl.prototype.destroy = function() {
12901
12902		this.$element.off('.owl.core');
12903		this.$stage.off('.owl.core');
12904		$(document).off('.owl.core');
12905
12906		if (this.settings.responsive !== false) {
12907			window.clearTimeout(this.resizeTimer);
12908			this.off(window, 'resize', this._handlers.onThrottledResize);
12909		}
12910
12911		for (var i in this._plugins) {
12912			this._plugins[i].destroy();
12913		}
12914
12915		this.$stage.children('.cloned').remove();
12916
12917		this.$stage.unwrap();
12918		this.$stage.children().contents().unwrap();
12919		this.$stage.children().unwrap();
12920
12921		this.$element
12922			.removeClass(this.options.refreshClass)
12923			.removeClass(this.options.loadingClass)
12924			.removeClass(this.options.loadedClass)
12925			.removeClass(this.options.rtlClass)
12926			.removeClass(this.options.dragClass)
12927			.removeClass(this.options.grabClass)
12928			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
12929			.removeData('owl.carousel');
12930	};
12931
12932	/**
12933	 * Operators to calculate right-to-left and left-to-right.
12934	 * @protected
12935	 * @param {Number} [a] - The left side operand.
12936	 * @param {String} [o] - The operator.
12937	 * @param {Number} [b] - The right side operand.
12938	 */
12939	Owl.prototype.op = function(a, o, b) {
12940		var rtl = this.settings.rtl;
12941		switch (o) {
12942			case '<':
12943				return rtl ? a > b : a < b;
12944			case '>':
12945				return rtl ? a < b : a > b;
12946			case '>=':
12947				return rtl ? a <= b : a >= b;
12948			case '<=':
12949				return rtl ? a >= b : a <= b;
12950			default:
12951				break;
12952		}
12953	};
12954
12955	/**
12956	 * Attaches to an internal event.
12957	 * @protected
12958	 * @param {HTMLElement} element - The event source.
12959	 * @param {String} event - The event name.
12960	 * @param {Function} listener - The event handler to attach.
12961	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
12962	 */
12963	Owl.prototype.on = function(element, event, listener, capture) {
12964		if (element.addEventListener) {
12965			element.addEventListener(event, listener, capture);
12966		} else if (element.attachEvent) {
12967			element.attachEvent('on' + event, listener);
12968		}
12969	};
12970
12971	/**
12972	 * Detaches from an internal event.
12973	 * @protected
12974	 * @param {HTMLElement} element - The event source.
12975	 * @param {String} event - The event name.
12976	 * @param {Function} listener - The attached event handler to detach.
12977	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
12978	 */
12979	Owl.prototype.off = function(element, event, listener, capture) {
12980		if (element.removeEventListener) {
12981			element.removeEventListener(event, listener, capture);
12982		} else if (element.detachEvent) {
12983			element.detachEvent('on' + event, listener);
12984		}
12985	};
12986
12987	/**
12988	 * Triggers a public event.
12989	 * @todo Remove `status`, `relatedTarget` should be used instead.
12990	 * @protected
12991	 * @param {String} name - The event name.
12992	 * @param {*} [data=null] - The event data.
12993	 * @param {String} [namespace=carousel] - The event namespace.
12994	 * @param {String} [state] - The state which is associated with the event.
12995	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
12996	 * @returns {Event} - The event arguments.
12997	 */
12998	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
12999		var status = {
13000			item: { count: this._items.length, index: this.current() }
13001		}, handler = $.camelCase(
13002			$.grep([ 'on', name, namespace ], function(v) { return v })
13003				.join('-').toLowerCase()
13004		), event = $.Event(
13005			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
13006			$.extend({ relatedTarget: this }, status, data)
13007		);
13008
13009		if (!this._supress[name]) {
13010			$.each(this._plugins, function(name, plugin) {
13011				if (plugin.onTrigger) {
13012					plugin.onTrigger(event);
13013				}
13014			});
13015
13016			this.register({ type: Owl.Type.Event, name: name });
13017			this.$element.trigger(event);
13018
13019			if (this.settings && typeof this.settings[handler] === 'function') {
13020				this.settings[handler].call(this, event);
13021			}
13022		}
13023
13024		return event;
13025	};
13026
13027	/**
13028	 * Enters a state.
13029	 * @param name - The state name.
13030	 */
13031	Owl.prototype.enter = function(name) {
13032		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
13033			if (this._states.current[name] === undefined) {
13034				this._states.current[name] = 0;
13035			}
13036
13037			this._states.current[name]++;
13038		}, this));
13039	};
13040
13041	/**
13042	 * Leaves a state.
13043	 * @param name - The state name.
13044	 */
13045	Owl.prototype.leave = function(name) {
13046		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
13047			this._states.current[name]--;
13048		}, this));
13049	};
13050
13051	/**
13052	 * Registers an event or state.
13053	 * @public
13054	 * @param {Object} object - The event or state to register.
13055	 */
13056	Owl.prototype.register = function(object) {
13057		if (object.type === Owl.Type.Event) {
13058			if (!$.event.special[object.name]) {
13059				$.event.special[object.name] = {};
13060			}
13061
13062			if (!$.event.special[object.name].owl) {
13063				var _default = $.event.special[object.name]._default;
13064				$.event.special[object.name]._default = function(e) {
13065					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
13066						return _default.apply(this, arguments);
13067					}
13068					return e.namespace && e.namespace.indexOf('owl') > -1;
13069				};
13070				$.event.special[object.name].owl = true;
13071			}
13072		} else if (object.type === Owl.Type.State) {
13073			if (!this._states.tags[object.name]) {
13074				this._states.tags[object.name] = object.tags;
13075			} else {
13076				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
13077			}
13078
13079			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
13080				return $.inArray(tag, this._states.tags[object.name]) === i;
13081			}, this));
13082		}
13083	};
13084
13085	/**
13086	 * Suppresses events.
13087	 * @protected
13088	 * @param {Array.<String>} events - The events to suppress.
13089	 */
13090	Owl.prototype.suppress = function(events) {
13091		$.each(events, $.proxy(function(index, event) {
13092			this._supress[event] = true;
13093		}, this));
13094	};
13095
13096	/**
13097	 * Releases suppressed events.
13098	 * @protected
13099	 * @param {Array.<String>} events - The events to release.
13100	 */
13101	Owl.prototype.release = function(events) {
13102		$.each(events, $.proxy(function(index, event) {
13103			delete this._supress[event];
13104		}, this));
13105	};
13106
13107	/**
13108	 * Gets unified pointer coordinates from event.
13109	 * @todo #261
13110	 * @protected
13111	 * @param {Event} - The `mousedown` or `touchstart` event.
13112	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
13113	 */
13114	Owl.prototype.pointer = function(event) {
13115		var result = { x: null, y: null };
13116
13117		event = event.originalEvent || event || window.event;
13118
13119		event = event.touches && event.touches.length ?
13120			event.touches[0] : event.changedTouches && event.changedTouches.length ?
13121				event.changedTouches[0] : event;
13122
13123		if (event.pageX) {
13124			result.x = event.pageX;
13125			result.y = event.pageY;
13126		} else {
13127			result.x = event.clientX;
13128			result.y = event.clientY;
13129		}
13130
13131		return result;
13132	};
13133
13134	/**
13135	 * Gets the difference of two vectors.
13136	 * @todo #261
13137	 * @protected
13138	 * @param {Object} - The first vector.
13139	 * @param {Object} - The second vector.
13140	 * @returns {Object} - The difference.
13141	 */
13142	Owl.prototype.difference = function(first, second) {
13143		return {
13144			x: first.x - second.x,
13145			y: first.y - second.y
13146		};
13147	};
13148
13149	/**
13150	 * The jQuery Plugin for the Owl Carousel
vendor: 32,216 bytes, lines 13151-14433
13151	 * @todo Navigation plugin `next` and `prev`
13152	 * @public
13153	 */
13154	$.fn.owlCarousel = function(option) {
13155		var args = Array.prototype.slice.call(arguments, 1);
13156
13157		return this.each(function() {
13158			var $this = $(this),
13159				data = $this.data('owl.carousel');
13160
13161			if (!data) {
13162				data = new Owl(this, typeof option == 'object' && option);
13163				$this.data('owl.carousel', data);
13164
13165				$.each([
13166					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
13167				], function(i, event) {
13168					data.register({ type: Owl.Type.Event, name: event });
13169					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
13170						if (e.namespace && e.relatedTarget !== this) {
13171							this.suppress([ event ]);
13172							data[event].apply(this, [].slice.call(arguments, 1));
13173							this.release([ event ]);
13174						}
13175					}, data));
13176				});
13177			}
13178
13179			if (typeof option == 'string' && option.charAt(0) !== '_') {
13180				data[option].apply(data, args);
13181			}
13182		});
13183	};
13184
13185	/**
13186	 * The constructor for the jQuery Plugin
13187	 * @public
13188	 */
13189	$.fn.owlCarousel.Constructor = Owl;
13190
13191})(window.Zepto || window.jQuery, window, document);
13192
13193/**
13194 * AutoRefresh Plugin
13195 * @version 2.0.0-beta.3
13196 * @author Artus Kolanowski
13197 * @license The MIT License (MIT)
13198 */
13199;(function($, window, document, undefined) {
13200
13201	/**
13202	 * Creates the auto refresh plugin.
13203	 * @class The Auto Refresh Plugin
13204	 * @param {Owl} carousel - The Owl Carousel
13205	 */
13206	var AutoRefresh = function(carousel) {
13207		/**
13208		 * Reference to the core.
13209		 * @protected
13210		 * @type {Owl}
13211		 */
13212		this._core = carousel;
13213
13214		/**
13215		 * Refresh interval.
13216		 * @protected
13217		 * @type {number}
13218		 */
13219		this._interval = null;
13220
13221		/**
13222		 * Whether the element is currently visible or not.
13223		 * @protected
13224		 * @type {Boolean}
13225		 */
13226		this._visible = null;
13227
13228		/**
13229		 * All event handlers.
13230		 * @protected
13231		 * @type {Object}
13232		 */
13233		this._handlers = {
13234			'initialized.owl.carousel': $.proxy(function(e) {
13235				if (e.namespace && this._core.settings.autoRefresh) {
13236					this.watch();
13237				}
13238			}, this)
13239		};
13240
13241		// set default options
13242		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
13243
13244		// register event handlers
13245		this._core.$element.on(this._handlers);
13246	};
13247
13248	/**
13249	 * Default options.
13250	 * @public
13251	 */
13252	AutoRefresh.Defaults = {
13253		autoRefresh: true,
13254		autoRefreshInterval: 500
13255	};
13256
13257	/**
13258	 * Watches the element.
13259	 */
13260	AutoRefresh.prototype.watch = function() {
13261		if (this._interval) {
13262			return;
13263		}
13264
13265		this._visible = this._core.$element.is(':visible');
13266		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
13267	};
13268
13269	/**
13270	 * Refreshes the element.
13271	 */
13272	AutoRefresh.prototype.refresh = function() {
13273		if (this._core.$element.is(':visible') === this._visible) {
13274			return;
13275		}
13276
13277		this._visible = !this._visible;
13278
13279		this._core.$element.toggleClass('owl-hidden', !this._visible);
13280
13281		this._visible && (this._core.invalidate('width') && this._core.refresh());
13282	};
13283
13284	/**
13285	 * Destroys the plugin.
13286	 */
13287	AutoRefresh.prototype.destroy = function() {
13288		var handler, property;
13289
13290		window.clearInterval(this._interval);
13291
13292		for (handler in this._handlers) {
13293			this._core.$element.off(handler, this._handlers[handler]);
13294		}
13295		for (property in Object.getOwnPropertyNames(this)) {
13296			typeof this[property] != 'function' && (this[property] = null);
13297		}
13298	};
13299
13300	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
13301
13302})(window.Zepto || window.jQuery, window, document);
13303
13304/**
13305 * Lazy Plugin
13306 * @version 2.0.0-beta.3
13307 * @author Bartosz Wojciechowski
13308 * @license The MIT License (MIT)
13309 */
13310;(function($, window, document, undefined) {
13311
13312	/**
13313	 * Creates the lazy plugin.
13314	 * @class The Lazy Plugin
13315	 * @param {Owl} carousel - The Owl Carousel
13316	 */
13317	var Lazy = function(carousel) {
13318
13319		/**
13320		 * Reference to the core.
13321		 * @protected
13322		 * @type {Owl}
13323		 */
13324		this._core = carousel;
13325
13326		/**
13327		 * Already loaded items.
13328		 * @protected
13329		 * @type {Array.<jQuery>}
13330		 */
13331		this._loaded = [];
13332
13333		/**
13334		 * Event handlers.
13335		 * @protected
13336		 * @type {Object}
13337		 */
13338		this._handlers = {
13339			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
13340				if (!e.namespace) {
13341					return;
13342				}
13343
13344				if (!this._core.settings || !this._core.settings.lazyLoad) {
13345					return;
13346				}
13347
13348				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
13349					var settings = this._core.settings,
13350						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
13351						i = ((settings.center && n * -1) || 0),
13352						position = ((e.property && e.property.value) || this._core.current()) + i,
13353						clones = this._core.clones().length,
13354						load = $.proxy(function(i, v) { this.load(v) }, this);
13355
13356					while (i++ < n) {
13357						this.load(clones / 2 + this._core.relative(position));
13358						clones && $.each(this._core.clones(this._core.relative(position)), load);
13359						position++;
13360					}
13361				}
13362			}, this)
13363		};
13364
13365		// set the default options
13366		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
13367
13368		// register event handler
13369		this._core.$element.on(this._handlers);
13370	}
13371
13372	/**
13373	 * Default options.
13374	 * @public
13375	 */
13376	Lazy.Defaults = {
13377		lazyLoad: false
13378	}
13379
13380	/**
13381	 * Loads all resources of an item at the specified position.
13382	 * @param {Number} position - The absolute position of the item.
13383	 * @protected
13384	 */
13385	Lazy.prototype.load = function(position) {
13386		var $item = this._core.$stage.children().eq(position),
13387			$elements = $item && $item.find('.owl-lazy');
13388
13389		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
13390			return;
13391		}
13392
13393		$elements.each($.proxy(function(index, element) {
13394			var $element = $(element), image,
13395				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
13396
13397			this._core.trigger('load', { element: $element, url: url }, 'lazy');
13398
13399			if ($element.is('img')) {
13400				$element.one('load.owl.lazy', $.proxy(function() {
13401					$element.css('opacity', 1);
13402					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
13403				}, this)).attr('src', url);
13404			} else {
13405				image = new Image();
13406				image.onload = $.proxy(function() {
13407					$element.css({
13408						'background-image': 'url(' + url + ')',
13409						'opacity': '1'
13410					});
13411					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
13412				}, this);
13413				image.src = url;
13414			}
13415		}, this));
13416
13417		this._loaded.push($item.get(0));
13418	}
13419
13420	/**
13421	 * Destroys the plugin.
13422	 * @public
13423	 */
13424	Lazy.prototype.destroy = function() {
13425		var handler, property;
13426
13427		for (handler in this.handlers) {
13428			this._core.$element.off(handler, this.handlers[handler]);
13429		}
13430		for (property in Object.getOwnPropertyNames(this)) {
13431			typeof this[property] != 'function' && (this[property] = null);
13432		}
13433	};
13434
13435	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
13436
13437})(window.Zepto || window.jQuery, window, document);
13438
13439/**
13440 * AutoHeight Plugin
13441 * @version 2.0.0-beta.3
13442 * @author Bartosz Wojciechowski
13443 * @license The MIT License (MIT)
13444 */
13445;(function($, window, document, undefined) {
13446
13447	/**
13448	 * Creates the auto height plugin.
13449	 * @class The Auto Height Plugin
13450	 * @param {Owl} carousel - The Owl Carousel
13451	 */
13452	var AutoHeight = function(carousel) {
13453		/**
13454		 * Reference to the core.
13455		 * @protected
13456		 * @type {Owl}
13457		 */
13458		this._core = carousel;
13459
13460		/**
13461		 * All event handlers.
13462		 * @protected
13463		 * @type {Object}
13464		 */
13465		this._handlers = {
13466			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
13467				if (e.namespace && this._core.settings.autoHeight) {
13468					this.update();
13469				}
13470			}, this),
13471			'changed.owl.carousel': $.proxy(function(e) {
13472				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
13473					this.update();
13474				}
13475			}, this),
13476			'loaded.owl.lazy': $.proxy(function(e) {
13477				if (e.namespace && this._core.settings.autoHeight
13478					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
13479					this.update();
13480				}
13481			}, this)
13482		};
13483
13484		// set default options
13485		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
13486
13487		// register event handlers
13488		this._core.$element.on(this._handlers);
13489	};
13490
13491	/**
13492	 * Default options.
13493	 * @public
13494	 */
13495	AutoHeight.Defaults = {
13496		autoHeight: false,
13497		autoHeightClass: 'owl-height'
13498	};
13499
13500	/**
13501	 * Updates the view.
13502	 */
13503	AutoHeight.prototype.update = function() {
13504		var start = this._core._current,
13505			end = start + this._core.settings.items,
13506			visible = this._core.$stage.children().toArray().slice(start, end);
13507			heights = [],
13508			maxheight = 0;
13509
13510		$.each(visible, function(index, item) {
13511			heights.push($(item).height());
13512		});
13513
13514		maxheight = Math.max.apply(null, heights);
13515
13516		this._core.$stage.parent()
13517			.height(maxheight)
13518			.addClass(this._core.settings.autoHeightClass);
13519	};
13520
13521	AutoHeight.prototype.destroy = function() {
13522		var handler, property;
13523
13524		for (handler in this._handlers) {
13525			this._core.$element.off(handler, this._handlers[handler]);
13526		}
13527		for (property in Object.getOwnPropertyNames(this)) {
13528			typeof this[property] != 'function' && (this[property] = null);
13529		}
13530	};
13531
13532	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
13533
13534})(window.Zepto || window.jQuery, window, document);
13535
13536/**
13537 * Video Plugin
13538 * @version 2.0.0-beta.3
13539 * @author Bartosz Wojciechowski
13540 * @license The MIT License (MIT)
13541 */
13542;(function($, window, document, undefined) {
13543
13544	/**
13545	 * Creates the video plugin.
13546	 * @class The Video Plugin
13547	 * @param {Owl} carousel - The Owl Carousel
13548	 */
13549	var Video = function(carousel) {
13550		/**
13551		 * Reference to the core.
13552		 * @protected
13553		 * @type {Owl}
13554		 */
13555		this._core = carousel;
13556
13557		/**
13558		 * Cache all video URLs.
13559		 * @protected
13560		 * @type {Object}
13561		 */
13562		this._videos = {};
13563
13564		/**
13565		 * Current playing item.
13566		 * @protected
13567		 * @type {jQuery}
13568		 */
13569		this._playing = null;
13570
13571		/**
13572		 * All event handlers.
13573		 * @todo The cloned content removale is too late
13574		 * @protected
13575		 * @type {Object}
13576		 */
13577		this._handlers = {
13578			'initialized.owl.carousel': $.proxy(function(e) {
13579				if (e.namespace) {
13580					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
13581				}
13582			}, this),
13583			'resize.owl.carousel': $.proxy(function(e) {
13584				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
13585					e.preventDefault();
13586				}
13587			}, this),
13588			'refreshed.owl.carousel': $.proxy(function(e) {
13589				if (e.namespace && this._core.is('resizing')) {
13590					this._core.$stage.find('.cloned .owl-video-frame').remove();
13591				}
13592			}, this),
13593			'changed.owl.carousel': $.proxy(function(e) {
13594				if (e.namespace && e.property.name === 'position' && this._playing) {
13595					this.stop();
13596				}
13597			}, this),
13598			'prepared.owl.carousel': $.proxy(function(e) {
13599				if (!e.namespace) {
13600					return;
13601				}
13602
13603				var $element = $(e.content).find('.owl-video');
13604
13605				if ($element.length) {
13606					$element.css('display', 'none');
13607					this.fetch($element, $(e.content));
13608				}
13609			}, this)
13610		};
13611
13612		// set default options
13613		this._core.options = $.extend({}, Video.Defaults, this._core.options);
13614
13615		// register event handlers
13616		this._core.$element.on(this._handlers);
13617
13618		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
13619			this.play(e);
13620		}, this));
13621	};
13622
13623	/**
13624	 * Default options.
13625	 * @public
13626	 */
13627	Video.Defaults = {
13628		video: false,
13629		videoHeight: false,
13630		videoWidth: false
13631	};
13632
13633	/**
13634	 * Gets the video ID and the type (YouTube/Vimeo only).
13635	 * @protected
13636	 * @param {jQuery} target - The target containing the video data.
13637	 * @param {jQuery} item - The item containing the video.
13638	 */
13639	Video.prototype.fetch = function(target, item) {
13640		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
13641			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
13642			width = target.attr('data-width') || this._core.settings.videoWidth,
13643			height = target.attr('data-height') || this._core.settings.videoHeight,
13644			url = target.attr('href');
13645
13646		if (url) {
13647			id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
13648
13649			if (id[3].indexOf('youtu') > -1) {
13650				type = 'youtube';
13651			} else if (id[3].indexOf('vimeo') > -1) {
13652				type = 'vimeo';
13653			} else {
13654				throw new Error('Video URL not supported.');
13655			}
13656			id = id[6];
13657		} else {
13658			throw new Error('Missing video URL.');
13659		}
13660
13661		this._videos[url] = {
13662			type: type,
13663			id: id,
13664			width: width,
13665			height: height
13666		};
13667
13668		item.attr('data-video', url);
13669
13670		this.thumbnail(target, this._videos[url]);
13671	};
13672
13673	/**
13674	 * Creates video thumbnail.
13675	 * @protected
13676	 * @param {jQuery} target - The target containing the video data.
13677	 * @param {Object} info - The video info object.
13678	 * @see `fetch`
13679	 */
13680	Video.prototype.thumbnail = function(target, video) {
13681		var tnLink,
13682			icon,
13683			path,
13684			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
13685			customTn = target.find('img'),
13686			srcType = 'src',
13687			lazyClass = '',
13688			settings = this._core.settings,
13689			create = function(path) {
13690				icon = '<div class="owl-video-play-icon"></div>';
13691
13692				if (settings.lazyLoad) {
13693					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
13694				} else {
13695					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
13696				}
13697				target.after(tnLink);
13698				target.after(icon);
13699			};
13700
13701		// wrap video content into owl-video-wrapper div
13702		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
13703
13704		if (this._core.settings.lazyLoad) {
13705			srcType = 'data-src';
13706			lazyClass = 'owl-lazy';
13707		}
13708
13709		// custom thumbnail
13710		if (customTn.length) {
13711			create(customTn.attr(srcType));
13712			customTn.remove();
13713			return false;
13714		}
13715
13716		if (video.type === 'youtube') {
13717			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
13718			create(path);
13719		} else if (video.type === 'vimeo') {
13720			$.ajax({
13721				type: 'GET',
13722				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
13723				jsonp: 'callback',
13724				dataType: 'jsonp',
13725				success: function(data) {
13726					path = data[0].thumbnail_large;
13727					create(path);
13728				}
13729			});
13730		}
13731	};
13732
13733	/**
13734	 * Stops the current video.
13735	 * @public
13736	 */
13737	Video.prototype.stop = function() {
13738		this._core.trigger('stop', null, 'video');
13739		this._playing.find('.owl-video-frame').remove();
13740		this._playing.removeClass('owl-video-playing');
13741		this._playing = null;
13742		this._core.leave('playing');
13743		this._core.trigger('stopped', null, 'video');
13744	};
13745
13746	/**
13747	 * Starts the current video.
13748	 * @public
13749	 * @param {Event} event - The event arguments.
13750	 */
13751	Video.prototype.play = function(event) {
13752		var target = $(event.target),
13753			item = target.closest('.' + this._core.settings.itemClass),
13754			video = this._videos[item.attr('data-video')],
13755			width = video.width || '100%',
13756			height = video.height || this._core.$stage.height(),
13757			html;
13758
13759		if (this._playing) {
13760			return;
13761		}
13762
13763		this._core.enter('playing');
13764		this._core.trigger('play', null, 'video');
13765
13766		item = this._core.items(this._core.relative(item.index()));
13767
13768		this._core.reset(item.index());
13769
13770		if (video.type === 'youtube') {
13771			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
13772				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
13773		} else if (video.type === 'vimeo') {
13774			html = '<iframe src="//player.vimeo.com/video/' + video.id +
13775				'?autoplay=1" width="' + width + '" height="' + height +
13776				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
13777		}
13778
13779		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
13780
13781		this._playing = item.addClass('owl-video-playing');
13782	};
13783
13784	/**
13785	 * Checks whether an video is currently in full screen mode or not.
13786	 * @todo Bad style because looks like a readonly method but changes members.
13787	 * @protected
13788	 * @returns {Boolean}
13789	 */
13790	Video.prototype.isInFullScreen = function() {
13791		var element = document.fullscreenElement || document.mozFullScreenElement ||
13792				document.webkitFullscreenElement;
13793
13794		return element && $(element).parent().hasClass('owl-video-frame');
13795	};
13796
13797	/**
13798	 * Destroys the plugin.
13799	 */
13800	Video.prototype.destroy = function() {
13801		var handler, property;
13802
13803		this._core.$element.off('click.owl.video');
13804
13805		for (handler in this._handlers) {
13806			this._core.$element.off(handler, this._handlers[handler]);
13807		}
13808		for (property in Object.getOwnPropertyNames(this)) {
13809			typeof this[property] != 'function' && (this[property] = null);
13810		}
13811	};
13812
13813	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
13814
13815})(window.Zepto || window.jQuery, window, document);
13816
13817/**
13818 * Animate Plugin
13819 * @version 2.0.0-beta.3
13820 * @author Bartosz Wojciechowski
13821 * @license The MIT License (MIT)
13822 */
13823;(function($, window, document, undefined) {
13824
13825	/**
13826	 * Creates the animate plugin.
13827	 * @class The Navigation Plugin
13828	 * @param {Owl} scope - The Owl Carousel
13829	 */
13830	var Animate = function(scope) {
13831		this.core = scope;
13832		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
13833		this.swapping = true;
13834		this.previous = undefined;
13835		this.next = undefined;
13836
13837		this.handlers = {
13838			'change.owl.carousel': $.proxy(function(e) {
13839				if (e.namespace && e.property.name == 'position') {
13840					this.previous = this.core.current();
13841					this.next = e.property.value;
13842				}
13843			}, this),
13844			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
13845				if (e.namespace) {
13846					this.swapping = e.type == 'translated';
13847				}
13848			}, this),
13849			'translate.owl.carousel': $.proxy(function(e) {
13850				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
13851					this.swap();
13852				}
13853			}, this)
13854		};
13855
13856		this.core.$element.on(this.handlers);
13857	};
13858
13859	/**
13860	 * Default options.
13861	 * @public
13862	 */
13863	Animate.Defaults = {
13864		animateOut: false,
13865		animateIn: false
13866	};
13867
13868	/**
13869	 * Toggles the animation classes whenever an translations starts.
13870	 * @protected
13871	 * @returns {Boolean|undefined}
13872	 */
13873	Animate.prototype.swap = function() {
13874
13875		if (this.core.settings.items !== 1) {
13876			return;
13877		}
13878
13879		if (!$.support.animation || !$.support.transition) {
13880			return;
13881		}
13882
13883		this.core.speed(0);
13884
13885		var left,
13886			clear = $.proxy(this.clear, this),
13887			previous = this.core.$stage.children().eq(this.previous),
13888			next = this.core.$stage.children().eq(this.next),
13889			incoming = this.core.settings.animateIn,
13890			outgoing = this.core.settings.animateOut;
13891
13892		if (this.core.current() === this.previous) {
13893			return;
13894		}
13895
13896		if (outgoing) {
13897			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
13898			previous.css( { 'left': left + 'px' } )
13899				.addClass('animated owl-animated-out')
13900				.addClass(outgoing)
13901				.on($.support.animation.end, clear);
13902		}
13903
13904		if (incoming) {
13905			next.addClass('animated owl-animated-in')
13906				.addClass(incoming)
13907				.on($.support.animation.end, clear);
13908		}
13909	};
13910
13911	Animate.prototype.clear = function(e) {
13912		if ($(e.target).hasClass('animated')) {
13913			$(e.target).css( { 'left': '' } )
13914				.removeClass('animated owl-animated-out owl-animated-in')
13915				.removeClass(this.core.settings.animateIn)
13916				.removeClass(this.core.settings.animateOut);
13917			this.core.onTransitionEnd();
13918		}
13919	};
13920
13921	/**
13922	 * Destroys the plugin.
13923	 * @public
13924	 */
13925	Animate.prototype.destroy = function() {
13926		var handler, property;
13927
13928		for (handler in this.handlers) {
13929			this.core.$element.off(handler, this.handlers[handler]);
13930		}
13931		for (property in Object.getOwnPropertyNames(this)) {
13932			typeof this[property] != 'function' && (this[property] = null);
13933		}
13934	};
13935
13936	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
13937
13938})(window.Zepto || window.jQuery, window, document);
13939
13940/**
13941 * Autoplay Plugin
13942 * @version 2.0.0-beta.3
13943 * @author Bartosz Wojciechowski
13944 * @author Artus Kolanowski
13945 * @license The MIT License (MIT)
13946 */
13947;(function($, window, document, undefined) {
13948
13949	/**
13950	 * Creates the autoplay plugin.
13951	 * @class The Autoplay Plugin
13952	 * @param {Owl} scope - The Owl Carousel
13953	 */
13954	var Autoplay = function(carousel) {
13955		/**
13956		 * Reference to the core.
13957		 * @protected
13958		 * @type {Owl}
13959		 */
13960		this._core = carousel;
13961
13962		/**
13963		 * The autoplay interval.
13964		 * @type {Number}
13965		 */
13966		this._interval = null;
13967
13968		/**
13969		 * Indicates whenever the autoplay is paused.
13970		 * @type {Boolean}
13971		 */
13972		this._paused = false;
13973
13974		/**
13975		 * All event handlers.
13976		 * @protected
13977		 * @type {Object}
13978		 */
13979		this._handlers = {
13980			'changed.owl.carousel': $.proxy(function(e) {
13981				if (e.namespace && e.property.name === 'settings') {
13982					if (this._core.settings.autoplay) {
13983						this.play();
13984					} else {
13985						this.stop();
13986					}
13987				}
13988			}, this),
13989			'initialized.owl.carousel': $.proxy(function(e) {
13990				if (e.namespace && this._core.settings.autoplay) {
13991					this.play();
13992				}
13993			}, this),
13994			'play.owl.autoplay': $.proxy(function(e, t, s) {
13995				if (e.namespace) {
13996					this.play(t, s);
13997				}
13998			}, this),
13999			'stop.owl.autoplay': $.proxy(function(e) {
14000				if (e.namespace) {
14001					this.stop();
14002				}
14003			}, this),
14004			'mouseover.owl.autoplay': $.proxy(function() {
14005				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
14006					this.pause();
14007				}
14008			}, this),
14009			'mouseleave.owl.autoplay': $.proxy(function() {
14010				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
14011					this.play();
14012				}
14013			}, this)
14014		};
14015
14016		// register event handlers
14017		this._core.$element.on(this._handlers);
14018
14019		// set default options
14020		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
14021	};
14022
14023	/**
14024	 * Default options.
14025	 * @public
14026	 */
14027	Autoplay.Defaults = {
14028		autoplay: false,
14029		autoplayTimeout: 5000,
14030		autoplayHoverPause: false,
14031		autoplaySpeed: false
14032	};
14033
14034	/**
14035	 * Starts the autoplay.
14036	 * @public
14037	 * @param {Number} [timeout] - The interval before the next animation starts.
14038	 * @param {Number} [speed] - The animation speed for the animations.
14039	 */
14040	Autoplay.prototype.play = function(timeout, speed) {
14041		this._paused = false;
14042
14043		if (this._core.is('rotating')) {
14044			return;
14045		}
14046
14047		this._core.enter('rotating');
14048
14049		this._interval = window.setInterval($.proxy(function() {
14050			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
14051				return;
14052			}
14053			this._core.next(speed || this._core.settings.autoplaySpeed);
14054		}, this), timeout || this._core.settings.autoplayTimeout);
14055	};
14056
14057	/**
14058	 * Stops the autoplay.
14059	 * @public
14060	 */
14061	Autoplay.prototype.stop = function() {
14062		if (!this._core.is('rotating')) {
14063			return;
14064		}
14065
14066		window.clearInterval(this._interval);
14067		this._core.leave('rotating');
14068	};
14069
14070	/**
14071	 * Stops the autoplay.
14072	 * @public
14073	 */
14074	Autoplay.prototype.pause = function() {
14075		if (!this._core.is('rotating')) {
14076			return;
14077		}
14078
14079		this._paused = true;
14080	};
14081
14082	/**
14083	 * Destroys the plugin.
14084	 */
14085	Autoplay.prototype.destroy = function() {
14086		var handler, property;
14087
14088		this.stop();
14089
14090		for (handler in this._handlers) {
14091			this._core.$element.off(handler, this._handlers[handler]);
14092		}
14093		for (property in Object.getOwnPropertyNames(this)) {
14094			typeof this[property] != 'function' && (this[property] = null);
14095		}
14096	};
14097
14098	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
14099
14100})(window.Zepto || window.jQuery, window, document);
14101
14102/**
14103 * Navigation Plugin
14104 * @version 2.0.0-beta.3
14105 * @author Artus Kolanowski
14106 * @license The MIT License (MIT)
14107 */
14108;(function($, window, document, undefined) {
14109	'use strict';
14110
14111	/**
14112	 * Creates the navigation plugin.
14113	 * @class The Navigation Plugin
14114	 * @param {Owl} carousel - The Owl Carousel.
14115	 */
14116	var Navigation = function(carousel) {
14117		/**
14118		 * Reference to the core.
14119		 * @protected
14120		 * @type {Owl}
14121		 */
14122		this._core = carousel;
14123
14124		/**
14125		 * Indicates whether the plugin is initialized or not.
14126		 * @protected
14127		 * @type {Boolean}
14128		 */
14129		this._initialized = false;
14130
14131		/**
14132		 * The current paging indexes.
14133		 * @protected
14134		 * @type {Array}
14135		 */
14136		this._pages = [];
14137
14138		/**
14139		 * All DOM elements of the user interface.
14140		 * @protected
14141		 * @type {Object}
14142		 */
14143		this._controls = {};
14144
14145		/**
14146		 * Markup for an indicator.
14147		 * @protected
14148		 * @type {Array.<String>}
14149		 */
14150		this._templates = [];
14151
14152		/**
14153		 * The carousel element.
14154		 * @type {jQuery}
14155		 */
14156		this.$element = this._core.$element;
14157
14158		/**
14159		 * Overridden methods of the carousel.
14160		 * @protected
14161		 * @type {Object}
14162		 */
14163		this._overrides = {
14164			next: this._core.next,
14165			prev: this._core.prev,
14166			to: this._core.to
14167		};
14168
14169		/**
14170		 * All event handlers.
14171		 * @protected
14172		 * @type {Object}
14173		 */
14174		this._handlers = {
14175			'prepared.owl.carousel': $.proxy(function(e) {
14176				if (e.namespace && this._core.settings.dotsData) {
14177					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
14178						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
14179				}
14180			}, this),
14181			'added.owl.carousel': $.proxy(function(e) {
14182				if (e.namespace && this._core.settings.dotsData) {
14183					this._templates.splice(e.position, 0, this._templates.pop());
14184				}
14185			}, this),
14186			'remove.owl.carousel': $.proxy(function(e) {
14187				if (e.namespace && this._core.settings.dotsData) {
14188					this._templates.splice(e.position, 1);
14189				}
14190			}, this),
14191			'changed.owl.carousel': $.proxy(function(e) {
14192				if (e.namespace && e.property.name == 'position') {
14193					this.draw();
14194				}
14195			}, this),
14196			'initialized.owl.carousel': $.proxy(function(e) {
14197				if (e.namespace && !this._initialized) {
14198					this._core.trigger('initialize', null, 'navigation');
14199					this.initialize();
14200					this.update();
14201					this.draw();
14202					this._initialized = true;
14203					this._core.trigger('initialized', null, 'navigation');
14204				}
14205			}, this),
14206			'refreshed.owl.carousel': $.proxy(function(e) {
14207				if (e.namespace && this._initialized) {
14208					this._core.trigger('refresh', null, 'navigation');
14209					this.update();
14210					this.draw();
14211					this._core.trigger('refreshed', null, 'navigation');
14212				}
14213			}, this)
14214		};
14215
14216		// set default options
14217		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
14218
14219		// register event handlers
14220		this.$element.on(this._handlers);
14221	};
14222
14223	/**
14224	 * Default options.
14225	 * @public
14226	 * @todo Rename `slideBy` to `navBy`
14227	 */
14228	Navigation.Defaults = {
14229		nav: false,
14230		navText: [ 'prev', 'next' ],
14231		navSpeed: false,
14232		navElement: 'div',
14233		navContainer: false,
14234		navContainerClass: 'owl-nav',
14235		navClass: [ 'owl-prev', 'owl-next' ],
14236		slideBy: 1,
14237		dotClass: 'owl-dot',
14238		dotsClass: 'owl-dots',
14239		dots: true,
14240		dotsEach: false,
14241		dotsData: false,
14242		dotsSpeed: false,
14243		dotsContainer: false
14244	};
14245
14246	/**
14247	 * Initializes the layout of the plugin and extends the carousel.
14248	 * @protected
14249	 */
14250	Navigation.prototype.initialize = function() {
14251		var override,
14252			settings = this._core.settings;
14253
14254		// create DOM structure for relative navigation
14255		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
14256			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
14257
14258		this._controls.$previous = $('<' + settings.navElement + '>')
14259			.addClass(settings.navClass[0])
14260			.html(settings.navText[0])
14261			.prependTo(this._controls.$relative)
14262			.on('click', $.proxy(function(e) {
14263				this.prev(settings.navSpeed);
14264			}, this));
14265		this._controls.$next = $('<' + settings.navElement + '>')
14266			.addClass(settings.navClass[1])
14267			.html(settings.navText[1])
14268			.appendTo(this._controls.$relative)
14269			.on('click', $.proxy(function(e) {
14270				this.next(settings.navSpeed);
14271			}, this));
14272
14273		// create DOM structure for absolute navigation
14274		if (!settings.dotsData) {
14275			this._templates = [ $('<div>')
14276				.addClass(settings.dotClass)
14277				.append($('<span>'))
14278				.prop('outerHTML') ];
14279		}
14280
14281		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
14282			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
14283
14284		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
14285			var index = $(e.target).parent().is(this._controls.$absolute)
14286				? $(e.target).index() : $(e.target).parent().index();
14287
14288			e.preventDefault();
14289
14290			this.to(index, settings.dotsSpeed);
14291		}, this));
14292
14293		// override public methods of the carousel
14294		for (override in this._overrides) {
14295			this._core[override] = $.proxy(this[override], this);
14296		}
14297	};
14298
14299	/**
14300	 * Destroys the plugin.
14301	 * @protected
14302	 */
14303	Navigation.prototype.destroy = function() {
14304		var handler, control, property, override;
14305
14306		for (handler in this._handlers) {
14307			this.$element.off(handler, this._handlers[handler]);
14308		}
14309		for (control in this._controls) {
14310			this._controls[control].remove();
14311		}
14312		for (override in this.overides) {
14313			this._core[override] = this._overrides[override];
14314		}
14315		for (property in Object.getOwnPropertyNames(this)) {
14316			typeof this[property] != 'function' && (this[property] = null);
14317		}
14318	};
14319
14320	/**
14321	 * Updates the internal state.
14322	 * @protected
14323	 */
14324	Navigation.prototype.update = function() {
14325		var i, j, k,
14326			lower = this._core.clones().length / 2,
14327			upper = lower + this._core.items().length,
14328			maximum = this._core.maximum(true),
14329			settings = this._core.settings,
14330			size = settings.center || settings.autoWidth || settings.dotsData
14331				? 1 : settings.dotsEach || settings.items;
14332
14333		if (settings.slideBy !== 'page') {
14334			settings.slideBy = Math.min(settings.slideBy, settings.items);
14335		}
14336
14337		if (settings.dots || settings.slideBy == 'page') {
14338			this._pages = [];
14339
14340			for (i = lower, j = 0, k = 0; i < upper; i++) {
14341				if (j >= size || j === 0) {
14342					this._pages.push({
14343						start: Math.min(maximum, i - lower),
14344						end: i - lower + size - 1
14345					});
14346					if (Math.min(maximum, i - lower) === maximum) {
14347						break;
14348					}
14349					j = 0, ++k;
14350				}
14351				j += this._core.mergers(this._core.relative(i));
14352			}
14353		}
14354	};
14355
14356	/**
14357	 * Draws the user interface.
14358	 * @todo The option `dotsData` wont work.
14359	 * @protected
14360	 */
14361	Navigation.prototype.draw = function() {
14362		var difference,
14363			settings = this._core.settings,
14364			disabled = this._core.items().length <= settings.items,
14365			index = this._core.relative(this._core.current()),
14366			loop = settings.loop || settings.rewind;
14367
14368		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
14369
14370		if (settings.nav) {
14371			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
14372			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
14373		}
14374
14375		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
14376
14377		if (settings.dots) {
14378			difference = this._pages.length - this._controls.$absolute.children().length;
14379
14380			if (settings.dotsData && difference !== 0) {
14381				this._controls.$absolute.html(this._templates.join(''));
14382			} else if (difference > 0) {
14383				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
14384			} else if (difference < 0) {
14385				this._controls.$absolute.children().slice(difference).remove();
14386			}
14387
14388			this._controls.$absolute.find('.active').removeClass('active');
14389			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
14390		}
14391	};
14392
14393	/**
14394	 * Extends event data.
14395	 * @protected
14396	 * @param {Event} event - The event object which gets thrown.
14397	 */
14398	Navigation.prototype.onTrigger = function(event) {
14399		var settings = this._core.settings;
14400
14401		event.page = {
14402			index: $.inArray(this.current(), this._pages),
14403			count: this._pages.length,
14404			size: settings && (settings.center || settings.autoWidth || settings.dotsData
14405				? 1 : settings.dotsEach || settings.items)
14406		};
14407	};
14408
14409	/**
14410	 * Gets the current page position of the carousel.
14411	 * @protected
14412	 * @returns {Number}
14413	 */
14414	Navigation.prototype.current = function() {
14415		var current = this._core.relative(this._core.current());
14416		return $.grep(this._pages, $.proxy(function(page, index) {
14417			return page.start <= current && page.end >= current;
14418		}, this)).pop();
14419	};
14420
14421	/**
14422	 * Gets the current succesor/predecessor position.
14423	 * @protected
14424	 * @returns {Number}
14425	 */
14426	Navigation.prototype.getPosition = function(successor) {
14427		var position, length,
14428			settings = this._core.settings;
14429
14430		if (settings.slideBy == 'page') {
14431			position = $.inArray(this.current(), this._pages);
14432			length = this._pages.length;
14433			successor ? ++position : --position;
vendor: 5,678 bytes, lines 14434-14658
14434			position = this._pages[((position % length) + length) % length].start;
14435		} else {
14436			position = this._core.relative(this._core.current());
14437			length = this._core.items().length;
14438			successor ? position += settings.slideBy : position -= settings.slideBy;
14439		}
14440
14441		return position;
14442	};
14443
14444	/**
14445	 * Slides to the next item or page.
14446	 * @public
14447	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
14448	 */
14449	Navigation.prototype.next = function(speed) {
14450		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
14451	};
14452
14453	/**
14454	 * Slides to the previous item or page.
14455	 * @public
14456	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
14457	 */
14458	Navigation.prototype.prev = function(speed) {
14459		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
14460	};
14461
14462	/**
14463	 * Slides to the specified item or page.
14464	 * @public
14465	 * @param {Number} position - The position of the item or page.
14466	 * @param {Number} [speed] - The time in milliseconds for the transition.
14467	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
14468	 */
14469	Navigation.prototype.to = function(position, speed, standard) {
14470		var length;
14471
14472		if (!standard) {
14473			length = this._pages.length;
14474			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
14475		} else {
14476			$.proxy(this._overrides.to, this._core)(position, speed);
14477		}
14478	};
14479
14480	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
14481
14482})(window.Zepto || window.jQuery, window, document);
14483
14484/**
14485 * Hash Plugin
14486 * @version 2.0.0-beta.3
14487 * @author Artus Kolanowski
14488 * @license The MIT License (MIT)
14489 */
14490;(function($, window, document, undefined) {
14491	'use strict';
14492
14493	/**
14494	 * Creates the hash plugin.
14495	 * @class The Hash Plugin
14496	 * @param {Owl} carousel - The Owl Carousel
14497	 */
14498	var Hash = function(carousel) {
14499		/**
14500		 * Reference to the core.
14501		 * @protected
14502		 * @type {Owl}
14503		 */
14504		this._core = carousel;
14505
14506		/**
14507		 * Hash index for the items.
14508		 * @protected
14509		 * @type {Object}
14510		 */
14511		this._hashes = {};
14512
14513		/**
14514		 * The carousel element.
14515		 * @type {jQuery}
14516		 */
14517		this.$element = this._core.$element;
14518
14519		/**
14520		 * All event handlers.
14521		 * @protected
14522		 * @type {Object}
14523		 */
14524		this._handlers = {
14525			/*'initialized.owl.carousel': $.proxy(function(e) {
14526				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
14527					$(window).trigger('hashchange.owl.navigation');
14528				}
14529			}, this),*/
14530			'prepared.owl.carousel': $.proxy(function(e) {
14531				if (e.namespace) {
14532					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
14533
14534					if (!hash) {
14535						return;
14536					}
14537
14538					this._hashes[hash] = e.content;
14539				}
14540			}, this),
14541			'changed.owl.carousel': $.proxy(function(e) {
14542				if (e.namespace && e.property.name === 'position') {
14543					var current = this._core.items(this._core.relative(this._core.current())),
14544						hash = $.map(this._hashes, function(item, hash) {
14545							return item === current ? hash : null;
14546						}).join();
14547
14548					if (!hash || window.location.hash.slice(1) === hash) {
14549						return;
14550					}
14551
14552					window.location.hash = hash;
14553				}
14554			}, this)
14555		};
14556
14557		// set default options
14558		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
14559
14560		// register the event handlers
14561		this.$element.on(this._handlers);
14562
14563		// register event listener for hash navigation
14564		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
14565			var hash = window.location.hash.substring(1),
14566				items = this._core.$stage.children(),
14567				position = this._hashes[hash] && items.index(this._hashes[hash]);
14568
14569			if (position === undefined || position === this._core.current()) {
14570				return;
14571			}
14572
14573			this._core.to(this._core.relative(position), false, true);
14574		}, this));*/
14575	};
14576
14577	/**
14578	 * Default options.
14579	 * @public
14580	 */
14581	Hash.Defaults = {
14582		URLhashListener: false
14583	};
14584
14585	/**
14586	 * Destroys the plugin.
14587	 * @public
14588	 */
14589	Hash.prototype.destroy = function() {
14590		var handler, property;
14591
14592		$(window).off('hashchange.owl.navigation');
14593
14594		for (handler in this._handlers) {
14595			this._core.$element.off(handler, this._handlers[handler]);
14596		}
14597		for (property in Object.getOwnPropertyNames(this)) {
14598			typeof this[property] != 'function' && (this[property] = null);
14599		}
14600	};
14601
14602	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
14603
14604})(window.Zepto || window.jQuery, window, document);
14605
14606/**
14607 * Support Plugin
14608 *
14609 * @version 2.0.0-beta.3
14610 * @author Vivid Planet Software GmbH
14611 * @author Artus Kolanowski
14612 * @license The MIT License (MIT)
14613 */
14614;(function($, window, document, undefined) {
14615
14616	var style = $('<support>').get(0).style,
14617		prefixes = 'Webkit Moz O ms'.split(' '),
14618		events = {
14619			transition: {
14620				end: {
14621					WebkitTransition: 'webkitTransitionEnd',
14622					MozTransition: 'transitionend',
14623					OTransition: 'oTransitionEnd',
14624					transition: 'transitionend'
14625				}
14626			},
14627			animation: {
14628				end: {
14629					WebkitAnimation: 'webkitAnimationEnd',
14630					MozAnimation: 'animationend',
14631					OAnimation: 'oAnimationEnd',
14632					animation: 'animationend'
14633				}
14634			}
14635		},
14636		tests = {
14637			csstransforms: function() {
14638				return !!test('transform');
14639			},
14640			csstransforms3d: function() {
14641				return !!test('perspective');
14642			},
14643			csstransitions: function() {
14644				return !!test('transition');
14645			},
14646			cssanimations: function() {
14647				return !!test('animation');
14648			}
14649		};
14650
14651	function test(property, prefixed) {
14652		var result = false,
14653			upper = property.charAt(0).toUpperCase() + property.slice(1);
14654
14655		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
14656			if (style[property] !== undefined) {
14657				result = prefixed ? property : true;
14658				return false;
14659			}
14660		});
14661
14662		return result;
14663	}
14664
14665	function prefixed(property) {
14666		return test(property, true);
14667	}
14668
14669	if (tests.csstransitions()) {
14670		/* jshint -W053 */
14671		$.support.transition = new String(prefixed('transition'))
14672		$.support.transition.end = events.transition.end[ $.support.transition ];
14673	}
14674
14675	if (tests.cssanimations()) {
14676		/* jshint -W053 */
14677		$.support.animation = new String(prefixed('animation'))
14678		$.support.animation.end = events.animation.end[ $.support.animation ];
14679	}
14680
14681	if (tests.csstransforms()) {
14682		/* jshint -W053 */
14683		$.support.transform = new String(prefixed('transform'));
14684		$.support.transform3d = tests.csstransforms3d();
14685	}
14686
14687})(window.Zepto || window.jQuery, window, document);
14688
14689(function(window, document, undefined) {
14690
14691	/**
14692	 * Find the absolute position of an element
14693	 */
14694	var absPos = function(element) {
14695		var offsetLeft, offsetTop;
14696		offsetLeft = offsetTop = 0;
14697		if (element.offsetParent) {
14698			do {
14699				offsetLeft += element.offsetLeft;
14700				offsetTop += element.offsetTop;
14701			} while (element = element.offsetParent);
14702		}
14703		return [offsetLeft, offsetTop];
14704	};
14705
14706	/**
14707	 * @constructor Progress Circle class
14708	 * @param params.canvas Canvas on which the circles will be drawn.
14709	 * @param params.minRadius Inner radius of the innermost circle, in px.
14710	 * @param params.arcWidth Width of each circle(to be more accurate, ring).
14711	 * @param params.gapWidth Space between each circle.
14712	 * @param params.centerX X coordinate of the center of circles.
14713	 * @param params.centerY Y coordinate of the center of circles.
14714	 * @param params.infoLineBaseAngle Base angle of the info line.
14715	 * @param params.infoLineAngleInterval Angles between the info lines.
14716	 */
14717	var ProgressCircle = function(params) {
14718		this.canvas = params.canvas;
14719		this.minRadius = params.minRadius || 15;
14720		this.arcWidth = params.arcWidth || 5;
14721		this.gapWidth = params.gapWidth || 3;
14722		this.centerX = params.centerX || this.canvas.width / 2;
14723		this.centerY = params.centerY || this.canvas.height / 2;
14724		this.infoLineLength = params.infoLineLength || 60;
14725		this.horizLineLength = params.horizLineLength || 10;
14726		this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
14727		this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
14728
14729		this.context = this.canvas.getContext('2d');
14730
14731		this.width = this.canvas.width;
14732		this.height = this.canvas.height;
14733
14734		this.circles = [];
14735		this.runningCount = 0;
14736	};
14737
14738	ProgressCircle.prototype = {
14739		constructor: ProgressCircle,
14740
14741		/**
14742		 * @method Adds an progress monitor entry.
14743		 * @param params.fillColor Color to fill in the circle.
14744		 * @param params.outlineColor Color to outline the circle.
14745		 * @param params.progressListener Callback function to fetch the progress.
14746		 * @param params.infoListener Callback function to fetch the info.
14747		 * @returns this
14748		 */
14749		addEntry: function(params) {
14750			this.circles.push(new Circle({
14751				canvas: this.canvas,
14752				context: this.context,
14753				centerX: this.centerX,
14754				centerY: this.centerY,
14755				innerRadius: this.minRadius + this.circles.length *
14756					(this.gapWidth + this.arcWidth),
14757				arcWidth: this.arcWidth,
14758				infoLineLength: this.infoLineLength,
14759				horizLineLength: this.horizLineLength,
14760
14761				id: this.circles.length,
14762				fillColor: params.fillColor,
14763				outlineColor: params.outlineColor,
14764				progressListener: params.progressListener,
14765				infoListener: params.infoListener,
14766				infoLineAngle: this.infoLineBaseAngle +
14767					this.circles.length * this.infoLineAngleInterval,
14768			}));
14769
14770			return this;
14771		},
14772
14773		/**
14774		 * @method Starts the monitor and updates with the given interval.
14775		 * @param interval Interval between updates, in millisecond.
14776		 * @returns this
14777		 */
14778		start: function(interval) {
14779			var self = this;
14780			this.timer = setInterval(function() {
14781				self._update();
14782			}, interval || 33);
14783
14784			return this;
14785		},
14786
14787		/**
14788		 * @method Stop the animation.
14789		 */
14790		stop: function() {
14791			clearTimeout(this.timer);
14792		},
14793
14794		/**
14795		 * @private
14796		 * @method Call update on each circle and redraw them.
14797		 * @returns this
14798		 */
14799		_update: function() {
14800			this._clear();
14801			this.circles.forEach(function(circle, idx, array) {
14802				circle.update();
14803			});
14804
14805			return this;
14806		},
14807
14808		/**
14809		 * @private
14810		 * @method Clear the canvas.
14811		 * @returns this
14812		 */
14813		_clear: function() {
14814			this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
14815
14816			return this;
14817		},
14818
14819	};
14820
14821	/**
14822	 * @private
14823	 * @class Individual progress circle.
14824	 * @param params.canvas Canvas on which the circle will be drawn.
14825	 * @param params.context Context of the canvas.
14826	 * @param params.innerRadius Inner radius of the circle, in px.
14827	 * @param params.arcWidth Width of each arc(circle).
14828	 * @param params.gapWidth Distance between each arc.
14829	 * @param params.centerX X coordinate of the center of circles.
14830	 * @param params.centerY Y coordinate of the center of circles.
14831	 * @param params.fillColor Color to fill in the circle.
14832	 * @param params.outlineColor Color to outline the circle.
14833	 * @param params.progressListener Callback function to fetch the progress.
14834	 * @param params.infoListener Callback function to fetch the info.
14835	 * @param params.infoLineAngle Angle of info line.
14836	 */
14837	var Circle = function(params) {
14838		this.id = params.id;
14839		this.canvas = params.canvas;
14840		this.context = params.context;
14841		this.centerX = params.centerX;
14842		this.centerY = params.centerY;
14843		this.arcWidth = params.arcWidth;
14844		this.innerRadius = params.innerRadius || 0;
14845		this.fillColor = params.fillColor || '#fff';
14846		this.outlineColor = params.outlineColor || this.fillColor;
14847		this.progressListener = params.progressListener;
14848		this.infoLineLength = params.infoLineLength || 250;
14849		this.horizLineLength = params.horizLineLength || 50;
14850		this.infoListener = params.infoListener;
14851		this.infoLineAngle = params.infoLineAngle;
14852
14853		this.outerRadius = this.innerRadius + this.arcWidth;
14854
14855		// If the info listener is not registered, then don't calculate
14856		// the related coordinates
14857		if (!this.infoListener) return;
14858
14859		// calculate the info-line turning points
14860		var angle = this.infoLineAngle,
14861			arcDistance = (this.innerRadius + this.outerRadius) / 2,
14862
14863			sinA = Math.sin(angle),
14864			cosA = Math.cos(angle);
14865
14866		this.infoLineStartX = this.centerX + sinA * arcDistance;
14867		this.infoLineStartY = this.centerY - cosA * arcDistance;
14868
14869		this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
14870		this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
14871
14872		this.infoLineEndX = this.infoLineMidX +
14873			 (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
14874		this.infoLineEndY = this.infoLineMidY;
14875
14876		var infoText = document.createElement('div'),
14877			style = infoText.style;
14878
14879		style.color = this.fillColor;
14880		style.position = 'absolute';
14881		style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
14882		// style.top will be calculated in the `drawInfo` method. Since
14883		// user may want to change the size of the font, so the top offset
14884		// must be updated in each loop.
14885		infoText.className = 'ProgressCircleInfo'; // For css styling
14886		infoText.id = 'progress_circle_info_' + this.id;
14887		document.body.appendChild(infoText);
14888		this.infoText = infoText;
14889	};
14890
14891	Circle.prototype = {
14892		constructor: Circle,
14893
14894		update: function() {
14895			this.progress = this.progressListener();
14896			this._draw();
14897
14898			if (this.infoListener) {
14899				this.info = this.infoListener();
14900				this._drawInfo();
14901			}
14902		},
14903
14904		/**
14905		 * @private
14906		 * @method Draw the circle on the canvas.
14907		 * @returns this
14908		 */
14909		_draw: function() {
14910			var ctx = this.context,
14911
14912				ANGLE_OFFSET = -Math.PI / 2,
14913
14914				startAngle = 0 + ANGLE_OFFSET,
14915				endAngle= startAngle + this.progress * Math.PI * 2,
14916
14917				x = this.centerX,
14918				y = this.centerY,
14919
14920				innerRadius = this.innerRadius - this.arcWidth - 1,
14921				outerRadius = this.outerRadius - this.arcWidth - 1;
14922
14923			if ( innerRadius < 0 )
14924				return;
14925
14926			ctx.fillStyle = this.fillColor;
14927			ctx.strokeStyle = this.outlineColor;
14928
14929			ctx.beginPath();
14930			ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
14931			ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
14932			ctx.closePath();
14933			ctx.stroke();
14934			ctx.fill();
14935
14936			return this;
14937		},
14938
14939		/**
14940		 * @private
14941		 * @method Draw the info lines and info text.
14942		 * @returns this
14943		 */
14944		_drawInfo: function() {
14945
14946			var pointList, lineHeight;
14947
14948			pointList = [
14949				[this.infoLineStartX, this.infoLineStartY],
14950				[this.infoLineMidX, this.infoLineMidY],
14951				[this.infoLineEndX, this.infoLineEndY],
14952			];
14953			this._drawSegments(pointList, false);
14954
14955			this.infoText.innerHTML = this.info;
14956
14957			lineHeight = this.infoText.offsetHeight;
14958			this.infoText.style.top = this.infoLineEndY +
14959				absPos(this.canvas)[1] - lineHeight / 2 + 'px';
14960
14961			return this;
14962		},
14963
14964		/**
14965		 * @private
14966		 * @method Helper function to draw the segments
14967		 * @param pointList An array of points in the form of [x, y].
14968		 * @param close Whether to connect the first and last point.
14969		 */
14970		_drawSegments: function(pointList, close) {
14971			var ctx = this.context;
14972
14973			ctx.beginPath();
14974			ctx.moveTo(pointList[0][0], pointList[0][1]);
14975			for (var i = 1; i < pointList.length; ++i) {
14976				ctx.lineTo(pointList[i][0], pointList[i][1]);
14977			}
14978
14979			if (close) {
14980				ctx.closePath();
14981			}
14982			ctx.stroke();
14983		},
14984	};
14985
14986	window.ProgressCircle = ProgressCircle;
14987
14988})(window, document);
14989
14990
14991
14992
14993/* =========================================================
14994 * jquery.vc_chart.js v1.0
14995 * =========================================================
14996 * Copyright 2013 Wpbakery
14997 *
14998 * Jquery chart plugin for the Visual Composer.
14999 * ========================================================= */
15000(function($){
15001	/**
15002	 * Pie chart animated.
15003	 * @param element - DOM element
15004	 * @param options - settings object.
15005	 * @constructor
15006	 */
15007	var VcChart = function(element, options) {
15008		this.el = element;
15009		this.$el = $(this.el);
15010		var $this = this;
15011		$this.options = $.extend({
15012			color: 'wpb_button',
15013			units: '',
15014			width: '',
15015			label_selector: '.vc_pie_chart_value',
15016			back_selector: '.vc_pie_chart_back',
15017			responsive: true
15018		}, options);
15019		$this.init();
15020	};
15021	VcChart.prototype = {
15022		constructor: VcChart,
15023		_progress_v: 0,
15024		animated: false,
15025		colors: {
15026			'wpb_button': 'rgba(247, 247, 247, 1)',
15027			'btn-primary': 'rgba(0, 136, 204, 1)',
15028			'btn-info': 'rgba(88, 185, 218, 1)',
15029			'btn-success': 'rgba(106, 177, 101, 1)',
15030			'btn-warning': 'rgba(255, 153, 0, 1)',
15031			'btn-danger': 'rgba(255, 103, 91, 1)',
15032			'btn-inverse': 'rgba(85, 85, 85, 1)'
15033		},
15034		init: function() {
15035			this.setupColor();
15036			this.value = this.$el.data('pie-value')/100;
15037			this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
15038			this.$wrapper = $('.vc_pie_wrapper', this.$el);
15039			this.$label = $(this.options.label_selector, this.$el);
15040			this.$back = $(this.options.back_selector, this.$el);
15041			this.$canvas = this.$el.find('canvas');
15042			this.arcWidth = this.$el.data('pie-width') * 2;
15043			this.draw();
15044			this.setWayPoint();
15045			if(this.options.responsive === true) this.setResponsive();
15046			if (UNCODE.isMobile) this._progress_v = this.value;
15047		},
15048		setupColor: function() {
15049			// if(typeof this.colors[this.options.color] !== 'undefined') {
15050			//     this.color = this.colors[this.options.color];
15051			// } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
15052			//     this.color = this.options.color;
15053			// } else {
15054			//     this.color = 'rgba(247, 247, 247, 0.2)';
15055			// }
15056			if(typeof this.options.color !== 'undefined') {
15057				this.color = this.options.color;
15058			} else this.color = 'rgba(247, 247, 247, 0.2)';
15059
15060		},
15061		setResponsive: function() {
15062			var that = this;
15063			if (!UNCODE.isMobile) {
15064				$(window).resize(function(){
15065					if(that.animated === true) that.circle.stop();
15066					that.draw(true);
15067				});
15068			}
15069		},
15070		draw: function(redraw) {
15071			var w = this.$el.addClass('vc_ready').width() * 2,
15072				border_w = this.arcWidth,
15073				radius;
15074			if(!w) w = this.$el.parents(':visible').first().width()-2;
15075			//w = Math.round(w/100*80);
15076			//if (w < 250) w = 250;
15077			radius = w/2;
15078			this.$wrapper.css({"width" : (w / 2) + "px"});
15079			this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
15080			this.$back.css({"width" : (w / 2), "height" : (w / 2)});
15081			this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
15082			this.$el.addClass('vc_ready');
15083			this.circle = new ProgressCircle({
15084				canvas: this.$canvas.get(0),
15085				minRadius: radius,
15086				arcWidth: border_w
15087			});
15088			if(redraw === true && this.animated === true) {
15089				this._progress_v = this.value;
15090				this.circle.addEntry({
15091					fillColor: this.color,
15092					progressListener: $.proxy(this.setProgress, this)
15093				}).start();
15094			}
15095		},
15096		setProgress: function() {
15097			if (this._progress_v >= this.value) {
15098				this.circle.stop();
15099				this.animated = true;
15100				this.$label.html(this.label_value + this.options.units);
15101				return this._progress_v;
15102			}
15103			this._progress_v += 0.01;
15104			if (!isNaN(this.label_value)) {
15105				var label_value = this._progress_v/this.value*this.label_value;
15106				var val = Math.round(label_value) + this.options.units;
15107				this.$label.html(val);
15108			} else this.$label.html(this.label_value + this.options.units);
15109			return this._progress_v;
15110		},
15111		animate: function() {
15112			if(this.animated !== true) {
15113				this.circle.addEntry({
15114					fillColor: this.color,
15115					progressListener: $.proxy(this.setProgress, this)
15116				}).start(10);
15117			}
15118		},
15119		setWayPoint: function() {
15120			if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
15121				this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
15122			} else {
15123				this.animate();
15124			}
15125		}
15126	};
15127	/**
15128	 * jQuery plugin
15129	 * @param option - object with settings
15130	 * @return {*}
15131	 */
15132	$.fn.vcChat = function(option, value) {
15133		return this.each(function () {
15134			var $this = $(this),
15135				data = $this.data('vc_chart'),
15136				options = typeof option === 'object' ? option : {
15137					color: $this.data('pie-color'),
15138					units: $this.data('pie-units')
15139				};
15140			if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
15141			if (typeof option == 'string') data[option](value);
15142		});
15143	};
15144	/**
15145	 * Allows users to rewrite function inside theme.
15146	 */
15147	if ( typeof window['vc_pieChart'] !== 'function' ) {
15148		window.vc_pieChart = function() {
15149			$('.vc_pie_chart:visible:not(.vc_ready)').vcChat();
15150		}
15151	}
15152	$(document).ready(function(){
15153		!window.vc_iframe && vc_pieChart();
15154
15155		/**
15156		* Tab and collapse integration.
15157		*/
15158		$('.nav-tabs a').on('shown.bs.tab', function(e){
15159			var $cont = $(e.target).closest('.tab-container'),
15160				$active = $('.tab-pane.active', $cont);
15161			$('.vc_pie_chart:not(.vc_ready)', $active).vcChat();
15162		});
15163
15164		$('.panel-collapse').on('shown.bs.collapse', function (e) {
15165			$('.vc_pie_chart:not(.vc_ready)', e.target).vcChat();
15166		})
15167	});
15168
15169})(window.jQuery);
15170
15171/* Progress bar
15172 ---------------------------------------------------------- */
15173function uncode_progress_bar() {    
15174	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
15175		if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) {
15176			return;
15177		}
15178		if (!UNCODE.isMobile) {
15179			new Waypoint({
15180				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
15181				element: val,
15182				handler: function() {
15183					var element = jQuery(this.element);
15184					element.find('.vc_single_bar').each(function(index) {          
15185						var $this = jQuery(this),
15186							            bar = $this.find('.vc_bar'),
15187							            val = bar.data('percentage-value');          
15188						setTimeout(function() {            
15189							bar.css({
15190								"width": val + '%'
15191							});          
15192						}, index * 200);        
15193					});
15194				},
15195				offset: '80%'
15196			});
15197		} else {
15198			var element = jQuery(val);
15199			element.find('.vc_single_bar').each(function(index) {          
15200				var $this = jQuery(this),
15201					            bar = $this.find('.vc_bar'),
15202					            val = bar.data('percentage-value');          
15203				setTimeout(function() {            
15204					bar.css({
15205						"width": val + '%'
15206					});          
15207				}, index * 200);        
15208			});
15209		}
15210	});
15211};
15212uncode_progress_bar();
15213
15214/*!
15215 * jquery.counterup.js 1.0
15216 *
15217 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
15218 * Released under the GPL v2 License
15219 *
15220 * Date: Nov 26, 2013
15221 */
15222(function($) {
15223	"use strict";
15224	$.fn.counterUp = function(options) {
15225		// Defaults
15226		var settings = $.extend({
15227			'time': 400,
15228			'delay': 10
15229		}, options);
15230		return this.each(function() {
15231			// Store the object
15232			var $this = $(this);
15233			var $settings = settings;
15234			var counterUpper = function() {
15235				var nums = [];
15236				var divisions = $settings.time / $settings.delay;
15237				var numReal = $this.attr('data-val'),
15238				num = numReal;
15239				var isComma = /[0-9]+,[0-9]+/.test(num);
15240				num = num.replace(/,/g, '');
15241				var isInt = /^[0-9]+$/.test(num);
15242				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
15243				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
15244				// Generate list of incremental numbers to display
15245				for (var i = divisions; i >= 1; i--) {
15246					// Preserve as int if input was int
15247					var newNum = parseInt(num / divisions * i);
15248					// Preserve float if input was float
15249					if (isFloat) {
15250						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
15251					}
15252					// Preserve commas if input had commas
15253					if (isComma) {
15254						while (/(\d+)(\d{3})/.test(newNum.toString())) {
15255							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
15256						}
15257					}
15258					nums.unshift(newNum);
15259				}
15260				nums.push(numReal);
15261				$this.data('counterup-nums', nums);
15262				$this.text('0');
15263				// Updates the number until we're done
15264				var f = function() {
15265					if ($this.data('counterup-nums') != null) {
15266						$this.text($this.data('counterup-nums').shift());
15267						if ($this.data('counterup-nums').length) {
15268							setTimeout($this.data('counterup-func'), $settings.delay);
15269						} else {
15270							delete $this.data('counterup-nums');
15271							$this.data('counterup-nums', null);
15272							$this.data('counterup-func', null);
15273						}
15274					}
15275				};
15276				$this.data('counterup-func', f);
15277				// Start the count up
15278				setTimeout($this.data('counterup-func'), $settings.delay);
15279			};
15280			// Perform counts when the element gets into view
15281			new Waypoint({
15282				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
15283				element: this,
15284				handler: function() {
15285					counterUpper();
15286					if (!UNCODE.isUnmodalOpen) {
15287						this.destroy();
15288					}
15289				},
15290				offset: '100%'
15291			});
15292		});
15293	};
15294})(jQuery);
15295
15296/*!
15297 * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/)
15298 * Copyright (c) 2016 Edson Hilios
15299 *
15300 * Permission is hereby granted, free of charge, to any person obtaining a copy of
15301 * this software and associated documentation files (the "Software"), to deal in
15302 * the Software without restriction, including without limitation the rights to
15303 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
15304 * the Software, and to permit persons to whom the Software is furnished to do so,
15305 * subject to the following conditions:
15306 *
15307 * The above copyright notice and this permission notice shall be included in all
15308 * copies or substantial portions of the Software.
15309 *
15310 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15311 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15312 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15313 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
15314 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15315 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15316 */
15317(function(factory) {
15318	"use strict";
15319	if (typeof define === "function" && define.amd) {
15320		define([ "jquery" ], factory);
15321	} else {
15322		factory(jQuery);
15323	}
15324})(function($) {
15325	"use strict";
15326	var instances = [], matchers = [], defaultOptions = {
15327		precision: 100,
15328		elapse: false,
15329		defer: false
15330	};
15331	matchers.push(/^[0-9]*$/.source);
15332	matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
15333	matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
15334	matchers = new RegExp(matchers.join("|"));
15335	function parseDateString(dateString) {
15336		if (dateString instanceof Date) {
15337			return dateString;
15338		}
15339		if (String(dateString).match(matchers)) {
15340			if (String(dateString).match(/^[0-9]*$/)) {
15341				dateString = Number(dateString);
15342			}
15343			if (String(dateString).match(/\-/)) {
15344				dateString = String(dateString).replace(/\-/g, "/");
15345			}
15346			return new Date(dateString);
15347		} else {
15348			throw new Error("Couldn't cast `" + dateString + "` to a date object.");
15349		}
15350	}
15351	var DIRECTIVE_KEY_MAP = {
15352		Y: "years",
15353		m: "months",
15354		n: "daysToMonth",
15355		d: "daysToWeek",
15356		w: "weeks",
15357		W: "weeksToMonth",
15358		H: "hours",
15359		M: "minutes",
15360		S: "seconds",
15361		D: "totalDays",
15362		I: "totalHours",
15363		N: "totalMinutes",
15364		T: "totalSeconds"
15365	};
15366	function escapedRegExp(str) {
15367		var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
15368		return new RegExp(sanitize);
15369	}
15370	function strftime(offsetObject) {
15371		return function(format) {
15372			var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi);
15373			if (directives) {
15374				for (var i = 0, len = directives.length; i < len; ++i) {
15375					var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null;
15376					directive = directive[2];
15377					if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
15378						value = DIRECTIVE_KEY_MAP[directive];
15379						value = Number(offsetObject[value]);
15380					}
15381					if (value !== null) {
15382						if (modifier === "!") {
15383							value = pluralize(plural, value);
15384						}
15385						if (modifier === "") {
15386							if (value < 10) {
15387			
vendor: 4,091 bytes, lines 15387-15524
15387					value = "0" + value.toString();
15388							}
15389						}
15390						format = format.replace(regexp, value.toString());
15391					}
15392				}
15393			}
15394			format = format.replace(/%%/, "%");
15395			return format;
15396		};
15397	}
15398	function pluralize(format, count) {
15399		var plural = "s", singular = "";
15400		if (format) {
15401			format = format.replace(/(:|;|\s)/gi, "").split(/\,/);
15402			if (format.length === 1) {
15403				plural = format[0];
15404			} else {
15405				singular = format[0];
15406				plural = format[1];
15407			}
15408		}
15409		if (Math.abs(count) > 1) {
15410			return plural;
15411		} else {
15412			return singular;
15413		}
15414	}
15415	var Countdown = function(el, finalDate, options) {
15416		this.el = el;
15417		this.$el = $(el);
15418		this.interval = null;
15419		this.offset = {};
15420		this.options = $.extend({}, defaultOptions);
15421		this.instanceNumber = instances.length;
15422		instances.push(this);
15423		this.$el.data("countdown-instance", this.instanceNumber);
15424		if (options) {
15425			if (typeof options === "function") {
15426				this.$el.on("update.countdown", options);
15427				this.$el.on("stoped.countdown", options);
15428				this.$el.on("finish.countdown", options);
15429			} else {
15430				this.options = $.extend({}, defaultOptions, options);
15431			}
15432		}
15433		this.setFinalDate(finalDate);
15434		if (this.options.defer === false) {
15435			this.start();
15436		}
15437	};
15438	$.extend(Countdown.prototype, {
15439		start: function() {
15440			if (this.interval !== null) {
15441				clearInterval(this.interval);
15442			}
15443			var self = this;
15444			this.update();
15445			this.interval = setInterval(function() {
15446				self.update.call(self);
15447			}, this.options.precision);
15448		},
15449		stop: function() {
15450			clearInterval(this.interval);
15451			this.interval = null;
15452			this.dispatchEvent("stoped");
15453		},
15454		toggle: function() {
15455			if (this.interval) {
15456				this.stop();
15457			} else {
15458				this.start();
15459			}
15460		},
15461		pause: function() {
15462			this.stop();
15463		},
15464		resume: function() {
15465			this.start();
15466		},
15467		remove: function() {
15468			this.stop.call(this);
15469			instances[this.instanceNumber] = null;
15470			delete this.$el.data().countdownInstance;
15471		},
15472		setFinalDate: function(value) {
15473			this.finalDate = parseDateString(value);
15474		},
15475		update: function() {
15476			if (this.$el.closest("html").length === 0) {
15477				this.remove();
15478				return;
15479			}
15480			var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft;
15481			newTotalSecsLeft = this.finalDate.getTime() - now.getTime();
15482			newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3);
15483			newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft);
15484			if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) {
15485				return;
15486			} else {
15487				this.totalSecsLeft = newTotalSecsLeft;
15488			}
15489			this.elapsed = now >= this.finalDate;
15490			this.offset = {
15491				seconds: this.totalSecsLeft % 60,
15492				minutes: Math.floor(this.totalSecsLeft / 60) % 60,
15493				hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24,
15494				days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
15495				daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
15496				daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368),
15497				weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
15498				weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4,
15499				months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368),
15500				years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()),
15501				totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24),
15502				totalHours: Math.floor(this.totalSecsLeft / 60 / 60),
15503				totalMinutes: Math.floor(this.totalSecsLeft / 60),
15504				totalSeconds: this.totalSecsLeft
15505			};
15506			if (!this.options.elapse && this.totalSecsLeft === 0) {
15507				this.stop();
15508				this.dispatchEvent("finish");
15509			} else {
15510				this.dispatchEvent("update");
15511			}
15512		},
15513		dispatchEvent: function(eventName) {
15514			var event = $.Event(eventName + ".countdown");
15515			event.finalDate = this.finalDate;
15516			event.elapsed = this.elapsed;
15517			event.offset = $.extend({}, this.offset);
15518			event.strftime = strftime(this.offset);
15519			this.$el.trigger(event);
15520		}
15521	});
15522	$.fn.countdown = function() {
15523		var argumentsArray = Array.prototype.slice.call(arguments, 0);
15524		return this.each(function() {
15525			var instanceNumber = $(this).data("countdown-instance");
15526			if (instanceNumber !== undefined) {
15527				var instance = instances[instanceNumber], method = argumentsArray[0];
15528				if (Countdown.prototype.hasOwnProperty(method)) {
15529					instance[method].apply(instance, argumentsArray.slice(1));
15530				} else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
15531					instance.setFinalDate.call(instance, method);
15532					instance.start();
15533				} else {
15534					$.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method));
15535				}
15536			} else {
15537				new Countdown(this, argumentsArray[0], argumentsArray[1]);
15538			}
15539		});
15540	};
15541});
15542
15543/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05
15544* https://github.com/alexanderdickson/waitForImages
15545* Copyright (c) 2015 Alex Dickson; Licensed MIT */
15546;(function (factory) {
15547    if (typeof define === 'function' && define.amd) {
15548        // AMD. Register as an anonymous module.
15549        define(['jquery'], factory);
15550    } else if (typeof exports === 'object') {
15551        // CommonJS / nodejs module
15552        module.exports = factory(require('jquery'));
15553    } else {
15554        // Browser globals
15555        factory(jQuery);
15556    }
15557}(function ($) {
15558    // Namespace all events.
15559    var eventNamespace = 'waitForImages';
15560
15561    // CSS properties which contain references to images.
15562    $.waitForImages = {
15563        hasImageProperties: [
15564            'backgroundImage',
15565            'listStyleImage',
15566            'borderImage',
15567            'borderCornerImage',
15568            'cursor'
15569        ],
15570        hasImageAttributes: ['srcset']
15571    };
15572
15573    // Custom selector to find `img` elements that have a valid `src`
15574    // attribute and have not already loaded.
15575    $.expr[':'].uncached = function (obj) {
15576        // Ensure we are dealing with an `img` element with a valid
15577        // `src` attribute.
15578        if (!$(obj).is('img[src][src!=""]')) {
15579            return false;
15580        }
15581
15582        return !obj.complete;
15583    };
15584
15585    $.fn.waitForImages = function () {
15586
15587        var allImgsLength = 0;
15588        var allImgsLoaded = 0;
15589        var deferred = $.Deferred();
15590
15591        var finishedCallback;
15592        var eachCallback;
15593        var waitForAll;
15594
15595        // Handle options object (if passed).
15596        if ($.isPlainObject(arguments[0])) {
15597
15598            waitForAll = arguments[0].waitForAll;
15599            eachCallback = arguments[0].each;
15600            finishedCallback = arguments[0].finished;
15601
15602        } else {
15603
15604            // Handle if using deferred object and only one param was passed in.
15605            if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
15606                waitForAll = arguments[0];
15607            } else {
15608                finishedCallback = arguments[0];
15609                eachCallback = arguments[1];
15610                waitForAll = arguments[2];
15611            }
15612
15613        }
15614
15615        // Handle missing callbacks.
15616        finishedCallback = finishedCallback || $.noop;
15617        eachCallback = eachCallback || $.noop;
15618
15619        // Convert waitForAll to Boolean
15620        waitForAll = !! waitForAll;
15621
15622        // Ensure callbacks are functions.
15623        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
15624            throw new TypeError('An invalid callback was supplied.');
15625        }
15626
15627        this.each(function () {
15628            // Build a list of all imgs, dependent on what images will
15629            // be considered.
15630            var obj = $(this);
15631            var allImgs = [];
15632            // CSS properties which may contain an image.
15633            var hasImgProperties = $.waitForImages.hasImageProperties || [];
15634            // Element attributes which may contain an image.
15635            var hasImageAttributes = $.waitForImages.hasImageAttributes || [];
15636            // To match `url()` references.
15637            // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
15638            var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
15639
15640            if (waitForAll) {
15641
15642                // Get all elements (including the original), as any one of
15643                // them could have a background image.
15644                obj.find('*').addBack().each(function () {
15645                    var element = $(this);
15646
15647                    // If an `img` element, add it. But keep iterating in
15648                    // case it has a background image too.
15649                    if (element.is('img:uncached')) {
15650                        allImgs.push({
15651                            src: element.attr('src'),
15652                            element: element[0]
15653                        });
15654                    }
15655
15656                    $.each(hasImgProperties, function (i, property) {
15657                        var propertyValue = element.css(property);
15658                        var match;
15659
15660                        // If it doesn't contain this property, skip.
15661                        if (!propertyValue) {
15662                            return true;
15663                        }
15664
15665                        // Get all url() of this element.
15666                        while (match = matchUrl.exec(propertyValue)) {
15667                            allImgs.push({
15668                                src: match[2],
15669                                element: element[0]
15670                            });
15671                        }
15672                    });
15673
15674                    $.each(hasImageAttributes, function (i, attribute) {
15675                        var attributeValue = element.attr(attribute);
15676                        var attributeValues;
15677
15678                        // If it doesn't contain this property, skip.
15679                        if (!attributeValue) {
15680                            return true;
15681                        }
15682
15683                        // Check for multiple comma separated images
15684                        attributeValues = attributeValue.split(',');
15685
15686                        $.each(attributeValues, function(i, value) {
15687                            // Trim value and get string before first
15688                            // whitespace (for use with srcset).
15689                            value = $.trim(value).split(' ')[0];
15690                            allImgs.push({
15691                                src: value,
15692                                element: element[0]
15693                            });
15694                        });
15695                    });
15696                });
15697            } else {
15698                // For images only, the task is simpler.
15699                obj.find('img:uncached')
15700                    .each(function () {
15701                    allImgs.push({
15702                        src: this.src,
15703                        element: this
15704                    });
15705                });
15706            }
15707
15708            allImgsLength = allImgs.length;
15709            allImgsLoaded = 0;
15710
15711            // If no images found, don't bother.
15712            if (allImgsLength === 0) {
15713                finishedCallback.call(obj[0]);
15714                deferred.resolveWith(obj[0]);
15715            }
15716
15717            $.each(allImgs, function (i, img) {
15718
15719                var image = new Image();
15720                var events =
15721                  'load.' + eventNamespace + ' error.' + eventNamespace;
15722
15723                // Handle the image loading and error with the same callback.
15724                $(image).one(events, function me (event) {
15725                    // If an error occurred with loading the image, set the
15726                    // third argument accordingly.
15727                    var eachArguments = [
15728                        allImgsLoaded,
15729                        allImgsLength,
15730                        event.type == 'load'
15731                    ];
15732                    allImgsLoaded++;
15733
15734                    eachCallback.apply(img.element, eachArguments);
15735                    deferred.notifyWith(img.element, eachArguments);
15736
15737                    // Unbind the event listeners. I use this in addition to
15738                    // `one` as one of those events won't be called (either
15739                    // 'load' or 'error' will be called).
15740                    $(this).off(events, me);
15741
15742                    if (allImgsLoaded == allImgsLength) {
15743                        finishedCallback.call(obj[0]);
15744                        deferred.resolveWith(obj[0]);
15745                        return false;
15746                    }
15747
15748                });
15749
15750                image.src = img.src;
15751            });
15752        });
15753
15754        return deferred.promise();
15755
15756    };
15757}));
15758
15759/**
15760 * @preserve  textfill
15761 * @name      jquery.textfill.js
15762 * @author    Russ Painter
15763 * @author    Yu-Jie Lin
15764 * @author    Alexandre Dantas
15765 * @version   0.6.0
15766 * @date      2014-08-19
15767 * @copyright (c) 2014 Alexandre Dantas
15768 * @copyright (c) 2012-2013 Yu-Jie Lin
15769 * @copyright (c) 2009 Russ Painter
15770 * @license   MIT License
15771 * @homepage  https://github.com/jquery-textfill/jquery-textfill
15772 * @example   http://jquery-textfill.github.io/jquery-textfill/index.html
15773 */
15774; (function($) {
15775
15776	/**
15777	 * Resizes an inner element's font so that the
15778	 * inner element completely fills the outer element.
15779	 *
15780	 * @param {Object} options User options that take
15781	 *                         higher precedence when
15782	 *                         merging with the default ones.
15783	 *
15784	 * @return All outer elements processed
15785	 */
15786	$.fn.textfill = function(options) {
15787
15788		// ______  _______ _______ _______ _     _        _______ _______
15789		// |     \ |______ |______ |_____| |     | |         |    |______
15790		// |_____/ |______ |       |     | |_____| |_____    |    ______|
15791        //
15792		// Merging user options with the default values
15793
15794		var defaults = {
15795			debug            : false,
15796			maxFontPixels    : 40,
15797			minFontPixels    : 4,
15798			innerTag         : 'span',
15799			widthOnly        : false,
15800			success          : null, // callback when a resizing is done
15801			callback         : null, // callback when a resizing is done (deprecated, use success)
15802			fail             : null, // callback when a resizing is failed
15803			complete         : null, // callback when all is done
15804			explicitWidth    : null,
15805			explicitHeight   : null,
15806			changeLineHeight : false
15807		};
15808
15809		var Opts = $.extend(defaults, options);
15810
15811		// _______ _     _ __   _ _______ _______ _____  _____  __   _ _______
15812		// |______ |     | | \  | |          |      |   |     | | \  | |______
15813		// |       |_____| |  \_| |_____     |    __|__ |_____| |  \_| ______|
15814		//
15815		// Predefining the awesomeness
15816
15817		// Output arguments to the Debug console
15818		// if "Debug Mode" is enabled
15819		function _debug() {
15820			if (!Opts.debug
15821				||  typeof console       == 'undefined'
15822				||  typeof console.debug == 'undefined') {
15823				return;
15824			}
15825			console.debug.apply(console, arguments);
15826		}
15827
15828		// Output arguments to the Warning console
15829		function _warn() {
15830			if (typeof console      == 'undefined' ||
15831				typeof console.warn == 'undefined') {
15832				return;
15833			}
15834			console.warn.apply(console, arguments);
15835		}
15836
15837		// Outputs all information on the current sizing
15838		// of the font.
15839		function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
15840
15841			function _m(v1, v2) {
15842
15843				var marker = ' / ';
15844
15845				if (v1 > v2)
15846					marker = ' > ';
15847
15848				else if (v1 == v2)
15849					marker = ' = ';
15850
15851				return marker;
15852			}
15853
15854			_debug(
15855				'[TextFill] '  + prefix + ' { ' +
15856				'font-size: ' + ourText.css('font-size') + ',' +
15857				'Height: '    + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' +
15858				'Width: '     + ourText.width()  + _m(ourText.width() , maxWidth)  + maxWidth + ',' +
15859				'minFontPixels: ' + minFontPixels + 'px, ' +
15860				'maxFontPixels: ' + maxFontPixels + 'px }'
15861			);
15862		}
15863
15864		/**
15865		 * Calculates which size the font can get resized,
15866		 * according to constrains.
15867		 *
15868		 * @param {String} prefix Gets shown on the console before
15869		 *                        all the arguments, if debug mode is on.
15870		 * @param {Object} ourText The DOM element to resize,
15871		 *                         that contains the text.
15872		 * @param {function} func Function called on `ourText` that's
15873		 *                        used to compare with `max`.
15874		 * @param {number} max Maximum value, that gets compared with
15875		 *                     `func` called on `ourText`.
15876		 * @param {number} minFontPixels Minimum value the font can
15877		 *                               get resized to (in pixels).
15878		 * @param {number} maxFontPixels Maximum value the font can
15879		 *                               get resized to (in pixels).
15880		 *
15881		 * @return Size (in pixels) that the font can be resized.
15882		 */
15883		function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
15884
15885			_debug_sizing(
15886				prefix, ourText,
15887				maxHeight, maxWidth,
15888				minFontPixels, maxFontPixels
15889			);
15890
15891			// The kernel of the whole plugin, take most attention
15892			// on this part.
15893			//
15894			// This is a loop that keeps increasing the `font-size`
15895			// until it fits the parent element.
15896			//
15897			// - Start from the minimal allowed value (`minFontPixels`)
15898			// - Guesses an average font size (in pixels) for the font,
15899			// - Resizes the text and sees if its size is within the
15900			//   boundaries (`minFontPixels` and `maxFontPixels`).
15901			//   - If so, keep guessing until we break.
15902			//   - If not, return the last calculated size.
15903			//
15904			// I understand this is not optimized and we should
15905			// consider implementing something akin to
15906			// Daniel Hoffmann's answer here:
15907			//
15908			//     http://stackoverflow.com/a/17433451/1094964
15909			//
15910
15911			while (minFontPixels < (maxFontPixels - 1)) {
15912
15913				var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2);
15914				ourText.css('font-size', fontSize);
15915
15916				if (func.call(ourText) <= max) {
15917					minFontPixels = fontSize;
15918
15919					if (func.call(ourText) == max)
15920						break;
15921				}
15922				else
15923					maxFontPixels = fontSize;
15924
15925				_debug_sizing(
15926					prefix, ourText,
15927					maxHeight, maxWidth,
15928					minFontPixels, maxFontPixels
15929				);
15930			}
15931
15932			ourText.css('font-size', maxFontPixels);
15933
15934			if (func.call(ourText) <= max) {
15935				minFontPixels = maxFontPixels;
15936
15937				_debug_sizing(
15938					prefix + '* ', ourText,
15939					maxHeight, maxWidth,
15940					minFontPixels, maxFontPixels
15941				);
15942			}
15943			return minFontPixels;
15944		}
15945
15946		// _______ _______ _______  ______ _______
15947		// |______    |    |_____| |_____/    |
15948		// ______|    |    |     | |    \_    |
15949        //
15950		// Let's get it started (yeah)!
15951
15952		_debug('[TextFill] Start Debug');
15953
15954		this.each(function() {
15955
15956			// Contains the child element we will resize.
15957			// $(this) means the parent container
15958			var ourText = $(Opts.innerTag + ':visible:first', this);
15959
15960			// Will resize to this dimensions.
15961			// Use explicit dimensions when specified
15962			var maxHeight = Opts.explicitHeight || $(this).height();
15963			var maxWidth  = Opts.explicitWidth  || $(this).width();
15964
15965			var oldFontSize = ourText.css('font-size');
15966
15967			var lineHeight  = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize);
15968
15969			_debug('[TextFill] Inner text: ' + ourText.text());
15970			_debug('[TextFill] All options: ', Opts);
15971			_debug('[TextFill] Maximum sizes: { ' +
15972				   'Height: ' + maxHeight + 'px, ' +
15973				   'Width: '  + maxWidth  + 'px' + ' }'
15974				  );
15975
15976			var minFontPixels = Opts.minFontPixels;
15977
15978			// Remember, if this `maxFontPixels` is negative,
15979			// the text will resize to as long as the container
15980			// can accomodate
15981			var maxFontPixels = (Opts.maxFontPixels <= 0 ?
15982								 maxHeight :
15983								 Opts.maxFontPixels);
15984
15985
15986			// Let's start it all!
15987
15988			// 1. Calculate which `font-size` would
15989			//    be best for the Height
15990			var fontSizeHeight = undefined;
15991
15992			if (! Opts.widthOnly)
15993				fontSizeHeight = _sizing(
15994					'Height', ourText,
15995					$.fn.height, maxHeight,
15996					maxHeight, maxWidth,
15997					minFontPixels, maxFontPixels
15998				);
15999
16000			// 2. Calculate which `font-size` would
16001			//    be best for the Width
16002			var fontSizeWidth = undefined;
16003
16004			fontSizeWidth = _sizing(
16005				'Width', ourText,
16006				$.fn.width, maxWidth,
16007				maxHeight, maxWidth,
16008				minFontPixels, maxFontPixels
16009			);
16010
16011			// 3. Actually resize the text!
16012
16013			if (Opts.widthOnly) {
16014				ourText.css({
16015					'font-size'  : fontSizeWidth,
16016					'white-space': 'nowrap'
16017				});
16018
16019				if (Opts.changeLineHeight)
16020					ourText.parent().css(
16021						'line-height',
16022						(lineHeight * fontSizeWidth + 'px')
16023					);
16024			}
16025			else {
16026				var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth);
16027
16028				ourText.css('font-size', fontSizeFinal);
16029
16030				if (Opts.changeLineHeight)
16031					ourText.parent().css(
16032						'line-height',
16033						(lineHeight * fontSizeFinal) + 'px'
16034					);
16035			}
16036
16037			_debug(
16038				'[TextFill] Finished { ' +
16039				'Old font-size: ' + oldFontSize              + ', ' +
16040				'New font-size: ' + ourText.css('font-size') + ' }'
16041			);
16042
16043			// Oops, something wrong happened!
16044			// We weren't supposed to exceed the original size
16045			if ((ourText.width()  > maxWidth) ||
16046				(ourText.height() > maxHeight && !Opts.widthOnly)) {
16047
16048				ourText.css('font-size', oldFontSize);
16049
16050				// Failure callback
16051				if (Opts.fail)
16052					Opts.fail(this);
16053
16054				_debug(
16055					'[TextFill] Failure { ' +
16056					'Current Width: '  + ourText.width()  + ', ' +
16057					'Maximum Width: '  + maxWidth         + ', ' +
16058					'Current Height: ' + ourText.height() + ', ' +
16059					'Maximum Height: ' + maxHeight        + ' }'
16060				);
16061			}
16062			else if (Opts.success) {
16063				Opts.success(this);
16064			}
16065			else if (Opts.callback) {
16066				_warn('callback is deprecated, use success, instead');
16067
16068				// Success callback
16069				Opts.callback(this);
16070			}
16071		});
16072
16073		// Complete callback
16074		if (Opts.complete)
16075			Opts.complete(this);
16076
16077		_debug('[TextFill] End Debug');
16078		return this;
16079	};
16080
16081})(window.jQuery);
16082
16083!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Share=e()}}(function(){var define,module,exports;
16084function getStyles(config){
16085  // return ""+config.selector+"{width:92px;height:20px;-webkit-touch-callout:none;-khtml-user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}"+config.selector+" [class*=social-]:before{font-family:'uncodeicon'}"+config.selector+" label{font-size:16px;cursor:pointer;margin:0;padding:5px 10px;border-radius:5px;background:#a29baa;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" label:hover{opacity:.8}"+config.selector+" label span{text-transform:uppercase;font-size:.9em;font-family:Lato,sans-serif;font-weight:700;-webkit-font-smoothing:antialiased;padding-left:6px}"+config.selector+" .social{opacity:0;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;margin-left:-15px;visibility:hidden}"+config.selector+" .social.top{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:-80px}"+config.selector+" .social.bottom{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:5px}"+config.selector+" .social.middle{margin-top:-34px}"+config.selector+" .social.middle.right{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%;margin-left:105px}"+config.selector+" .social.middle.left{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%}"+config.selector+" .social.right{margin-left:14px}"+config.selector+" .social.load{-webkit-transition:none!important;transition:none!important}"+config.selector+" .social.networks-1{width:60px}"+config.selector+" .social.networks-1.center,"+config.selector+" .social.networks-1.left{margin-left:14px}"+config.selector+" .social.networks-1.middle.left{margin-left:-70px}"+config.selector+" .social.networks-1 ul{width:60px}"+config.selector+" .social.networks-2{width:120px}"+config.selector+" .social.networks-2.center{margin-left:-13px}"+config.selector+" .social.networks-2.left{margin-left:-44px}"+config.selector+" .social.networks-2.middle.left{margin-left:-130px}"+config.selector+" .social.networks-2 ul{width:120px}"+config.selector+" .social.networks-3{width:180px}"+config.selector+" .social.networks-3.center{margin-left:-45px}"+config.selector+" .social.networks-3.left{margin-left:-102px}"+config.selector+" .social.networks-3.middle.left{margin-left:-190px}"+config.selector+" .social.networks-3 ul{width:180px}"+config.selector+" .social.networks-4{width:240px}"+config.selector+" .social.networks-4.center{margin-left:-75px}"+config.selector+" .social.networks-4.left{margin-left:162px}"+config.selector+" .social.networks-4.middle.left{margin-left:-250px}"+config.selector+" .social.networks-4 ul{width:240px}"+config.selector+" .social.networks-5{width:300px}"+config.selector+" .social.networks-5.center{margin-left:-105px}"+config.selector+" .social.networks-5.left{margin-left:-225px}"+config.selector+" .social.networks-5.middle.left{margin-left:-320px}"+config.selector+" .social.networks-5 ul{width:300px}"+config.selector+" .social.active{opacity:1;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;visibility:visible}"+config.selector+" .social.active.top{-webkit-transform:scale(1) translateY(-20px);-ms-transform:scale(1) translateY(-20px);transform:scale(1) translateY(-20px)}"+config.selector+" .social.active.bottom{-webkit-transform:scale(1) translateY(15px);-ms-transform:scale(1) translateY(15px);transform:scale(1) translateY(15px)}"+config.selector+" .social.active.middle.right{-webkit-transform:scale(1) translateX(10px);-ms-transform:scale(1) translateX(10px);transform:scale(1) translateX(10px)}"+config.selector+" .social.active.middle.left{-webkit-transform:scale(1) translateX(-20px);-ms-transform:scale(1) translateX(-20px);transform:scale(1) translateX(-20px)}"+config.selector+" .social ul{position:relative;
16085left:0;right:0;height:46px;color:#fff;margin:auto;padding:0;list-style:none}"+config.selector+" .social ul li{font-size:20px;cursor:pointer;width:60px;margin:0;padding:12px 0;text-align:center;float:left;display:none;height:22px;position:relative;z-index:2;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" .social ul li:hover{}"+config.selector+" .social li[class*=facebook]{display:"+config.networks.facebook.display+"}"+config.selector+" .social li[class*=twitter]{display:"+config.networks.twitter.display+"}"+config.selector+" .social li[class*=gplus]{display:"+config.networks.google_plus.display+"}"+config.selector+" .social li[class*=pinterest]{display:"+config.networks.pinterest.display+"}"+config.selector+" .social li[class*=paper-plane]{display:"+config.networks.email.display+"}"
16086};
16087  var ShareUtils;
16088
16089if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
16090  Object.defineProperty(HTMLElement.prototype, "classList", {
16091    get: function() {
16092      var ret, self, update;
16093      update = function(fn) {
16094        return function(value) {
16095          var classes, index;
16096          classes = self.className.split(/\s+/);
16097          index = classes.indexOf(value);
16098          fn(classes, index, value);
16099          self.className = classes.join(" ");
16100        };
16101      };
16102      self = this;
16103      ret = {
16104        add: update(function(classes, index, value) {
16105          ~index || classes.push(value);
16106        }),
16107        remove: update(function(classes, index) {
16108          ~index && classes.splice(index, 1);
16109        }),
16110        toggle: update(function(classes, index, value) {
16111          if (~index) {
16112            classes.splice(index, 1);
16113          } else {
16114            classes.push(value);
16115          }
16116        }),
16117        contains: function(value) {
16118          return !!~self.className.split(/\s+/).indexOf(value);
16119        },
16120        item: function(i) {
16121          return self.className.split(/\s+/)[i] || null;
16122        }
16123      };
16124      Object.defineProperty(ret, "length", {
16125        get: function() {
16126          return self.className.split(/\s+/).length;
16127        }
16128      });
16129      return ret;
16130    }
16131  });
16132}
16133
16134String.prototype.to_rfc3986 = function() {
16135  var tmp;
16136  tmp = encodeURIComponent(this);
16137  return tmp.replace(/[!'()*]/g, function(c) {
16138    return "%" + c.charCodeAt(0).toString(16);
16139  });
16140};
16141
16142ShareUtils = (function() {
16143  function ShareUtils() {}
16144
16145  ShareUtils.prototype.extend = function(to, from, overwrite) {
16146    var hasProp, prop;
16147    for (prop in from) {
16148      hasProp = to[prop] !== undefined;
16149      if (hasProp && typeof from[prop] === "object") {
16150        this.extend(to[prop], from[prop], overwrite);
16151      } else {
16152        if (overwrite || !hasProp) {
16153          to[prop] = from[prop];
16154        }
16155      }
16156    }
16157  };
16158
16159  ShareUtils.prototype.hide = function(el) {
16160    return el.style.display = "none";
16161  };
16162
16163  ShareUtils.prototype.show = function(el) {
16164    return el.style.display = "block";
16165  };
16166
16167  ShareUtils.prototype.has_class = function(el, class_name) {
16168    return el.classList.contains(class_name);
16169  };
16170
16171  ShareUtils.prototype.add_class = function(el, class_name) {
16172    return el.classList.add(class_name);
16173  };
16174
16175  ShareUtils.prototype.remove_class = function(el, class_name) {
16176    return el.classList.remove(class_name);
16177  };
16178
16179  ShareUtils.prototype.is_encoded = function(str) {
16180    str = str.to_rfc3986();
16181    return decodeURIComponent(str) !== str;
16182  };
16183
16184  ShareUtils.prototype.encode = function(str) {
16185    if (typeof str === "undefined" || this.is_encoded(str)) {
16186      return str;
16187    } else {
16188      return str.to_rfc3986();
16189    }
16190  };
16191
16192  ShareUtils.prototype.popup = function(url, params) {
16193    var k, popup, qs, v;
16194    if (params == null) {
16195      params = {};
16196    }
16197    popup = {
16198      width: 500,
16199      height: 350
16200    };
16201    popup.top = (screen.height / 2) - (popup.height / 2);
16202    popup.left = (screen.width / 2) - (popup.width / 2);
16203    qs = ((function() {
16204      var _results;
16205      _results = [];
16206      for (k in params) {
16207        v = params[k];
16208        _results.push("" + k + "=" + (this.encode(v)));
16209      }
16210      return _results;
16211    }).call(this)).join('&');
16212    if (qs) {
16213      qs = "?" + qs;
16214    }
16215    return window.open(url + qs, 'targetWindow', "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,left=" + popup.left + ",top=" + popup.top + ",width=" 
16215+ popup.width + ",height=" + popup.height);
16216  };
16217
16218  return ShareUtils;
16219
16220})();
16221var Share,
16222  __hasProp = {}.hasOwnProperty,
16223  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
16224
16225Share = (function(_super) {
16226  __extends(Share, _super);
16227
16228  function Share(element, options) {
16229    this.element = element;
16230    this.el = {
16231      head: document.getElementsByTagName('head')[0],
16232      body: document.getElementsByTagName('body')[0]
16233    };
16234    this.config = {
16235      enabled_networks: 0,
16236      protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
16237      url: window.location.href.replace("&", "%26"),
16238      caption: null,
16239      title: this.default_title(),
16240      image: this.default_image(),
16241      description: this.default_description(),
16242      ui: {
16243        flyout: 'top center',
16244        button_text: 'Share',
16245        button_font: true,
16246        icon_font: true
16247      },
16248      networks: {
16249        google_plus: {
16250          enabled: true,
16251          url: null
16252        },
16253        twitter: {
16254          enabled: true,
16255          url: null,
16256          title: null,
16257          description: null
16258        },
16259        facebook: {
16260          enabled: true,
16261          load_sdk: true,
16262          url: null,
16263          app_id: null,
16264          title: null,
16265          caption: null,
16266          description: null,
16267          image: null
16268        },
16269        pinterest: {
16270          enabled: true,
16271          url: null,
16272          image: null,
16273          description: null
16274        },
16275        reddit: {
16276          enabled: true,
16277          url: null,
16278          title: null
16279        },
16280        linkedin: {
16281          enabled: true,
16282          url: null,
16283          title: null,
16284          description: null
16285        },
16286        xing: {
16287          enabled: true,
16288          url: null,
16289          title: null,
16290          image: null,
16291          description: null
16292        },
16293        whatsapp: {
16294          enabled: true,
16295          description: null,
16296          url: null
16297        },
16298        email: {
16299          enabled: true,
16300          title: null,
16301          description: null,
16302          url: null
16303        }
16304      }
16305    };
16306    this.setup(element, options);
16307    return this;
16308  }
16309
16310  Share.prototype.setup = function(element, opts) {
16311    var index, instance, instances, _i, _len;
16312    instances = document.querySelectorAll(element);
16313    this.extend(this.config, opts, true);
16314    this.set_global_configuration();
16315    this.normalize_network_configuration();
16316    if (this.config.ui.icon_font) {
16317      this.inject_icons();
16318    }
16319    if (this.config.ui.button_font) {
16320      this.inject_fonts();
16321    }
16322    if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
16323      this.inject_facebook_sdk();
16324    }
16325    for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
16326      instance = instances[index];
16327      this.setup_instance(element, index);
16328    }
16329  };
16330
16331  Share.prototype.setup_instance = function(element, index) {
16332    var button, instance, label, network, networks, _i, _len, _results,
16333      _this = this;
16334    instance = document.querySelectorAll(element)[index];
16335    this.hide(instance);
16336    this.add_class(instance, "sharer-" + index);
16337    instance = document.querySelectorAll(element)[index];
16338    this.inject_css(instance);
16339    this.inject_html(instance);
16340    this.show(instance);
16341    label = instance.getElementsByTagName("label")[0];
16342    button = instance.getElementsByClassName("social")[0];
16343    networks = instance.getElementsByTagName('li');
16344    this.add_class(button, "networks-" + this.config.enabled_networks);
16345    label.addEventListener("click", function() {
16346      return _this.event_toggle(button);
16347    });
16348    _this = this;
16349    _results = [];
16350    for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
16351      network = networks[index];
16352      _results.push(network.addEventListener("click", function() {
16353        _this.event_network(instance, this);
16354        return _this.event_close(button);
16355      }));
16356    }
16357    return _results;
16358  };
16359
16360  Share.prototype.event_toggle = function(button) {
16361    if (this.has_class(button, "active")) {
16362      return this.event_close(button);
16363    } else {
16364      return this.event_open(button);
16365    }
16366  };
16367
16368  Share.prototype.event_open = function(button) {
16369    if (this.has_class(button, "load")) {
16370      this.remove_class(button, "load");
16371    }
16372    return this.add_class(button, "active");
16373  };
16374
16375  Share.prototype.event_close = function(button) {
16376    return this.remove_class(button, "active");
16377  };
16378
16379  Share.prototype.event_network = function(instance, network) {
16380    var name;
16381    name = network.getAttribute("data-network");
16382    this.hook("before", name, instance);
16383    this["network_" + name]();
16384    return this.hook("after", name, instance);
16385  };
16386
16387  Share.prototype.open = function() {
16388    return this["public"]("open");
16389  };
16390
16391  Share.prototype.close = function() {
16392    return this["public"]("close");
16393  };
16394
16395  Share.prototype.toggle = function() {
16396    return this["public"]("toggle");
16397  };
16398
16399  Share.prototype["public"] = function(action) {
16400    var button, index, instance, _i, _len, _ref, _results;
16401    _ref = document.querySelectorAll(this.element);
16402    _results = [];
16403    for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
16404      instance = _ref[index];
16405      button = instance.getElementsByClassName("social")[0];
16406      _results.push(this["event_" + action](button));
16407    }
16408    return _results;
16409  };
16410
16411  Share.prototype.network_facebook = function() {
16412    if (this.config.networks.facebook.load_sdk) {
16413      if (!window.FB) {
16414        return console.error("The Facebook JS SDK hasn't loaded yet.");
16415      }
16416      return FB.ui({
16417        method: 'feed',
16418        name: this.config.networks.facebook.title,
16419        link: this.config.networks.facebook.url,
16420        picture: this.config.networks.facebook.image,
16421        caption: this.config.networks.facebook.caption,
16422        description: this.config.networks.facebook.description
16423      });
16424    } else {
16425      return this.popup('https://www.facebook.com/sharer/sharer.php', {
16426        u: this.config.networks.facebook.url
16427      });
16428    }
16429  };
16430
16431  Share.prototype.network_twitter = function() {
16432    return this.popup('https://twitter.com/intent/tweet', {
16433      text: this.config.networks.twitter.title,
16434      url: this.config.networks.twitter.url
16435    });
16436  };
16437
16438  Share.prototype.network_google_plus = function() {
16439    return this.popup('https://plus.google.com/share', {
16440      url: this.config.networks.google_plus.url
16441    });
16442  };
16443
16444  Share.prototype.network_pinterest = function() {
16445    return this.popup('https://www.pinterest.com/pin/create/button', {
16446      url: this.config.networks.pinterest.url,
16447      media: this.config.networks.pinterest.image,
16448      description: this.config.networks.pinterest.description
16449    });
16450  };
16451
16452  Share.prototype.network_linkedin = function() {
16453    return this.popup('https://www.linkedin.com/shareArticle', {
16454      url: this.config.networks.linkedin.url,
16455      title: this.config.networks.linkedin.title,
16456      summary: this.config.networks.linkedin.description
16457    });
16458  }
16459
16460  Share.prototype.network_xing = function() {
16461    return this.popup('https://www.xing.com/spi/shares/new', {
16462      url: this.config.networks.xing.url,
16463      image: this.config.networks.xing.image,
16464      title: this.config.networks.xing.title,
16465      summary: this.config.networks.xing.description
16466    });
16467  }
16468
16469  Share.prototype.network_email = function() {
16470    return this.popup('mailto:', {
16471      subject: this.config.networks.email.title,
16472      body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
16473    });
16474  };
16475
16476  Share.prototype.inject_icons = function() {
16477  //  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
16478  };
16479
16480  Share.prototype.inject_fonts = function() {
16481   // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
16482  };
16483
16484  Share.prototype.inject_stylesheet = function(url) {
16485    var link;
16486    if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
16487      link = document.createElement("link");
16488      link.setAttribute("rel", "stylesheet");
16489      link.setAttribute("href", url);
16490      return this.el.head.appendChild(link);
16491    }
16492  };
16493
16494  Share.prototype.inject_css = function(instance) {
16495    var css, meta, selector, style;
16496    selector = "." + (instance.getAttribute('class').split(" ").join("."));
16497    if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
16498      this.config.selector = selector;
16499      css = getStyles(this.config);
16500      style = document.createElement("style");
16501      style.type = "text/css";
16502      if (style.styleSheet) {
16503        style.styleSheet.cssText = css;
16504      } else {
16505        style.appendChild(document.createTextNode(css));
16506      }
16507      this.el.head.appendChild(style);
16508      delete this.config.selector;
16509      meta = document.createElement("meta");
16510      meta.setAttribute("name", "sharer" + selector);
16511      return this.el.head.appendChild(meta);
16512    }
16513  };
16514
16515  Share.prototype.inject_html = function(instance) {
16516    //return instance.innerHTML = "<label class='social-export'><span>" + this.config.ui.button_text + "</span></label><div class='social load " + this.config.ui.flyout + "'><ul><li class='social-facebook' data-network='facebook' tabindex='0'></li><li class='social-twitter' data-network='twitter' tabindex='0'></li><li class='social-gplus' data-network='google_plus' tabindex='0'></li><li class='social-pinterest' data-network='pinterest' tabindex='0'></li><li class='social-linkedin' data-network='linkedin' tabindex='0'></li><li class='social-xing' data-network='xing' tabindex='0'></li><li class='social-paper-plane' data-network='email' tabindex='0'></li></ul></div>";
16517    return instance.innerHTML = "<label class='social-export'><span>" + this.config.ui.button_text + "</span></label><div class='social load " + this.config.ui.flyout + "'><ul><li class='social-facebook' data-network='facebook' tabindex='0'></li><li class='social-twitter' data-network='twitter' tabindex='0'></li><li class='social-pinterest' data-network='pinterest' tabindex='0'></li><li class='social-linkedin' data-network='linkedin' tabindex='0'></li><li class='social-xing' data-network='xing' tabindex='0'></li><li class='social-paper-plane' data-network='email' tabindex='0'></li></ul></div>";
16518  };
16519
16520  Share.prototype.inject_facebook_sdk = function() {
16521    var fb_root, script;
16522    if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
16523      script = document.createElement("script");
16524      script.text = "window.fbAsyncInit=function(){FB.init({appId:'" + this.config.networks.facebook.app_id + "',status:true,xfbml:true})};(function(e,t,n){var r,i=e.getElementsByTagName(t)[0];if(e.getElementById(n)){return}r=e.createElement(t);r.id=n;r.src='" + this.config.protocol + "connect.facebook.net/en_US/all.js';i.parentNode.insertBefore(r,i)})(document,'script','facebook-jssdk')";
16525      fb_root = document.createElement("div");
16526      fb_root.id = "fb-root";
16527      this.el.body.appendChild(fb_root);
16528      return this.el.body.appendChild(script);
16529    }
16530  };
16531
16532  Share.prototype.hook = function(type, network, instance) {
16533    var fn, opts;
16534    fn = this.config.networks[network][type];
16535    if (typeof fn === "function") {
16536      opts = fn.call(this.config.networks[network], instance);
16537      if (opts !== void 0) {
16538        opts = this.normalize_filter_config_updates(opts);
16539        this.extend(this.config.networks[network], opts, true);
16540        this.normalize_network_configuration();
16541      }
16542    }
16543  };
16544
16545  Share.prototype.default_title = function() {
16546    var content;
16547    if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
16548      return encodeURIComponent(content.getAttribute('content'));
16549    } else if (content = document.querySelector('title')) {
16550      return encodeURIComponent(content.innerText);
16551    }
16552  };
16553
16554  Share.prototype.default_image = function() {
16555    var content;
16556    if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
16557      return content.getAttribute('content');
16558    }
16559  };
16560
16561  Share.prototype.default_description = function() {
16562    var content;
16563    if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
16564      return encodeURIComponent(content.getAttribute('content'));
16565    } else {
16566      return '';
16567    }
16568  };
16569
16570  Share.prototype.set_global_configuration = function() {
16571    var display, network, option, options, _ref, _results;
16572    _ref = this.config.networks;
16573    _results = [];
16574    for (network in _ref) {
16575      options = _ref[network];
16576      for (option in options) {
16577        if (this.config.networks[network][option] == null) {
16578          this.config.networks[network][option] = this.config[option];
16579        }
16580      }
16581      if (this.config.networks[network].enabled) {
16582        display = 'block';
16583        this.config.enabled_networks += 1;
16584      } else {
16585        display = 'none';
16586      }
16587      _results.push(this.config.networks[network].display = display);
16588    }
16589    return _results;
16590  };
16591
16592  Share.prototype.normalize_network_configuration = function() {
16593    if (!this.config.networks.facebook.app_id) {
16594      this.config.networks.facebook.load_sdk = false;
16595    }
16596    if (!this.is_encoded(this.config.networks.twitter.description)) {
16597      this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
16598    }
16599    if (typeof this.config.networks.facebook.app_id === 'number') {
16600      return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
16601    }
16602  };
16603
16604  Share.prototype.normalize_filter_config_updates = function(opts) {
16605    if (this.config.networks.facebook.app_id !== opts.app_id) {
16606      console.warn("You are unable to change the Facebook app_id after the button has been initialized. Please-in-out update your Facebook filters accordingly.");
16607      delete opts.app_id;
16608    }
16609    if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
16610      console.warn("You are unable to change the Facebook load_sdk option after the button has been initialized. Please-in-out update your Facebook filters accordingly.");
16611      delete opts.app_id;
16612    }
16613    return opts;
16614  };
16615
16616  return Share;
16617
16618})(ShareUtils);
16619 return Share;
16620});
16621
16622// Generated by CoffeeScript 1.9.2
16623
16624// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
16625
16626(function() {
16627  var $, win;
16628
16629  $ = this.jQuery || window.jQuery;
16630
16631  win = $(window);
16632
16633  $.fn.stick_in_parent = function(opts) {
16634    var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
16635    if (opts == null) {
16636      opts = {};
16637    }
16638    sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming;
16639    if (offset_top == null) {
16640      offset_top = 0;
16641    }
16642    if (parent_selector == null) {
16643      parent_selector = void 0;
16644    }
16645    if (inner_scrolling == null) {
16646      inner_scrolling = true;
16647    }
16648    if (sticky_class == null) {
16649      sticky_class = "is_stuck";
16650    }
16651    doc = $(document);
16652    if (enable_bottoming == null) {
16653      enable_bottoming = true;
16654    }
16655    outer_width = function(el) {
16656      var _el, computed, w;
16657      if (window.getComputedStyle) {
16658        _el = el[0];
16659        computed = window.getComputedStyle(el[0]);
16660        w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
16661        if (computed.getPropertyValue("box-sizing") !== "border-box") {
16662          w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
16663        }
16664        return w;
16665      } else {
16666        return el.outerWidth(true);
16667      }
16668    };
16669    fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
16670      var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
16671      if (elm.data("sticky_kit")) {
16672        return;
16673      }
16674      elm.data("sticky_kit", true);
16675      last_scroll_height = doc.height();
16676      parent = elm.parent();
16677      if (parent_selector != null) {
16678        parent = parent.closest(parent_selector);
16679      }
16680      if (!parent.length) {
16681        throw "failed to find stick parent";
16682      }
16683      fixed = false;
16684      bottomed = false;
16685      spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
16686      if (spacer) {
16687        spacer.css('position', elm.css('position'));
16688      }
16689      recalc = function() {
16690        var border_top, padding_top, restore;
16691        if (detached) {
16692          return;
16693        }
16694        last_scroll_height = doc.height();
16695        border_top = parseInt(parent.css("border-top-width"), 10);
16696        padding_top = parseInt(parent.css("padding-top"), 10);
16697        padding_bottom = parseInt(parent.css("padding-bottom"), 10);
16698        parent_top = parent.offset().top + border_top + padding_top;
16699        parent_height = parent.height();
16700        if (fixed) {
16701          fixed = false;
vendor: 6,068 bytes, lines 16702-16896
16702          bottomed = false;
16703          if (manual_spacer == null) {
16704            elm.insertAfter(spacer);
16705            spacer.detach();
16706          }
16707          elm.css({
16708            position: "",
16709            top: "",
16710            width: "",
16711            bottom: ""
16712          }).removeClass(sticky_class);
16713          restore = true;
16714        }
16715        top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
16716        height = elm.outerHeight(true);
16717        el_float = elm.css("float");
16718        if (spacer) {
16719          spacer.css({
16720            width: outer_width(elm),
16721            height: height,
16722            display: elm.css("display"),
16723            "vertical-align": elm.css("vertical-align"),
16724            "float": el_float
16725          });
16726        }
16727        if (restore) {
16728          return tick();
16729        }
16730      };
16731      recalc();
16732      if (height === parent_height) {
16733        return;
16734      }
16735      last_pos = void 0;
16736      offset = offset_top;
16737      recalc_counter = recalc_every;
16738      tick = function() {
16739        var css, delta, recalced, scroll, will_bottom, win_height;
16740        if (detached) {
16741          return;
16742        }
16743        recalced = false;
16744        if (recalc_counter != null) {
16745          recalc_counter -= 1;
16746          if (recalc_counter <= 0) {
16747            recalc_counter = recalc_every;
16748            recalc();
16749            recalced = true;
16750          }
16751        }
16752        if (!recalced && doc.height() !== last_scroll_height) {
16753          recalc();
16754          recalced = true;
16755        }
16756        scroll = win.scrollTop();
16757        if (last_pos != null) {
16758          delta = scroll - last_pos;
16759        }
16760        last_pos = scroll;
16761        if (fixed) {
16762          if (enable_bottoming) {
16763            will_bottom = scroll + height + offset > parent_height + parent_top;
16764            if (bottomed && !will_bottom) {
16765              bottomed = false;
16766              elm.css({
16767                position: "fixed",
16768                bottom: "",
16769                top: offset
16770              }).trigger("sticky_kit:unbottom");
16771            }
16772          }
16773          if (scroll < top) {
16774            fixed = false;
16775            offset = offset_top;
16776            if (manual_spacer == null) {
16777              if (el_float === "left" || el_float === "right") {
16778                elm.insertAfter(spacer);
16779              }
16780              spacer.detach();
16781            }
16782            css = {
16783              position: "",
16784              width: "",
16785              top: ""
16786            };
16787            elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
16788          }
16789          if (inner_scrolling) {
16790            win_height = win.height();
16791            if (height + offset_top > win_height) {
16792              if (!bottomed) {
16793                offset -= delta;
16794                offset = Math.max(win_height - height, offset);
16795                offset = Math.min(offset_top, offset);
16796                if (fixed) {
16797                  elm.css({
16798                    top: offset + "px"
16799                  });
16800                }
16801              }
16802            }
16803          }
16804        } else {
16805          if (scroll > top) {
16806            fixed = true;
16807            css = {
16808              position: "fixed",
16809              top: offset
16810            };
16811            css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
16812            elm.css(css).addClass(sticky_class);
16813            if (manual_spacer == null) {
16814              elm.after(spacer);
16815              if (el_float === "left" || el_float === "right") {
16816                spacer.append(elm);
16817              }
16818            }
16819            elm.trigger("sticky_kit:stick");
16820          }
16821        }
16822        if (fixed && enable_bottoming) {
16823          if (will_bottom == null) {
16824            will_bottom = scroll + height + offset > parent_height + parent_top;
16825          }
16826          if (!bottomed && will_bottom) {
16827            bottomed = true;
16828            if (parent.css("position") === "static") {
16829              parent.css({
16830                position: "relative"
16831              });
16832            }
16833            return elm.css({
16834              position: "absolute",
16835              bottom: padding_bottom,
16836              top: "auto"
16837            }).trigger("sticky_kit:bottom");
16838          }
16839        }
16840      };
16841      recalc_and_tick = function() {
16842        recalc();
16843        return tick();
16844      };
16845      detach = function() {
16846        detached = true;
16847        win.off("touchmove", tick);
16848        win.off("scroll", tick);
16849        win.off("resize", recalc_and_tick);
16850        $(document.body).off("sticky_kit:recalc", recalc_and_tick);
16851        elm.off("sticky_kit:detach", detach);
16852        elm.removeData("sticky_kit");
16853        elm.css({
16854          position: "",
16855          bottom: "",
16856          top: "",
16857          width: ""
16858        });
16859        parent.position("position", "");
16860        if (fixed) {
16861          if (manual_spacer == null) {
16862            if (el_float === "left" || el_float === "right") {
16863              elm.insertAfter(spacer);
16864            }
16865            spacer.remove();
16866          }
16867          return elm.removeClass(sticky_class);
16868        }
16869      };
16870      win.on("touchmove", tick);
16871      win.on("scroll", tick);
16872      win.on("resize", recalc_and_tick);
16873      $(document.body).on("sticky_kit:recalc", recalc_and_tick);
16874      elm.on("sticky_kit:detach", detach);
16875      return setTimeout(tick, 0);
16876    };
16877    for (i = 0, len = this.length; i < len; i++) {
16878      elm = this[i];
16879      fn($(elm));
16880    }
16881    return this;
16882  };
16883
16884}).call(this);
16885/* ==========================================================================
16886 * bootstrap-tab-history.js
16887 * Author: Michael Narayan <[email protected]>
16888 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
16889 * ==========================================================================
16890 * Licensed under the Apache License, Version 2.0 (the "License"); you may
16891 * not use this file except in compliance with the License. You may obtain a
16892 * copy of the License at
16893 *
16894 * http://www.apache.org/licenses/LICENSE-2.0
16895 *
16896 * Unless required by applicable law or agreed to in writing, softw
16896are
16897 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16898 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16899 * License for the specific language governing permissions and limitations
16900 * under the License.
16901 * ========================================================================== */
16902
16903/* ========================================================================== */
16904/* JSHint directives                                                          */
16905/*                                                                            */
16906/* global BootstrapTabHistory: true                                           */
16907/*                                                                            */
16908/* global document                                                            */
16909/* global jQuery                                                              */
16910/* global history                                                             */
16911/* global window                                                              */
16912/* ========================================================================== */
16913
16914/**
16915 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
16916 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
16917 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
16918 *
16919 * See the README for additional information.
16920 *
16921 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
16922 */
16923
16924BootstrapTabHistory = {
16925  options: {
16926    /**
16927     * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
16928     * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
16929     *
16930     * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
16931     *
16932     * @public
16933     * @type {?number}
16934     */
16935    defaultAnchorYOffset: 0,
16936    /**
16937     * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
16938     *
16939     * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
16940     *
16941     * @public
16942     * @type {string}
16943     */
16944    defaultChanger: 'replace',
16945    /**
16946     * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
16947     * `null` is passed as the third parameter to these calls.
16948     *
16949     * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
16950     *
16951     * @public
16952     * @type {boolean}
16953     */
16954    defaultUpdateURL: false,
16955    /**
16956     * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
16957     * load.
16958     *
16959     * @public
16960     * @type {boolean}
16961     */
16962    showTabsBasedOnAnchor: true
16963  }
16964};
16965
16966(function () {
16967  'use strict';
16968
16969  jQuery(function () {
16970    if(history && history.pushState && history.replaceState) {
16971      var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
16972
16973      if(bootstrapTabHistory) {
16974        showTabsBasedOnState(bootstrapTabHistory);
16975      } else {
16976        showTabsBasedOnAnchor();
16977      }
16978
16979      backfillHistoryState();
16980
16981      jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
16982      jQuery(window).on('popstate', onPopState);
16983    } else {
16984      showTabsBasedOnAnchor();
16985    }
16986  });
16987
16988  /**
16989   * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
16990   *
16991   * @type {boolean}
16992   */
16993  var showingTabsBasedOnState = false;
16994
16995  /**
16996   * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
16997   * `history.back` handling when `data-tab-history-update-url` is true.
16998   */
16999  function backfillHistoryState() {
17000    var newState = null;
17001
17002    jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
17003      var $activeTabElement = jQuery(this);
17004      var selector = getTabSelector($activeTabElement);
17005
17006      if(selector) {
17007        var tabGroup = getTabGroup($activeTabElement);
17008
17009        if(tabGroup) {
17010          newState = createNewHistoryState(newState || history.state, tabGroup, selector);
17011        }
17012      }
17013    });
17014
17015    if(newState) {
17016      history.replaceState(newState, '', null);
17017    }
17018  }
17019
17020  /**
17021   * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
17022   * said bootstrapTabHistory attribute.
17023   *
17024   * @param {?object} existingState
17025   * @param {!string} tabGroup
17026   * @param {!string} selector
17027   * @returns {!object}
17028   */
17029  function createNewHistoryState(existingState, tabGroup, selector) {
17030    // Clone history.state and ensure it has a bootstrapTabHistory entry.
17031    var newState = jQuery.extend(true, {}, existingState, {
17032      bootstrapTabHistory: {}
17033    });
17034
17035    newState.bootstrapTabHistory[tabGroup] = selector;
17036
17037    return newState;
17038  }
17039
17040  /**
17041   * @param {jQuery} $tab
17042   * @returns {?string}
17043   */
17044  function getTabGroup($tab) {
17045    return parseTruthyAttributeValue($tab.data('tab-history'));
17046  }
17047
17048  /**
17049   * @param {jQuery} $tab
17050   * @returns {?string}
17051   */
17052  function getTabSelector($tab) {
17053    return $tab.data('target') || $tab.attr('href');
17054  }
17055
17056  /**
17057   * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
17058   *
17059   * @param {jQuery.Event} shownEvt
17060   */
17061  function onShownTab(shownEvt) {
17062    if(!showingTabsBasedOnState) {
17063      var $activatedTab = jQuery(shownEvt.target);
17064      if ( $activatedTab.hasClass('panel-collapse') )
17065        $activatedTab = $activatedTab.closest('.panel').find('a');
17066      var selector = getTabSelector($activatedTab);
17067
17068      if(selector) {
17069        var tabGroup = getTabGroup($activatedTab);
17070
17071        if(tabGroup) {
17072          var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
17073          var newState = createNewHistoryState(history.state, tabGroup, selector);
17074          var updateURL = (function ($activatedTab) {
17075            if(selector[0] === '#') {
17076              var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
17077
17078              if(elementUpdateURLOption === undefined) {
17079                return BootstrapTabHistory.options.defaultUpdateURL;
17080              } else {
17081                return elementUpdateURLOption;
17082              }
17083            } else {
17084              return false;
17085            }
17086          })($activatedTab);
17087
17088          switch(historyChanger) {
17089            case 'push':
17090              history.pushState(newState, '', updateURL ? selector : null);
17091              break;
17092            case 'replace':
17093              history.replaceState(newState, '', updateURL ? selector : null);
17094              break;
17095            default:
17096              throw new Error('Unknown tab-history-changer: ' + historyChanger);
17097          }
17098        }
17099      }
17100    }
17101  }
17102
17103  /**
17104   * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
17105   */
17106  function onPopState() {
17107    var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
17108
17109    if(bootstrapTabHistory) {
17110      showTabsBasedOnState(bootstrapTabHistory);
17111    }
17112  }
17113
17114  /**
17115   * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
17116   *
17117   * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
17118   *
17119   * @param {*} value
17120   * @returns {*}
17121   */
17122  function parseTruthyAttributeValue(value) {
17123    if(value) {
17124      return value;
17125    } else if(value === '') {
17126      return true;
17127    } else {
17128      return value;
17129    }
17130  }
17131
17132  /**
17133   * Show tabs based upon the anchor component of `window.location`.
17134   */
17135  function showTabsBasedOnAnchor() {
17136    if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
17137      var anchor = window.location && window.location.hash;
17138
17139      if(anchor) {
17140        var $tabElement = showTabForSelector(anchor);
17141
17142        if($tabElement && window.addEventListener && window.removeEventListener) {
17143          var anchorYOffset = (function ($tabElement) {
17144            var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
17145
17146            if(elementSetting === undefined) {
17147              return BootstrapTabHistory.options.defaultAnchorYOffset;
17148            } else {
17149              return elementSetting;
17150            }
17151          })($tabElement);
17152
17153          // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
17154          //   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
17155          //   `history.state` object should have been used (unless the browser did not support the modern History API).
17156          if(anchorYOffset || anchorYOffset === 0) {
17157            var scrollListener = function resetAnchorScroll () {
17158              window.removeEventListener('scroll', scrollListener);
17159              window.scrollTo(0, anchorYOffset);
17160            };
17161
17162            window.addEventListener('scroll', scrollListener);
17163          }
17164        }
17165      }
17166    }
17167  }
17168
17169  /**
17170   * Show a tab which corresponds to the provided selector.
17171   *
17172   * @param {string} selector - A CSS selector.
17173   * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
17174   */
17175  function showTabForSelector(selector) {
17176    var $tabElement = (function (selector) {
17177      var $ret = null;
17178
17179      jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
17180        var $potentialTab = jQuery(this);
17181
17182        if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
17183          $ret = $potentialTab;
17184          return false;
vendor: 4,522 bytes, lines 17185-17334
17185        } else {
17186         return null;
17187        }
17188      });
17189
17190      return $ret;
17191    })(selector);
17192
17193    if($tabElement) {
17194      $tabElement.trigger('click');
17195      //$tabElement.tab('show');
17196    }
17197
17198    return $tabElement;
17199  }
17200
17201  /**
17202   * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
17203   *
17204   * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
17205   */
17206  function showTabsBasedOnState(bootstrapTabHistory) {
17207    showingTabsBasedOnState = true;
17208
17209    try {
17210      for(var k in bootstrapTabHistory) {
17211        if(bootstrapTabHistory.hasOwnProperty(k)) {
17212          showTabForSelector(bootstrapTabHistory[k]);
17213        }
17214      }
17215    } finally {
17216      showingTabsBasedOnState = false;
17217    }
17218  }
17219})();
17220
17221/*!
17222 * Justified Gallery - v3.6.3
17223 * http://miromannino.github.io/Justified-Gallery/
17224 * Copyright (c) 2016 Miro Mannino
17225 * Licensed under the MIT license.
17226 */
17227(function($) {
17228
17229  function hasScrollBar() {
17230    return $("body").height() > $(window).height();
17231  }
17232  /**
17233   * Justified Gallery controller constructor
17234   *
17235   * @param $gallery the gallery to build
17236   * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults)
17237   * @constructor
17238   */
17239  var JustifiedGallery = function ($gallery, settings) {
17240    
17241    this.settings = settings;
17242    this.checkSettings();
17243
17244    this.imgAnalyzerTimeout = null;
17245    this.entries = null;
17246    this.buildingRow = {
17247      entriesBuff : [],
17248      width : 0,
17249      height : 0,
17250      aspectRatio : 0
17251    };
17252    this.lastFetchedEntry = null;
17253    this.lastAnalyzedIndex = -1;
17254    this.yield = {
17255      every : 2, // do a flush every n flushes (must be greater than 1)
17256      flushed : 0 // flushed rows without a yield
17257    };
17258    this.border = settings.border >= 0 ? settings.border : settings.margins;
17259    this.maxRowHeight = this.retrieveMaxRowHeight();
17260    this.suffixRanges = this.retrieveSuffixRanges();
17261    this.offY = this.border;
17262    this.rows = 0;
17263    this.spinner = {
17264      phase : 0,
17265      timeSlot : 150,
17266      $el : $('<div class="spinner"><span></span><span></span><span></span></div>'),
17267      intervalId : null
17268    };
17269    this.checkWidthIntervalId = null;
17270    this.galleryWidth = $gallery.width();
17271    this.$gallery = $gallery;
17272
17273  };
17274
17275  /** @returns {String} the best suffix given the width and the height */
17276  JustifiedGallery.prototype.getSuffix = function (width, height) {
17277    var longestSide, i;
17278    longestSide = (width > height) ? width : height;
17279    for (i = 0; i < this.suffixRanges.length; i++) {
17280      if (longestSide <= this.suffixRanges[i]) {
17281        return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
17282      }
17283    }
17284    return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
17285  };
17286
17287  /**
17288   * Remove the suffix from the string
17289   *
17290   * @returns {string} a new string without the suffix
17291   */
17292  JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
17293    return str.substring(0, str.length - suffix.length);
17294  };
17295
17296  /**
17297   * @returns {boolean} a boolean to say if the suffix is contained in the str or not
17298   */
17299  JustifiedGallery.prototype.endsWith = function (str, suffix) {
17300    return str.indexOf(suffix, str.length - suffix.length) !== -1;
17301  };
17302
17303  /**
17304   * Get the used suffix of a particular url
17305   *
17306   * @param str
17307   * @returns {String} return the used suffix
17308   */
17309  JustifiedGallery.prototype.getUsedSuffix = function (str) {
17310    for (var si in this.settings.sizeRangeSuffixes) {
17311      if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
17312        if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
17313        if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
17314      }
17315    }
17316    return '';
17317  };
17318
17319  /**
17320   * Given an image src, with the width and the height, returns the new image src with the
17321   * best suffix to show the best quality thumbnail.
17322   *
17323   * @returns {String} the suffix to use
17324   */
17325  JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
17326    var newImageSrc;
17327
17328    if (this.settings.thumbnailPath) {
17329      newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
17330    } else {
17331      var matchRes = imageSrc.match(this.settings.extension);
17332      var ext = (matchRes !== null) ? matchRes[0] : '';
17333      newImageSrc = imageSrc.replace(this.settings.extension, '');
17334      newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
17335      newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
17336    }
17337
17338    return newImageSrc;
17339  };
17340
17341  /**
17342   * Shows the images that is in the given entry
17343   *
17344   * @param $entry the entry
17345   * @param callback the callback that is called when the show animation is finished
17346   */
17347  JustifiedGallery.prototype.showImg = function ($entry, callback) {
17348    if (this.settings.cssAnimation) {
17349      $entry.addClass('entry-visible');
17350      if (callback) callback();
17351    } else {
17352      $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
17353      $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
17354    }
17355  };
17356
17357  /**
17358   * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
17359   * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
17360   *
17361   * @param $image the image to analyze
17362   * @returns {String} the extracted src
17363   */
17364  JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
17365    var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src');
17366    $image.data('jg.originalSrc', imageSrc);
17367    return imageSrc;
17368  };
17369
17370  /** @returns {jQuery} the image in the given entry */
17371  JustifiedGallery.prototype.imgFromEntry = function ($entry) {
17372    var $img = $entry.find('> img');
17373    if ($img.length === 0) $img = $entry.find('> a > img');
17374    if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
17375    return $img.length === 0 ? null : $img;
17376  };
17377
17378  /** @returns {jQuery} the caption in the given entry */
17379  JustifiedGallery.prototype.captionFromEntry = function ($entry) {
17380    var $caption = $entry.find('> .caption');
17381    return $caption.length === 0 ? null : $caption;
17382  };
17383
17384  /**
17385   * Display the entry
17386   *
17387   * @param {jQuery} $entry the entry to display
17388   * @param {int} x the x position where the entry must be positioned
17389   * @param y the y position where the entry must be positioned
17390   * @param imgWidth the image width
17391   * @param imgHeight the image height
17392   * @param rowHeight the row height of the row that owns the entry
17393   */
17394  JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
17395    $entry.width(imgWidth);
17396    $entry.height(Math.floor(rowHeight));//hacked by Uncode
17397    $entry.css('top', Math.floor(y));//hacked by Uncode
17398    $entry.css('left', x);
17399
17400    var $image = this.imgFromEntry($entry);
17401    if ($image !== null) {
17402      $image.css('width', imgWidth);
17403      $image.css('height', imgHeight);
17404      $image.css('margin-left', - imgWidth / 2);
17405      $image.css('margin-top', - imgHeight / 2);
17406
17407      // Image reloading for an high quality of thumbnails
17408      var imageSrc = $image.attr('src');
17409      var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
17410
17411      $image.one('error', function () {
17412        $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it.
17413      });
17414
17415      var loadNewImage = function () {
17416        if (imageSrc !== newImageSrc) { //load the new image after the fadeIn
17417          $image.attr('src', newImageSrc);
17418        }
17419      };
17420
17421      if ($entry.data('jg.loaded') === 'skipped') {
17422        this.onImageEvent(imageSrc, $.proxy(function() {
17423          this.showImg($entry, loadNewImage);
17424          $entry.data('jg.loaded', true);
17425        }, this));
17426      } else {
17427        this.showImg($entry, loadNewImage);
17428      }
17429
17430    } else {
17431      this.showImg($entry);
17432    }
17433
17434    this.displayEntryCaption($entry);
17435  };
17436
17437  /**
17438   * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
17439   * or the 'title' attributes.
17440   *
17441   * @param {jQuery} $entry the entry to process
17442   */
17443  JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
17444    var $image = this.imgFromEntry($entry);
17445    if ($image !== null && this.settings.captions) {
17446      var $imgCaption = this.captionFromEntry($entry);
17447
17448      // Create it if it doesn't exists
17449      if ($imgCaption === null) {
17450        var caption = $image.attr('alt');
17451        if (!this.isValidCaption(caption)) caption = $entry.attr('title');
17452        if (this.isValidCaption(caption)) { // Create only we found something
17453          $imgCaption = $('<div class="caption">' + caption + '</div>');
17454          $entry.append($imgCaption);
17455          $entry.data('jg.createdCaption', true);
17456        }
17457      }
17458
17459      // Create events (we check again the $imgCaption because it can be still inexistent)
17460      if ($imgCaption !== null) {
17461        if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
17462        this.addCaptionEventsHandlers($entry);
17463      }
17464    } else {
17465      this.removeCaptionEventsHandlers($entry);
17466    }
17467  };
17468
17469  /**
17470   * Validates the caption
17471   *
17472   * @param caption The caption that should be validated
17473   * @return {boolean} Validation result
17474   */
17475  JustifiedGallery.prototype.isValidCaption = function (caption) {
17476    return (typeof caption !== 'undefined' && caption.length > 0);
17477  };
17478
17479  /**
17480   * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
17481   * It shows the caption using jQuery (or using CSS if it is configured so)
17482   *
17483   * @param {Event} eventObject the event object
17484   */
17485  JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
17486    var $caption = this.captionFromEntry($(eventObject.currentTarget));
17487    if (this.settings.cssAnimation) {
17488      $caption.addClass('caption-visible').removeClass('caption-hidden');
17489    } else {
17490      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
17491          this.settings.captionSettings.visibleOpacity);
17492    }
17493  };
17494
17495  /**
17496   * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
17497   * It hides the caption using jQuery (or using CSS if it is configured so)
17498   *
17499   * @param {Event} eventObject the event object
17500   */
17501  JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
17502    var $caption = this.captionFromEntry($(eventObject.currentTarget));
17503    if (this.settings.cssAnimation) {
17504      $caption.removeClass('caption-visible').removeClass('caption-hidden');
17505    } else {
17506      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
17507          this.settings.captionSettings.nonVisibleOpacity);
17508    }
17509  };
17510
17511  /**
17512   * Add the handlers of the entry for the caption
17513   *
17514   * @param $entry the entry to modify
17515   */
17516  JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
17517    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
17518    if (typeof captionMouseEvents === 'undefined') {
17519      captionMouseEvents = {
17520        mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
17521        mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
17522      };
17523      $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
17524      $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
17525      $entry.data('jg.captionMouseEvents', captionMouseEvents);
17526    }
17527  };
17528
17529  /**
17530   * Remove the handlers of the entry for the caption
17531   *
17532   * @param $entry the entry to modify
17533   */
17534  JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
17535    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
17536    if (typeof captionMouseEvents !== 'undefined') {
17537      $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
17538      $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
17539      $entry.removeData('jg.captionMouseEvents');
17540    }
17541  };
17542
17543  /**
17544   * Justify the building row, preparing it to
17545   *
17546   * @param isLastRow
17547   * @returns a boolean to know if the row has been justified or not
17548   */
17549  JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) {
17550    var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
17551    var minHeight = 0;
17552    var availableWidth = this.galleryWidth - 2 * this.border - (
17553        (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
17554    var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
17555    var defaultRowHeight = this.settings.rowHeight;
17556    var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
17557
17558    //Skip the last row if we can't justify it and the lastRow == 'hide'
17559    if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) {
17560      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17561        $entry = this.buildingRow.entriesBuff[i];
17562        if (this.settings.cssAnimation)
17563          $entry.removeClass('entry-visible');
17564        else {
17565          $entry.stop().fadeTo(0, 0.1);
17566          $entry.find('> img, > a > img').fadeTo(0, 0);
17567        }
17568      }
17569      return -1;
17570    }
17571
17572    // With lastRow = nojustify, justify if is justificable (the images will not become too big)
17573    if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
17574      justify = false;
17575
17576      if (this.rows > 0) {
17577        defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
17578        justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
17579      }
17580    }
17581
17582    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17583      $entry = this.buildingRow.entriesBuff[i];
17584      imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
17585
17586      if (justify) {
17587        newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
17588        newImgH = rowHeight;
17589      } else {
17590        newImgW = defaultRowHeight * imgAspectRatio;
17591        newImgH = defaultRowHeight;
17592      }
17593
17594      availableWidth -= Math.round(newImgW);
17595      $entry.data('jg.jwidth', Math.round(newImgW));
17596      $entry.data('jg.jheight', Math.ceil(newImgH));
17597      if (i === 0 || minHeight > newImgH) minHeight = newImgH;
17598    }
17599
17600    this.buildingRow.height = minHeight;
17601    return justify;
17602  };
17603
17604  /**
17605   * Clear the building row data to be used for a new row
17606   */
17607  JustifiedGallery.prototype.clearBuildingRow = function () {
17608    this.buildingRow.entriesBuff = [];
17609    this.buildingRow.aspectRatio = 0;
17610    this.buildingRow.width = 0;
17611  };
17612
17613  /**
17614   * Flush a row: justify it, modify the gallery height accordingly to the row height
17615   *
17616   * @param isLastRow
17617   */
17618  JustifiedGallery.prototype.flushRow = function (isLastRow) {
17619    var settings = this.settings;
17620    var $entry, buildingRowRes, offX = this.border, i;
17621
17622    buildingRowRes = this.prepareBuildingRow(isLastRow);
17623    if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) {
17624      this.clearBuildingRow();
17625      return;
17626    }
17627
17628    if (this.maxRowHeight) {
17629      if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) {
17630        this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight;
17631      } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) {
17632        this.buildingRow.height = this.maxRowHeight.value;
17633      }
17634    }
17635
17636    //Align last (unjustified) row
17637    if (settings.lastRow === 'center' || settings.lastRow === 'right') {
17638      var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
17639
17640      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17641        $entry = this.buildingRow.entriesBuff[i];
17642        availableWidth -= $entry.data('jg.jwidth');
17643      }
17644
17645      if (settings.lastRow === 'center')
17646        offX += availableWidth / 2;
17647      else if (settings.lastRow === 'right')
17648        offX += availableWidth;
17649    }
17650
17651    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17652      $entry = this.buildingRow.entriesBuff[i];
17653      this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
17654      offX += $entry.data('jg.jwidth') + settings.margins;
17655    }
17656
17657    //Gallery Height
17658    this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
17659    this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight());
17660
17661    if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
17662      //Ready for a new row
17663      this.offY += this.buildingRow.height + settings.margins;
17664      this.rows += 1;
17665      this.clearBuildingRow();
17666      this.$gallery.trigger('jg.rowflush');
17667    }
17668  };
17669
17670  /**
17671   * Checks the width of the gallery container, to know if a new justification is needed
17672   */
17673  var scrollBarOn = false;
17674  JustifiedGallery.prototype.checkWidth = function () {
17675    this.checkWidthIntervalId = setInterval($.proxy(function () {
17676      var galleryWidth = parseFloat(this.$gallery.width());
17677      if (hasScrollBar() === scrollBarOn) {
17678        if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
17679          this.galleryWidth = galleryWidth;
17680          this.rewind();
17681
17682          // Restart to analyze
17683          this.startImgAnalyzer(true);
17684        }
17685      } else {
17686        scrollBarOn = hasScrollBar();
17687        this.galleryWidth = galleryWidth;
17688      }
17689    }, this), this.settings.refreshTime);
17690  };
17691
17692  /**
17693   * @returns {boolean} a boolean saying if the spinner is active or not
17694   */
17695  JustifiedGallery.prototype.isSpinnerActive = function () {
17696    return this.spinner.intervalId !== null;
17697  };
17698
17699  /**
17700   * @returns {int} the spinner height
17701   */
17702  JustifiedGallery.prototype.getSpinnerHeight = function () {
17703    return this.spinner.$el.innerHeight();
17704  };
17705
17706  /**
17707   * Stops the spinner animation and modify the gallery height to exclude the spinner
17708   */
17709  JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
17710    clearInterval(this.spinner.intervalId);
17711    this.spinner.intervalId = null;
17712    this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight());
17713    this.spinner.$el.detach();
17714  };
17715
17716  /**
17717   * Starts the spinner animation
17718   */
17719  JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
17720    var spinnerContext = this.spinner;
17721    var $spinnerPoints = spinnerContext.$el.find('span');
17722    clearInterval(spinnerContext.intervalId);
17723    this.$gallery.append(spinnerContext.$el);
17724    this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight());
17725    spinnerContext.intervalId = setInterval(function () {
17726      if (spinnerContext.phase < $spinnerPoints.length) {
17727        $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
17728      } else {
vendor: 4,333 bytes, lines 17729-17873
17729        $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
17730      }
17731      spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
17732    }, spinnerContext.timeSlot);
17733  };
17734
17735  /**
17736   * Rewind the image analysis to start from the first entry.
17737   */
17738  JustifiedGallery.prototype.rewind = function () {
17739    this.lastFetchedEntry = null;
17740    this.lastAnalyzedIndex = -1;
17741    this.offY = this.border;
17742    this.rows = 0;
17743    this.clearBuildingRow();
17744  };
17745
17746  /**
17747   * Update the entries searching it from the justified gallery HTML element
17748   *
17749   * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
17750   * @returns {boolean} true if some entries has been founded
17751   */
17752  JustifiedGallery.prototype.updateEntries = function (norewind) {
17753    var newEntries;
17754
17755    if (norewind && this.lastFetchedEntry != null) {
17756      newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray();
17757    } else {
17758      this.entries = [];
17759      newEntries = this.$gallery.children(this.settings.selector).toArray();
17760    }
17761
17762    if (newEntries.length > 0) {
17763
17764      // Sort or randomize
17765      if ($.isFunction(this.settings.sort)) {
17766        newEntries = this.sortArray(newEntries);
17767      } else if (this.settings.randomize) {
17768        newEntries = this.shuffleArray(newEntries);
17769      }
17770      this.lastFetchedEntry = newEntries[newEntries.length - 1];
17771
17772      // Filter
17773      if (this.settings.filter) {
17774        newEntries = this.filterArray(newEntries);
17775      } else {
17776        this.resetFilters(newEntries);
17777      }
17778
17779    }
17780
17781    this.entries = this.entries.concat(newEntries);
17782    return true;
17783  };
17784
17785  /**
17786   * Apply the entries order to the DOM, iterating the entries and appending the images
17787   *
17788   * @param entries the entries that has been modified and that must be re-ordered in the DOM
17789   */
17790  JustifiedGallery.prototype.insertToGallery = function (entries) {
17791    var that = this;
17792    $.each(entries, function () {
17793      $(this).appendTo(that.$gallery);
17794    });
17795  };
17796
17797  /**
17798   * Shuffle the array using the Fisher-Yates shuffle algorithm
17799   *
17800   * @param a the array to shuffle
17801   * @return the shuffled array
17802   */
17803  JustifiedGallery.prototype.shuffleArray = function (a) {
17804    var i, j, temp;
17805    for (i = a.length - 1; i > 0; i--) {
17806      j = Math.floor(Math.random() * (i + 1));
17807      temp = a[i];
17808      a[i] = a[j];
17809      a[j] = temp;
17810    }
17811    this.insertToGallery(a);
17812    return a;
17813  };
17814
17815  /**
17816   * Sort the array using settings.comparator as comparator
17817   *
17818   * @param a the array to sort (it is sorted)
17819   * @return the sorted array
17820   */
17821  JustifiedGallery.prototype.sortArray = function (a) {
17822    a.sort(this.settings.sort);
17823    this.insertToGallery(a);
17824    return a;
17825  };
17826
17827  /**
17828   * Reset the filters removing the 'jg-filtered' class from all the entries
17829   *
17830   * @param a the array to reset
17831   */
17832  JustifiedGallery.prototype.resetFilters = function (a) {
17833    for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
17834  };
17835
17836  /**
17837   * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
17838   *
17839   * @param a the array to filter
17840   * @return the filtered array
17841   */
17842  JustifiedGallery.prototype.filterArray = function (a) {
17843    var settings = this.settings;
17844    if ($.type(settings.filter) === 'string') {
17845      // Filter only keeping the entries passed in the string
17846      return a.filter(function (el) {
17847        var $el = $(el);
17848        if ($el.is(settings.filter)) {
17849          $el.removeClass('jg-filtered');
17850          return true;
17851        } else {
17852          $el.addClass('jg-filtered').removeClass('jg-visible');
17853          return false;
17854        }
17855      });
17856    } else if ($.isFunction(settings.filter)) {
17857      // Filter using the passed function
17858      var filteredArr = a.filter(settings.filter);
17859      for (var i = 0; i < a.length; i++) {
17860        if (filteredArr.indexOf(a[i]) == -1) {
17861          $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
17862        } else {
17863          $(a[i]).removeClass('jg-filtered');
17864        }
17865      }
17866      return filteredArr;
17867    }
17868  };
17869
17870  /**
17871   * Destroy the Justified Gallery instance.
17872   *
17873   * It clears all the css properties added in the style attributes. We doesn't backup the original
17874   * values for those css attributes, because it costs (performance) and because in general one
17875   * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
17876   * classes). Creating a backup is also difficult because JG could be called multiple times and
17877   * with different style attributes.
17878   */
17879  JustifiedGallery.prototype.destroy = function () {
17880    clearInterval(this.checkWidthIntervalId);
17881
17882    $.each(this.entries, $.proxy(function(_, entry) {
17883      var $entry = $(entry);
17884
17885      // Reset entry style
17886      $entry.css('width', '');
17887      $entry.css('height', '');
17888      $entry.css('top', '');
17889      $entry.css('left', '');
17890      $entry.data('jg.loaded', undefined);
17891      $entry.removeClass('jg-entry');
17892
17893      // Reset image style
17894      var $img = this.imgFromEntry($entry);
17895      $img.css('width', '');
17896      $img.css('height', '');
17897      $img.css('margin-left', '');
17898      $img.css('margin-top', '');
17899      $img.attr('src', $img.data('jg.originalSrc'));
17900      $img.data('jg.originalSrc', undefined);
17901
17902      // Remove caption
17903      this.removeCaptionEventsHandlers($entry);
17904      var $caption = this.captionFromEntry($entry);
17905      if ($entry.data('jg.createdCaption')) {
17906        // remove also the caption element (if created by jg)
17907        $entry.data('jg.createdCaption', undefined);
17908        if ($caption !== null) $caption.remove();
17909      } else {
17910        if ($caption !== null) $caption.fadeTo(0, 1);
17911      }
17912
17913    }, this));
17914
17915    this.$gallery.css('height', '');
17916    this.$gallery.removeClass('justified-gallery');
17917    this.$gallery.data('jg.controller', undefined);
17918  };
17919
17920  /**
17921   * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
17922   *
17923   * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
17924   */
17925  JustifiedGallery.prototype.analyzeImages = function (isForResize) {
17926    for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
17927      var $entry = $(this.entries[i]);
17928      if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
17929        var availableWidth = this.galleryWidth - 2 * this.border - (
17930            (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
17931        var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
17932        if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
17933          this.flushRow(false);
17934          if(++this.yield.flushed >= this.yield.every) {
17935            this.startImgAnalyzer(isForResize);
17936            return;
17937          }
17938        }
17939
17940        this.buildingRow.entriesBuff.push($entry);
17941        this.buildingRow.aspectRatio += imgAspectRatio;
17942        this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
17943        this.lastAnalyzedIndex = i;
17944
17945      } else if ($entry.data('jg.loaded') !== 'error') {
17946        return;
17947      }
17948    }
17949
17950    // Last row flush (the row is not full)
17951    if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true);
17952
17953    if (this.isSpinnerActive()) {
17954      this.stopLoadingSpinnerAnimation();
17955    }
17956
17957    /* Stop, if there is, the timeout to start the analyzeImages.
17958     This is because an image can be set loaded, and the timeout can be set,
17959     but this image can be analyzed yet.
17960     */
17961    this.stopImgAnalyzerStarter();
17962
17963    //On complete callback
17964    this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete');
17965    this.$gallery.height(this.galleryHeightToSet);
17966  };
17967
17968  /**
17969   * Stops any ImgAnalyzer starter (that has an assigned timeout)
17970   */
17971  JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
17972    this.yield.flushed = 0;
17973    if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout);
17974  };
17975
17976  /**
17977   * Starts the image analyzer. It is not immediately called to let the browser to update the view
17978   *
17979   * @param isForResize specifies if the image analyzer must be called for resizing or not
17980   */
17981  JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
17982    var that = this;
17983    this.stopImgAnalyzerStarter();
17984    this.imgAnalyzerTimeout = setTimeout(function () {
17985      that.analyzeImages(isForResize);
17986    }, 0.001); // we can't start it immediately due to a IE different behaviour
17987  };
17988
17989  /**
17990   * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
17991   * because some browsers, with a 404 set complete = true.
17992   *
17993   * @param imageSrc the image src to load
17994   * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 17995-18345
17995   * @param onError callback that is called in case of an error
17996   */
17997  JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
17998    if (!onLoad && !onError) return;
17999
18000    var memImage = new Image();
18001    var $memImage = $(memImage);
18002    if (onLoad) {
18003      $memImage.one('load', function () {
18004        $memImage.off('load error');
18005        onLoad(memImage);
18006      });
18007    }
18008    if (onError) {
18009      $memImage.one('error', function() {
18010        $memImage.off('load error');
18011        onError(memImage);
18012      });
18013    }
18014    memImage.src = imageSrc;
18015  };
18016
18017  /**
18018   * Init of Justified Gallery controlled
18019   * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
18020   */
18021  JustifiedGallery.prototype.init = function () {
18022    var imagesToLoad = false, skippedImages = false, that = this;
18023    $.each(this.entries, function (index, entry) {
18024      var $entry = $(entry);
18025      var $image = that.imgFromEntry($entry);
18026
18027      $entry.addClass('jg-entry');
18028
18029      if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
18030
18031        // Link Rel global overwrite
18032        if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
18033
18034        // Link Target global overwrite
18035        if (that.settings.target !== null) $entry.attr('target', that.settings.target);
18036
18037        if ($image !== null) {
18038
18039          // Image src
18040          var imageSrc = that.extractImgSrcFromImage($image);
18041          $image.attr('src', imageSrc);
18042
18043          /* If we have the height and the width, we don't wait that the image is loaded, but we start directly
18044           * with the justification */
18045          if (that.settings.waitThumbnailsLoad === false) {
18046            var width = parseFloat($image.attr('width'));
18047            var height = parseFloat($image.attr('height'));
18048            if (!isNaN(width) && !isNaN(height)) {
18049              $entry.data('jg.width', width);
18050              $entry.data('jg.height', height);
18051              $entry.data('jg.loaded', 'skipped');
18052              skippedImages = true;
18053              that.startImgAnalyzer(false);
18054              return true; // continue
18055            }
18056          }
18057
18058          $entry.data('jg.loaded', false);
18059          imagesToLoad = true;
18060
18061          // Spinner start
18062          if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
18063
18064          that.onImageEvent(imageSrc, function (loadImg) { // image loaded
18065            $entry.data('jg.width', loadImg.width);
18066            $entry.data('jg.height', loadImg.height);
18067            $entry.data('jg.loaded', true);
18068            that.startImgAnalyzer(false);
18069          }, function () { // image load error
18070            $entry.data('jg.loaded', 'error');
18071            that.startImgAnalyzer(false);
18072          });
18073
18074        } else {
18075          $entry.data('jg.loaded', true);
18076          $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
18077          $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
18078        }
18079
18080      }
18081
18082    });
18083
18084    if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
18085    this.checkWidth();
18086  };
18087
18088  /**
18089   * Checks that it is a valid number. If a string is passed it is converted to a number
18090   *
18091   * @param settingContainer the object that contains the setting (to allow the conversion)
18092   * @param settingName the setting name
18093   */
18094  JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
18095    if ($.type(settingContainer[settingName]) === 'string') {
18096      settingContainer[settingName] = parseFloat(settingContainer[settingName]);
18097    }
18098
18099    if ($.type(settingContainer[settingName]) === 'number') {
18100      if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
18101    } else {
18102      throw settingName + ' must be a number';
18103    }
18104  };
18105
18106  /**
18107   * Checks the sizeRangeSuffixes and, if necessary, converts
18108   * its keys from string (e.g. old settings with 'lt100') to int.
18109   */
18110  JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
18111    if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
18112      throw 'sizeRangeSuffixes must be defined and must be an object';
18113    }
18114
18115    var suffixRanges = [];
18116    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
18117      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
18118    }
18119
18120    var newSizeRngSuffixes = {0: ''};
18121    for (var i = 0; i < suffixRanges.length; i++) {
18122      if ($.type(suffixRanges[i]) === 'string') {
18123        try {
18124          var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
18125          newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
18126        } catch (e) {
18127          throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
18128        }
18129      } else {
18130        newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
18131      }
18132    }
18133
18134    this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
18135  };
18136
18137  /**
18138   * check and convert the maxRowHeight setting
18139   */
18140  JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
18141    var newMaxRowHeight = { };
18142
18143    if ($.type(this.settings.maxRowHeight) === 'string') {
18144      if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
18145        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
18146        newMaxRowHeight.isPercentage = false;
18147      } else {
18148        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight);
18149        newMaxRowHeight.isPercentage = true;
18150      }
18151    } else if ($.type(this.settings.maxRowHeight) === 'number') {
18152      newMaxRowHeight.value = this.settings.maxRowHeight;
18153      newMaxRowHeight.isPercentage = false;
18154    } else if (this.settings.maxRowHeight === false ||
18155        this.settings.maxRowHeight === null ||
18156        typeof this.settings.maxRowHeight == 'undefined') {
18157      return null;
18158    } else {
18159      throw 'maxRowHeight must be a number or a percentage';
18160    }
18161
18162    // check if the converted value is not a number
18163    if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight';
18164
18165    // check values
18166    if (newMaxRowHeight.isPercentage) {
18167      if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100;
18168    }
18169
18170    return newMaxRowHeight;
18171  };
18172
18173  /**
18174   * Checks the settings
18175   */
18176  JustifiedGallery.prototype.checkSettings = function () {
18177    this.checkSizeRangesSuffixes();
18178
18179    this.checkOrConvertNumber(this.settings, 'rowHeight');
18180    this.checkOrConvertNumber(this.settings, 'margins');
18181    this.checkOrConvertNumber(this.settings, 'border');
18182
18183    var lastRowModes = [
18184      'justify',
18185      'nojustify',
18186      'left',
18187      'center',
18188      'right',
18189      'hide'
18190    ];
18191    if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
18192      throw 'lastRow must be one of: ' + lastRowModes.join(', ');
18193    }
18194
18195    this.checkOrConvertNumber(this.settings, 'justifyThreshold');
18196    if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
18197      throw 'justifyThreshold must be in the interval [0,1]';
18198    }
18199    if ($.type(this.settings.cssAnimation) !== 'boolean') {
18200      throw 'cssAnimation must be a boolean';
18201    }
18202
18203    if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
18204    this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
18205
18206    this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
18207    if (this.settings.captionSettings.visibleOpacity < 0 ||
18208        this.settings.captionSettings.visibleOpacity > 1) {
18209      throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
18210    }
18211
18212    this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
18213    if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
18214        this.settings.captionSettings.nonVisibleOpacity > 1) {
18215      throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
18216    }
18217
18218    this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
18219    this.checkOrConvertNumber(this.settings, 'refreshTime');
18220    this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
18221    if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
18222    if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
18223
18224    if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
18225      throw 'sort must be false or a comparison function';
18226    }
18227
18228    if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
18229        $.type(this.settings.filter) !== 'string') {
18230      throw 'filter must be false, a string or a filter function';
18231    }
18232  };
18233
18234  /**
18235   * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
18236   * @returns {Array} sorted suffix ranges
18237   */
18238  JustifiedGallery.prototype.retrieveSuffixRanges = function () {
18239    var suffixRanges = [];
18240    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
18241      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
18242    }
18243    suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
18244    return suffixRanges;
18245  };
18246
18247  /**
18248   * Update the existing settings only changing some of them
18249   *
18250   * @param newSettings the new settings (or a subgroup of them)
18251   */
18252  JustifiedGallery.prototype.updateSettings = function (newSettings) {
18253    // In this case Justified Gallery has been called again changing only some options
18254    this.settings = $.extend({}, this.settings, newSettings);
18255    this.checkSettings();
18256
18257    // As reported in the settings: negative value = same as margins, 0 = disabled
18258    this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
18259
18260    this.maxRowHeight = this.retrieveMaxRowHeight();
18261    this.suffixRanges = this.retrieveSuffixRanges();
18262  };
18263
18264  /**
18265   * Justified Gallery plugin for jQuery
18266   *
18267   * Events
18268   *  - jg.complete : called when all the gallery has been created
18269   *  - jg.resize : called when the gallery has been resized
18270   *  - jg.rowflush : when a new row appears
18271   *
18272   * @param arg the action (or the settings) passed when the plugin is called
18273   * @returns {*} the object itself
18274   */
18275  $.fn.justifiedGallery = function (arg) {
18276    return this.each(function (index, gallery) {
18277
18278      var $gallery = $(gallery);
18279      $gallery.addClass('justified-gallery');
18280
18281      var controller = $gallery.data('jg.controller');
18282      if (typeof controller === 'undefined') {
18283        // Create controller and assign it to the object data
18284        if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
18285          if (arg === 'destroy') return; // Just a call to an unexisting object
18286          throw 'The argument must be an object';
18287        }
18288        controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg));
18289        $gallery.data('jg.controller', controller);
18290      } else if (arg === 'norewind') {
18291        // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
18292        // ... left to be more readable
18293      } else if (arg === 'destroy') {
18294        controller.destroy();
18295        return;
18296      } else {
18297        // In this case Justified Gallery has been called again changing only some options
18298        controller.updateSettings(arg);
18299        controller.rewind();
18300      }
18301
18302      // Update the entries list
18303      if (!controller.updateEntries(arg === 'norewind')) return;
18304
18305      // Init justified gallery
18306      controller.init();
18307
18308    });
18309  };
18310
18311  // Default options
18312  $.fn.justifiedGallery.defaults = {
18313    sizeRangeSuffixes: { }, /* e.g. Flickr configuration
18314        {
18315          100: '_t',  // used when longest is less than 100px
18316          240: '_m',  // used when longest is between 101px and 240px
18317          320: '_n',  // ...
18318          500: '',
18319          640: '_z',
18320          1024: '_b'  // used as else case because it is the last
18321        }
18322    */
18323    thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
18324    path relative to a specific thumbnail size. The function should accept respectively three arguments:
18325    current path, width and height */
18326    rowHeight: 120,
18327    maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
18328                         // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
18329                         // can't exceed 3 * rowHeight)
18330    margins: 1,
18331    border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
18332
18333    lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
18334
18335    justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
18336                             * (i.e. lastRow setting is not considered) */
18337    waitThumbnailsLoad: true,
18338    captions: true,
18339    cssAnimation: true,
18340    imagesAnimationDuration: 500, // ignored with css animations
18341    captionSettings: { // ignored with css animations
18342      animationDuration: 500,
18343      visibleOpacity: 0.7,
18344      nonVisibleOpacity: 0.0
18345    },
vendor: 5,759 bytes, lines 18346-18488
18346    rel: null, // rewrite the rel of each analyzed links
18347    target: null, // rewrite the target of all links
18348    extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
18349    refreshTime: 200, // time interval (in ms) to check if the page changes its width
18350    refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
18351    randomize: false,
18352    sort: false, /*
18353      - false: to do not sort
18354      - function: to sort them using the function as comparator (see Array.prototype.sort())
18355    */
18356    filter: false, /*
18357      - false, null or undefined: for a disabled filter
18358      - a string: an entry is kept if entry.is(filter string) returns true
18359                  see jQuery's .is() function for further information
18360      - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
18361                    It follows the specifications of the Array.prototype.filter() function of JavaScript.
18362    */
18363    selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery
18364  };
18365
18366}(jQuery));
18367/*!
18368* Customized version of iScroll.js 0.0.1
18369* It fixes bugs affecting its integration with fullpage.js
18370*/
18371/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
18372(function (window, document, Math) {
18373var rAF = window.requestAnimationFrame  ||
18374    window.webkitRequestAnimationFrame  ||
18375    window.mozRequestAnimationFrame     ||
18376    window.oRequestAnimationFrame       ||
18377    window.msRequestAnimationFrame      ||
18378    function (callback) { window.setTimeout(callback, 1000 / 60); };
18379
18380var utils = (function () {
18381    var me = {};
18382
18383    var _elementStyle = document.createElement('div').style;
18384    var _vendor = (function () {
18385        var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
18386            transform,
18387            i = 0,
18388            l = vendors.length;
18389
18390        for ( ; i < l; i++ ) {
18391            transform = vendors[i] + 'ransform';
18392            if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
18393        }
18394
18395        return false;
18396    })();
18397
18398    function _prefixStyle (style) {
18399        if ( _vendor === false ) return false;
18400        if ( _vendor === '' ) return style;
18401        return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
18402    }
18403
18404    me.getTime = Date.now || function getTime () { return new Date().getTime(); };
18405
18406    me.extend = function (target, obj) {
18407        for ( var i in obj ) {
18408            target[i] = obj[i];
18409        }
18410    };
18411
18412    me.addEvent = function (el, type, fn, capture) {
18413        el.addEventListener(type, fn, !!capture);
18414    };
18415
18416    me.removeEvent = function (el, type, fn, capture) {
18417        el.removeEventListener(type, fn, !!capture);
18418    };
18419
18420    me.prefixPointerEvent = function (pointerEvent) {
18421        return window.MSPointerEvent ?
18422            'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
18423            pointerEvent;
18424    };
18425
18426    me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
18427        var distance = current - start,
18428            speed = Math.abs(distance) / time,
18429            destination,
18430            duration;
18431
18432        deceleration = deceleration === undefined ? 0.0006 : deceleration;
18433
18434        destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
18435        duration = speed / deceleration;
18436
18437        if ( destination < lowerMargin ) {
18438            destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
18439            distance = Math.abs(destination - current);
18440            duration = distance / speed;
18441        } else if ( destination > 0 ) {
18442            destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
18443            distance = Math.abs(current) + destination;
18444            duration = distance / speed;
18445        }
18446
18447        return {
18448            destination: Math.round(destination),
18449            duration: duration
18450        };
18451    };
18452
18453    var _transform = _prefixStyle('transform');
18454
18455    me.extend(me, {
18456        hasTransform: _transform !== false,
18457        hasPerspective: _prefixStyle('perspective') in _elementStyle,
18458        hasTouch: 'ontouchstart' in window,
18459        hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
18460        hasTransition: _prefixStyle('transition') in _elementStyle
18461    });
18462
18463    /*
18464    This should find all Android browsers lower than build 535.19 (both stock browser and webview)
18465    - galaxy S2 is ok
18466    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
18467    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
18468   - galaxy S3 is badAndroid (stock brower, webview)
18469     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
18470   - galaxy S4 is badAndroid (stock brower, webview)
18471     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
18472   - galaxy S5 is OK
18473     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
18474   - galaxy S6 is OK
18475     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
18476  */
18477    me.isBadAndroid = (function() {
18478        var appVersion = window.navigator.appVersion;
18479        // Android browser is not a chrome browser.
18480        if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
18481            var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
18482            if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
18483                return parseFloat(safariVersion[1]) < 535.19;
18484            } else {
18485                return true;
18486            }
18487        } else {
18488            return false;
vendor: 5,536 bytes, lines 18489-18681
18489        }
18490    })();
18491
18492    me.extend(me.style = {}, {
18493        transform: _transform,
18494        transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
18495        transitionDuration: _prefixStyle('transitionDuration'),
18496        transitionDelay: _prefixStyle('transitionDelay'),
18497        transformOrigin: _prefixStyle('transformOrigin')
18498    });
18499
18500    me.hasClass = function (e, c) {
18501        var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
18502        return re.test(e.className);
18503    };
18504
18505    me.addClass = function (e, c) {
18506        if ( me.hasClass(e, c) ) {
18507            return;
18508        }
18509
18510        var newclass = e.className.split(' ');
18511        newclass.push(c);
18512        e.className = newclass.join(' ');
18513    };
18514
18515    me.removeClass = function (e, c) {
18516        if ( !me.hasClass(e, c) ) {
18517            return;
18518        }
18519
18520        var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
18521        e.className = e.className.replace(re, ' ');
18522    };
18523
18524    me.offset = function (el) {
18525        var left = -el.offsetLeft,
18526            top = -el.offsetTop;
18527
18528        // jshint -W084
18529        while (el = el.offsetParent) {
18530            left -= el.offsetLeft;
18531            top -= el.offsetTop;
18532        }
18533        // jshint +W084
18534
18535        return {
18536            left: left,
18537            top: top
18538        };
18539    };
18540
18541    me.preventDefaultException = function (el, exceptions) {
18542        for ( var i in exceptions ) {
18543            if ( exceptions[i].test(el[i]) ) {
18544                return true;
18545            }
18546        }
18547
18548        return false;
18549    };
18550
18551    me.extend(me.eventType = {}, {
18552        touchstart: 1,
18553        touchmove: 1,
18554        touchend: 1,
18555
18556        mousedown: 2,
18557        mousemove: 2,
18558        mouseup: 2,
18559
18560        pointerdown: 3,
18561        pointermove: 3,
18562        pointerup: 3,
18563
18564        MSPointerDown: 3,
18565        MSPointerMove: 3,
18566        MSPointerUp: 3
18567    });
18568
18569    me.extend(me.ease = {}, {
18570        quadratic: {
18571            style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
18572            fn: function (k) {
18573                return k * ( 2 - k );
18574            }
18575        },
18576        circular: {
18577            style: 'cubic-bezier(0.1, 0.57, 0.1, 1)',   // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
18578            fn: function (k) {
18579                return Math.sqrt( 1 - ( --k * k ) );
18580            }
18581        },
18582        back: {
18583            style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
18584            fn: function (k) {
18585                var b = 4;
18586                return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
18587            }
18588        },
18589        bounce: {
18590            style: '',
18591            fn: function (k) {
18592                if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
18593                    return 7.5625 * k * k;
18594                } else if ( k < ( 2 / 2.75 ) ) {
18595                    return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
18596                } else if ( k < ( 2.5 / 2.75 ) ) {
18597                    return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
18598                } else {
18599                    return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
18600                }
18601            }
18602        },
18603        elastic: {
18604            style: '',
18605            fn: function (k) {
18606                var f = 0.22,
18607                    e = 0.4;
18608
18609                if ( k === 0 ) { return 0; }
18610                if ( k == 1 ) { return 1; }
18611
18612                return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
18613            }
18614        }
18615    });
18616
18617    me.tap = function (e, eventName) {
18618        var ev = document.createEvent('Event');
18619        ev.initEvent(eventName, true, true);
18620        ev.pageX = e.pageX;
18621        ev.pageY = e.pageY;
18622        e.target.dispatchEvent(ev);
18623    };
18624
18625    me.click = function (e) {
18626        var target = e.target,
18627            ev;
18628
18629        if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
18630            // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
18631            // initMouseEvent is deprecated.
18632            ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
18633            ev.initEvent('click', true, true);
18634            ev.view = e.view || window;
18635            ev.detail = 1;
18636            ev.screenX = target.screenX || 0;
18637            ev.screenY = target.screenY || 0;
18638            ev.clientX = target.clientX || 0;
18639            ev.clientY = target.clientY || 0;
18640            ev.ctrlKey = !!e.ctrlKey;
18641            ev.altKey = !!e.altKey;
18642            ev.shiftKey = !!e.shiftKey;
18643            ev.metaKey = !!e.metaKey;
18644            ev.button = 0;
18645            ev.relatedTarget = null;
18646            ev._constructed = true;
18647            target.dispatchEvent(ev);
18648        }
18649    };
18650
18651    return me;
18652})();
18653function IScroll (el, options) {
18654    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
18655    this.scroller = this.wrapper.children[0];
18656    this.scrollerStyle = this.scroller.style;       // cache style for better performance
18657
18658    this.options = {
18659
18660        resizeScrollbars: true,
18661
18662        mouseWheelSpeed: 20,
18663
18664        snapThreshold: 0.334,
18665
18666// INSERT POINT: OPTIONS
18667        disablePointer : !utils.hasPointer,
18668        disableTouch : utils.hasPointer || !utils.hasTouch,
18669        disableMouse : utils.hasPointer || utils.hasTouch,
18670        startX: 0,
18671        startY: 0,
18672        scrollY: true,
18673        directionLockThreshold: 5,
18674        momentum: true,
18675
18676        bounce: true,
18677        bounceTime: 600,
18678        bounceEasing: '',
18679
18680        preventDefault: true,
18681        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
vendor: 4,420 bytes, lines 18681-18825
18681SELECT|LABEL)$/ },
18682
18683        HWCompositing: true,
18684        useTransition: true,
18685        useTransform: true,
18686        bindToWrapper: typeof window.onmousedown === "undefined"
18687    };
18688
18689    for ( var i in options ) {
18690        this.options[i] = options[i];
18691    }
18692
18693    // Normalize options
18694    this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
18695
18696    this.options.useTransition = utils.hasTransition && this.options.useTransition;
18697    this.options.useTransform = utils.hasTransform && this.options.useTransform;
18698
18699    this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
18700    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
18701
18702    // If you want eventPassthrough I have to lock one of the axes
18703    this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
18704    this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
18705
18706    // With eventPassthrough we also need lockDirection mechanism
18707    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
18708    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
18709
18710    this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
18711
18712    this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
18713
18714    if ( this.options.tap === true ) {
18715        this.options.tap = 'tap';
18716    }
18717
18718    // https://github.com/cubiq/iscroll/issues/1029
18719    if (!this.options.useTransition && !this.options.useTransform) {
18720        if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
18721            this.scrollerStyle.position = "relative";
18722        }
18723    }
18724
18725    if ( this.options.shrinkScrollbars == 'scale' ) {
18726        this.options.useTransition = false;
18727    }
18728
18729    this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
18730
18731// INSERT POINT: NORMALIZATION
18732
18733    // Some defaults
18734    this.x = 0;
18735    this.y = 0;
18736    this.directionX = 0;
18737    this.directionY = 0;
18738    this._events = {};
18739
18740// INSERT POINT: DEFAULTS
18741
18742    this._init();
18743    this.refresh();
18744
18745    this.scrollTo(this.options.startX, this.options.startY);
18746    this.enable();
18747}
18748
18749IScroll.prototype = {
18750    version: '5.2.0',
18751
18752    _init: function () {
18753        this._initEvents();
18754
18755        if ( this.options.scrollbars || this.options.indicators ) {
18756            this._initIndicators();
18757        }
18758
18759        if ( this.options.mouseWheel ) {
18760            this._initWheel();
18761        }
18762
18763        if ( this.options.snap ) {
18764            this._initSnap();
18765        }
18766
18767        if ( this.options.keyBindings ) {
18768            this._initKeys();
18769        }
18770
18771// INSERT POINT: _init
18772
18773    },
18774
18775    destroy: function () {
18776        this._initEvents(true);
18777        clearTimeout(this.resizeTimeout);
18778        this.resizeTimeout = null;
18779        this._execEvent('destroy');
18780    },
18781
18782    _transitionEnd: function (e) {
18783        if ( e.target != this.scroller || !this.isInTransition ) {
18784            return;
18785        }
18786
18787        this._transitionTime();
18788        if ( !this.resetPosition(this.options.bounceTime) ) {
18789            this.isInTransition = false;
18790            this._execEvent('scrollEnd');
18791        }
18792    },
18793
18794    _start: function (e) {
18795        // React to left mouse button only
18796        if ( utils.eventType[e.type] != 1 ) {
18797          // for button property
18798          // http://unixpapa.com/js/mouse.html
18799          var button;
18800        if (!e.which) {
18801          /* IE case */
18802          button = (e.button < 2) ? 0 :
18803                   ((e.button == 4) ? 1 : 2);
18804        } else {
18805          /* All others */
18806          button = e.button;
18807        }
18808            if ( button !== 0 ) {
18809                return;
18810            }
18811        }
18812
18813        if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
18814            return;
18815        }
18816
18817        if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
18818            e.preventDefault();
18819        }
18820
18821        var point = e.touches ? e.touches[0] : e,
18822            pos;
18823
18824        this.initiated  = utils.eventType[e.type];
18825        this.moved      = false;
vendor: 5,928 bytes, lines 18826-19004
18826        this.distX      = 0;
18827        this.distY      = 0;
18828        this.directionX = 0;
18829        this.directionY = 0;
18830        this.directionLocked = 0;
18831
18832        this.startTime = utils.getTime();
18833
18834        if ( this.options.useTransition && this.isInTransition ) {
18835            this._transitionTime();
18836            this.isInTransition = false;
18837            pos = this.getComputedPosition();
18838            this._translate(Math.round(pos.x), Math.round(pos.y));
18839            this._execEvent('scrollEnd');
18840        } else if ( !this.options.useTransition && this.isAnimating ) {
18841            this.isAnimating = false;
18842            this._execEvent('scrollEnd');
18843        }
18844
18845        this.startX    = this.x;
18846        this.startY    = this.y;
18847        this.absStartX = this.x;
18848        this.absStartY = this.y;
18849        this.pointX    = point.pageX;
18850        this.pointY    = point.pageY;
18851
18852        this._execEvent('beforeScrollStart');
18853    },
18854
18855    _move: function (e) {
18856        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
18857            return;
18858        }
18859
18860        if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
18861            e.preventDefault();
18862        }
18863
18864        var point       = e.touches ? e.touches[0] : e,
18865            deltaX      = point.pageX - this.pointX,
18866            deltaY      = point.pageY - this.pointY,
18867            timestamp   = utils.getTime(),
18868            newX, newY,
18869            absDistX, absDistY;
18870
18871        this.pointX     = point.pageX;
18872        this.pointY     = point.pageY;
18873
18874        this.distX      += deltaX;
18875        this.distY      += deltaY;
18876        absDistX        = Math.abs(this.distX);
18877        absDistY        = Math.abs(this.distY);
18878
18879        // We need to move at least 10 pixels for the scrolling to initiate
18880        if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
18881            return;
18882        }
18883
18884        // If you are scrolling in one direction lock the other
18885        if ( !this.directionLocked && !this.options.freeScroll ) {
18886            if ( absDistX > absDistY + this.options.directionLockThreshold ) {
18887                this.directionLocked = 'h';     // lock horizontally
18888            } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
18889                this.directionLocked = 'v';     // lock vertically
18890            } else {
18891                this.directionLocked = 'n';     // no lock
18892            }
18893        }
18894
18895        if ( this.directionLocked == 'h' ) {
18896            if ( this.options.eventPassthrough == 'vertical' ) {
18897                e.preventDefault();
18898            } else if ( this.options.eventPassthrough == 'horizontal' ) {
18899                this.initiated = false;
18900                return;
18901            }
18902
18903            deltaY = 0;
18904        } else if ( this.directionLocked == 'v' ) {
18905            if ( this.options.eventPassthrough == 'horizontal' ) {
18906                e.preventDefault();
18907            } else if ( this.options.eventPassthrough == 'vertical' ) {
18908                this.initiated = false;
18909                return;
18910            }
18911
18912            deltaX = 0;
18913        }
18914
18915        deltaX = this.hasHorizontalScroll ? deltaX : 0;
18916        deltaY = this.hasVerticalScroll ? deltaY : 0;
18917
18918        newX = this.x + deltaX;
18919        newY = this.y + deltaY;
18920
18921        // Slow down if outside of the boundaries
18922        if ( newX > 0 || newX < this.maxScrollX ) {
18923            newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
18924        }
18925        if ( newY > 0 || newY < this.maxScrollY ) {
18926            newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
18927        }
18928
18929        this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
18930        this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
18931
18932        if ( !this.moved ) {
18933            this._execEvent('scrollStart');
18934        }
18935
18936        this.moved = true;
18937
18938        this._translate(newX, newY);
18939
18940/* REPLACE START: _move */
18941
18942        if ( timestamp - this.startTime > 300 ) {
18943            this.startTime = timestamp;
18944            this.startX = this.x;
18945            this.startY = this.y;
18946        }
18947
18948/* REPLACE END: _move */
18949
18950    },
18951
18952    _end: function (e) {
18953        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
18954            return;
18955        }
18956
18957        if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
18958            e.preventDefault();
18959        }
18960
18961        var point = e.changedTouches ? e.changedTouches[0] : e,
18962            momentumX,
18963            momentumY,
18964            duration = utils.getTime() - this.startTime,
18965            newX = Math.round(this.x),
18966            newY = Math.round(this.y),
18967            distanceX = Math.abs(newX - this.startX),
18968            distanceY = Math.abs(newY - this.startY),
18969            time = 0,
18970            easing = '';
18971
18972        this.isInTransition = 0;
18973        this.initiated = 0;
18974        this.endTime = utils.getTime();
18975
18976        // reset if we are outside of the boundaries
18977        if ( this.resetPosition(this.options.bounceTime) ) {
18978            return;
18979        }
18980
18981        this.scrollTo(newX, newY);  // ensures that the last position is rounded
18982
18983        // we scrolled less than 10 pixels
18984        if ( !this.moved ) {
18985            if ( this.options.tap ) {
18986                utils.tap(e, this.options.tap);
18987            }
18988
18989            if ( this.options.click ) {
18990                utils.click(e);
18991            }
18992
18993            this._execEvent('scrollCancel');
18994            return;
18995        }
18996
18997        if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
18998            this._execEvent('flick');
18999            return;
19000        }
19001
19002        // start momentum animation if needed
19003        if ( this.options.momentum && duration < 300 ) {
19004            momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 7,740 bytes, lines 19004-19277
19004idth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
19005            momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
19006            newX = momentumX.destination;
19007            newY = momentumY.destination;
19008            time = Math.max(momentumX.duration, momentumY.duration);
19009            this.isInTransition = 1;
19010        }
19011
19012
19013        if ( this.options.snap ) {
19014            var snap = this._nearestSnap(newX, newY);
19015            this.currentPage = snap;
19016            time = this.options.snapSpeed || Math.max(
19017                    Math.max(
19018                        Math.min(Math.abs(newX - snap.x), 1000),
19019                        Math.min(Math.abs(newY - snap.y), 1000)
19020                    ), 300);
19021            newX = snap.x;
19022            newY = snap.y;
19023
19024            this.directionX = 0;
19025            this.directionY = 0;
19026            easing = this.options.bounceEasing;
19027        }
19028
19029// INSERT POINT: _end
19030
19031        if ( newX != this.x || newY != this.y ) {
19032            // change easing function when scroller goes out of the boundaries
19033            if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
19034                easing = utils.ease.quadratic;
19035            }
19036
19037            this.scrollTo(newX, newY, time, easing);
19038            return;
19039        }
19040
19041        this._execEvent('scrollEnd');
19042    },
19043
19044    _resize: function () {
19045        var that = this;
19046
19047        clearTimeout(this.resizeTimeout);
19048
19049        this.resizeTimeout = setTimeout(function () {
19050            that.refresh();
19051        }, this.options.resizePolling);
19052    },
19053
19054    resetPosition: function (time) {
19055        var x = this.x,
19056            y = this.y;
19057
19058        time = time || 0;
19059
19060        if ( !this.hasHorizontalScroll || this.x > 0 ) {
19061            x = 0;
19062        } else if ( this.x < this.maxScrollX ) {
19063            x = this.maxScrollX;
19064        }
19065
19066        if ( !this.hasVerticalScroll || this.y > 0 ) {
19067            y = 0;
19068        } else if ( this.y < this.maxScrollY ) {
19069            y = this.maxScrollY;
19070        }
19071
19072        if ( x == this.x && y == this.y ) {
19073            return false;
19074        }
19075
19076        this.scrollTo(x, y, time, this.options.bounceEasing);
19077
19078        return true;
19079    },
19080
19081    disable: function () {
19082        this.enabled = false;
19083    },
19084
19085    enable: function () {
19086        this.enabled = true;
19087    },
19088
19089    refresh: function () {
19090        var rf = this.wrapper.offsetHeight;     // Force reflow
19091
19092        this.wrapperWidth   = this.wrapper.clientWidth;
19093        this.wrapperHeight  = this.wrapper.clientHeight;
19094
19095/* REPLACE START: refresh */
19096
19097        this.scrollerWidth  = this.scroller.offsetWidth;
19098        this.scrollerHeight = this.scroller.offsetHeight;
19099
19100        this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
19101        this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
19102
19103/* REPLACE END: refresh */
19104
19105        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
19106        this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
19107
19108        if ( !this.hasHorizontalScroll ) {
19109            this.maxScrollX = 0;
19110            this.scrollerWidth = this.wrapperWidth;
19111        }
19112
19113        if ( !this.hasVerticalScroll ) {
19114            this.maxScrollY = 0;
19115            this.scrollerHeight = this.wrapperHeight;
19116        }
19117
19118        this.endTime = 0;
19119        this.directionX = 0;
19120        this.directionY = 0;
19121
19122        this.wrapperOffset = utils.offset(this.wrapper);
19123
19124        this._execEvent('refresh');
19125
19126        this.resetPosition();
19127
19128// INSERT POINT: _refresh
19129
19130    },
19131
19132    on: function (type, fn) {
19133        if ( !this._events[type] ) {
19134            this._events[type] = [];
19135        }
19136
19137        this._events[type].push(fn);
19138    },
19139
19140    off: function (type, fn) {
19141        if ( !this._events[type] ) {
19142            return;
19143        }
19144
19145        var index = this._events[type].indexOf(fn);
19146
19147        if ( index > -1 ) {
19148            this._events[type].splice(index, 1);
19149        }
19150    },
19151
19152    _execEvent: function (type) {
19153        if ( !this._events[type] ) {
19154            return;
19155        }
19156
19157        var i = 0,
19158            l = this._events[type].length;
19159
19160        if ( !l ) {
19161            return;
19162        }
19163
19164        for ( ; i < l; i++ ) {
19165            this._events[type][i].apply(this, [].slice.call(arguments, 1));
19166        }
19167    },
19168
19169    scrollBy: function (x, y, time, easing) {
19170        x = this.x + x;
19171        y = this.y + y;
19172        time = time || 0;
19173
19174        this.scrollTo(x, y, time, easing);
19175    },
19176
19177    scrollTo: function (x, y, time, easing) {
19178        easing = easing || utils.ease.circular;
19179
19180        this.isInTransition = this.options.useTransition && time > 0;
19181        var transitionType = this.options.useTransition && easing.style;
19182        if ( !time || transitionType ) {
19183                if(transitionType) {
19184                    this._transitionTimingFunction(easing.style);
19185                    this._transitionTime(time);
19186                }
19187            this._translate(x, y);
19188        } else {
19189            this._animate(x, y, time, easing.fn);
19190        }
19191    },
19192
19193    scrollToElement: function (el, time, offsetX, offsetY, easing) {
19194        el = el.nodeType ? el : this.scroller.querySelector(el);
19195
19196        if ( !el ) {
19197            return;
19198        }
19199
19200        var pos = utils.offset(el);
19201
19202        pos.left -= this.wrapperOffset.left;
19203        pos.top  -= this.wrapperOffset.top;
19204
19205        // if offsetX/Y are true we center the element to the screen
19206        if ( offsetX === true ) {
19207            offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
19208        }
19209        if ( offsetY === true ) {
19210            offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
19211        }
19212
19213        pos.left -= offsetX || 0;
19214        pos.top  -= offsetY || 0;
19215
19216        pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
19217        pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
19218
19219        time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
19220
19221        this.scrollTo(pos.left, pos.top, time, easing);
19222    },
19223
19224    _transitionTime: function (time) {
19225        if (!this.options.useTransition) {
19226            return;
19227        }
19228        time = time || 0;
19229        var durationProp = utils.style.transitionDuration;
19230        if(!durationProp) {
19231            return;
19232        }
19233
19234        this.scrollerStyle[durationProp] = time + 'ms';
19235
19236        if ( !time && utils.isBadAndroid ) {
19237            this.scrollerStyle[durationProp] = '0.0001ms';
19238            // remove 0.0001ms
19239            var self = this;
19240            rAF(function() {
19241                if(self.scrollerStyle[durationProp] === '0.0001ms') {
19242                    self.scrollerStyle[durationProp] = '0s';
19243                }
19244            });
19245        }
19246
19247
19248        if ( this.indicators ) {
19249            for ( var i = this.indicators.length; i--; ) {
19250                this.indicators[i].transitionTime(time);
19251            }
19252        }
19253
19254
19255// INSERT POINT: _transitionTime
19256
19257    },
19258
19259    _transitionTimingFunction: function (easing) {
19260        this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
19261
19262
19263        if ( this.indicators ) {
19264            for ( var i = this.indicators.length; i--; ) {
19265                this.indicators[i].transitionTimingFunction(easing);
19266            }
19267        }
19268
19269
19270// INSERT POINT: _transitionTimingFunction
19271
19272    },
19273
19274    _translate: function (x, y) {
19275        //Uncode addition
19276        if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
19277            return false;
vendor: 9,939 bytes, lines 19278-19589
19278
19279        if ( this.options.useTransform ) {
19280
19281/* REPLACE START: _translate */
19282
19283            this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
19284
19285/* REPLACE END: _translate */
19286
19287        } else {
19288            x = Math.round(x);
19289            y = Math.round(y);
19290            this.scrollerStyle.left = x + 'px';
19291            this.scrollerStyle.top = y + 'px';
19292        }
19293
19294        this.x = x;
19295        this.y = y;
19296
19297
19298        if ( this.indicators ) {
19299            for ( var i = this.indicators.length; i--; ) {
19300                this.indicators[i].updatePosition();
19301            }
19302        }
19303
19304        //Uncode addition
19305        var uncodevent = new CustomEvent('fp-slide-scroll');
19306        window.dispatchEvent(uncodevent);
19307
19308// INSERT POINT: _translate
19309
19310    },
19311
19312    _initEvents: function (remove) {
19313        var eventType = remove ? utils.removeEvent : utils.addEvent,
19314            target = this.options.bindToWrapper ? this.wrapper : window;
19315
19316        eventType(window, 'orientationchange', this);
19317        eventType(window, 'resize', this);
19318
19319        if ( this.options.click ) {
19320            eventType(this.wrapper, 'click', this, true);
19321        }
19322
19323        if ( !this.options.disableMouse ) {
19324            eventType(this.wrapper, 'mousedown', this);
19325            eventType(target, 'mousemove', this);
19326            eventType(target, 'mousecancel', this);
19327            eventType(target, 'mouseup', this);
19328        }
19329
19330        if ( utils.hasPointer && !this.options.disablePointer ) {
19331            eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
19332            eventType(target, utils.prefixPointerEvent('pointermove'), this);
19333            eventType(target, utils.prefixPointerEvent('pointercancel'), this);
19334            eventType(target, utils.prefixPointerEvent('pointerup'), this);
19335        }
19336
19337        if ( utils.hasTouch && !this.options.disableTouch ) {
19338            eventType(this.wrapper, 'touchstart', this);
19339            eventType(target, 'touchmove', this);
19340            eventType(target, 'touchcancel', this);
19341            eventType(target, 'touchend', this);
19342        }
19343
19344        eventType(this.scroller, 'transitionend', this);
19345        eventType(this.scroller, 'webkitTransitionEnd', this);
19346        eventType(this.scroller, 'oTransitionEnd', this);
19347        eventType(this.scroller, 'MSTransitionEnd', this);
19348    },
19349
19350    getComputedPosition: function () {
19351        var matrix = window.getComputedStyle(this.scroller, null),
19352            x, y;
19353
19354        if ( this.options.useTransform ) {
19355            matrix = matrix[utils.style.transform].split(')')[0].split(', ');
19356            x = +(matrix[12] || matrix[4]);
19357            y = +(matrix[13] || matrix[5]);
19358        } else {
19359            x = +matrix.left.replace(/[^-\d.]/g, '');
19360            y = +matrix.top.replace(/[^-\d.]/g, '');
19361        }
19362
19363        return { x: x, y: y };
19364    },
19365    _initIndicators: function () {
19366        var interactive = this.options.interactiveScrollbars,
19367            customStyle = typeof this.options.scrollbars != 'string',
19368            indicators = [],
19369            indicator;
19370
19371        var that = this;
19372
19373        this.indicators = [];
19374
19375        if ( this.options.scrollbars ) {
19376            // Vertical scrollbar
19377            if ( this.options.scrollY ) {
19378                indicator = {
19379                    el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
19380                    interactive: interactive,
19381                    defaultScrollbars: true,
19382                    customStyle: customStyle,
19383                    resize: this.options.resizeScrollbars,
19384                    shrink: this.options.shrinkScrollbars,
19385                    fade: this.options.fadeScrollbars,
19386                    listenX: false
19387                };
19388
19389                this.wrapper.appendChild(indicator.el);
19390                indicators.push(indicator);
19391            }
19392
19393            // Horizontal scrollbar
19394            if ( this.options.scrollX ) {
19395                indicator = {
19396                    el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
19397                    interactive: interactive,
19398                    defaultScrollbars: true,
19399                    customStyle: customStyle,
19400                    resize: this.options.resizeScrollbars,
19401                    shrink: this.options.shrinkScrollbars,
19402                    fade: this.options.fadeScrollbars,
19403                    listenY: false
19404                };
19405
19406                this.wrapper.appendChild(indicator.el);
19407                indicators.push(indicator);
19408            }
19409        }
19410
19411        if ( this.options.indicators ) {
19412            // TODO: check concat compatibility
19413            indicators = indicators.concat(this.options.indicators);
19414        }
19415
19416        for ( var i = indicators.length; i--; ) {
19417            this.indicators.push( new Indicator(this, indicators[i]) );
19418        }
19419
19420        // TODO: check if we can use array.map (wide compatibility and performance issues)
19421        function _indicatorsMap (fn) {
19422            if (that.indicators) {
19423                for ( var i = that.indicators.length; i--; ) {
19424                    fn.call(that.indicators[i]);
19425                }
19426            }
19427        }
19428
19429        if ( this.options.fadeScrollbars ) {
19430            this.on('scrollEnd', function () {
19431                _indicatorsMap(function () {
19432                    this.fade();
19433                });
19434            });
19435
19436            this.on('scrollCancel', function () {
19437                _indicatorsMap(function () {
19438                    this.fade();
19439                });
19440            });
19441
19442            this.on('scrollStart', function () {
19443                _indicatorsMap(function () {
19444                    this.fade(1);
19445                });
19446            });
19447
19448            this.on('beforeScrollStart', function () {
19449                _indicatorsMap(function () {
19450                    this.fade(1, true);
19451                });
19452            });
19453        }
19454
19455
19456        this.on('refresh', function () {
19457            _indicatorsMap(function () {
19458                this.refresh();
19459            });
19460        });
19461
19462        this.on('destroy', function () {
19463            _indicatorsMap(function () {
19464                this.destroy();
19465            });
19466
19467            delete this.indicators;
19468        });
19469    },
19470
19471    _initWheel: function () {
19472        utils.addEvent(this.wrapper, 'wheel', this);
19473        utils.addEvent(this.wrapper, 'mousewheel', this);
19474        utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
19475
19476        this.on('destroy', function () {
19477            clearTimeout(this.wheelTimeout);
19478            this.wheelTimeout = null;
19479            utils.removeEvent(this.wrapper, 'wheel', this);
19480            utils.removeEvent(this.wrapper, 'mousewheel', this);
19481            utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
19482        });
19483    },
19484
19485    _wheel: function (e) {
19486        if ( !this.enabled ) {
19487            return;
19488        }
19489
19490        var wheelDeltaX, wheelDeltaY,
19491            newX, newY,
19492            that = this;
19493
19494        if ( this.wheelTimeout === undefined ) {
19495            that._execEvent('scrollStart');
19496        }
19497
19498        // Execute the scrollEnd event after 400ms the wheel stopped scrolling
19499        clearTimeout(this.wheelTimeout);
19500        this.wheelTimeout = setTimeout(function () {
19501            if(!that.options.snap) {
19502                that._execEvent('scrollEnd');
19503            }
19504            that.wheelTimeout = undefined;
19505        }, 400);
19506
19507        if ( 'deltaX' in e ) {
19508            if (e.deltaMode === 1) {
19509                wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
19510                wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
19511            } else {
19512                wheelDeltaX = -e.deltaX;
19513                wheelDeltaY = -e.deltaY;
19514            }
19515        } else if ( 'wheelDeltaX' in e ) {
19516            wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
19517            wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
19518        } else if ( 'wheelDelta' in e ) {
19519            wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
19520        } else if ( 'detail' in e ) {
19521            wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
19522        } else {
19523            return;
19524        }
19525
19526        wheelDeltaX *= this.options.invertWheelDirection;
19527        wheelDeltaY *= this.options.invertWheelDirection;
19528
19529        if ( !this.hasVerticalScroll ) {
19530            wheelDeltaX = wheelDeltaY;
19531            wheelDeltaY = 0;
19532        }
19533
19534        if ( this.options.snap ) {
19535            newX = this.currentPage.pageX;
19536            newY = this.currentPage.pageY;
19537
19538            if ( wheelDeltaX > 0 ) {
19539                newX--;
19540            } else if ( wheelDeltaX < 0 ) {
19541                newX++;
19542            }
19543
19544            if ( wheelDeltaY > 0 ) {
19545                newY--;
19546            } else if ( wheelDeltaY < 0 ) {
19547                newY++;
19548            }
19549
19550            this.goToPage(newX, newY);
19551
19552            return;
19553        }
19554
19555        newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
19556        newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
19557
19558        this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
19559        this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
19560
19561        if ( newX > 0 ) {
19562            newX = 0;
19563        } else if ( newX < this.maxScrollX ) {
19564            newX = this.maxScrollX;
19565        }
19566
19567        if ( newY > 0 ) {
19568            newY = 0;
19569        } else if ( newY < this.maxScrollY ) {
19570            newY = this.maxScrollY;
19571        }
19572
19573        this.scrollTo(newX, newY, 0);
19574
19575// INSERT POINT: _wheel
19576    },
19577
19578    _initSnap: function () {
19579        this.currentPage = {};
19580
19581        if ( typeof this.options.snap == 'string' ) {
19582            this.options.snap = this.scroller.querySelectorAll(this.options.snap);
19583        }
19584
19585        this.on('refresh', function () {
19586            var i = 0, l,
19587                m = 0, n,
19588                cx, cy,
19589                x = 0, y,
vendor: 7,339 bytes, lines 19590-19843
19590                stepX = this.options.snapStepX || this.wrapperWidth,
19591                stepY = this.options.snapStepY || this.wrapperHeight,
19592                el;
19593
19594            this.pages = [];
19595
19596            if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
19597                return;
19598            }
19599
19600            if ( this.options.snap === true ) {
19601                cx = Math.round( stepX / 2 );
19602                cy = Math.round( stepY / 2 );
19603
19604                while ( x > -this.scrollerWidth ) {
19605                    this.pages[i] = [];
19606                    l = 0;
19607                    y = 0;
19608
19609                    while ( y > -this.scrollerHeight ) {
19610                        this.pages[i][l] = {
19611                            x: Math.max(x, this.maxScrollX),
19612                            y: Math.max(y, this.maxScrollY),
19613                            width: stepX,
19614                            height: stepY,
19615                            cx: x - cx,
19616                            cy: y - cy
19617                        };
19618
19619                        y -= stepY;
19620                        l++;
19621                    }
19622
19623                    x -= stepX;
19624                    i++;
19625                }
19626            } else {
19627                el = this.options.snap;
19628                l = el.length;
19629                n = -1;
19630
19631                for ( ; i < l; i++ ) {
19632                    if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
19633                        m = 0;
19634                        n++;
19635                    }
19636
19637                    if ( !this.pages[m] ) {
19638                        this.pages[m] = [];
19639                    }
19640
19641                    x = Math.max(-el[i].offsetLeft, this.maxScrollX);
19642                    y = Math.max(-el[i].offsetTop, this.maxScrollY);
19643                    cx = x - Math.round(el[i].offsetWidth / 2);
19644                    cy = y - Math.round(el[i].offsetHeight / 2);
19645
19646                    this.pages[m][n] = {
19647                        x: x,
19648                        y: y,
19649                        width: el[i].offsetWidth,
19650                        height: el[i].offsetHeight,
19651                        cx: cx,
19652                        cy: cy
19653                    };
19654
19655                    if ( x > this.maxScrollX ) {
19656                        m++;
19657                    }
19658                }
19659            }
19660
19661            this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
19662
19663            // Update snap threshold if needed
19664            if ( this.options.snapThreshold % 1 === 0 ) {
19665                this.snapThresholdX = this.options.snapThreshold;
19666                this.snapThresholdY = this.options.snapThreshold;
19667            } else {
19668                this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
19669                this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
19670            }
19671        });
19672
19673        this.on('flick', function () {
19674            var time = this.options.snapSpeed || Math.max(
19675                    Math.max(
19676                        Math.min(Math.abs(this.x - this.startX), 1000),
19677                        Math.min(Math.abs(this.y - this.startY), 1000)
19678                    ), 300);
19679
19680            this.goToPage(
19681                this.currentPage.pageX + this.directionX,
19682                this.currentPage.pageY + this.directionY,
19683                time
19684            );
19685        });
19686    },
19687
19688    _nearestSnap: function (x, y) {
19689        if ( !this.pages.length ) {
19690            return { x: 0, y: 0, pageX: 0, pageY: 0 };
19691        }
19692
19693        var i = 0,
19694            l = this.pages.length,
19695            m = 0;
19696
19697        // Check if we exceeded the snap threshold
19698        if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
19699            Math.abs(y - this.absStartY) < this.snapThresholdY ) {
19700            return this.currentPage;
19701        }
19702
19703        if ( x > 0 ) {
19704            x = 0;
19705        } else if ( x < this.maxScrollX ) {
19706            x = this.maxScrollX;
19707        }
19708
19709        if ( y > 0 ) {
19710            y = 0;
19711        } else if ( y < this.maxScrollY ) {
19712            y = this.maxScrollY;
19713        }
19714
19715        for ( ; i < l; i++ ) {
19716            if ( x >= this.pages[i][0].cx ) {
19717                x = this.pages[i][0].x;
19718                break;
19719            }
19720        }
19721
19722        l = this.pages[i].length;
19723
19724        for ( ; m < l; m++ ) {
19725            if ( y >= this.pages[0][m].cy ) {
19726                y = this.pages[0][m].y;
19727                break;
19728            }
19729        }
19730
19731        if ( i == this.currentPage.pageX ) {
19732            i += this.directionX;
19733
19734            if ( i < 0 ) {
19735                i = 0;
19736            } else if ( i >= this.pages.length ) {
19737                i = this.pages.length - 1;
19738            }
19739
19740            x = this.pages[i][0].x;
19741        }
19742
19743        if ( m == this.currentPage.pageY ) {
19744            m += this.directionY;
19745
19746            if ( m < 0 ) {
19747                m = 0;
19748            } else if ( m >= this.pages[0].length ) {
19749                m = this.pages[0].length - 1;
19750            }
19751
19752            y = this.pages[0][m].y;
19753        }
19754
19755        return {
19756            x: x,
19757            y: y,
19758            pageX: i,
19759            pageY: m
19760        };
19761    },
19762
19763    goToPage: function (x, y, time, easing) {
19764        easing = easing || this.options.bounceEasing;
19765
19766        if ( x >= this.pages.length ) {
19767            x = this.pages.length - 1;
19768        } else if ( x < 0 ) {
19769            x = 0;
19770        }
19771
19772        if ( y >= this.pages[x].length ) {
19773            y = this.pages[x].length - 1;
19774        } else if ( y < 0 ) {
19775            y = 0;
19776        }
19777
19778        var posX = this.pages[x][y].x,
19779            posY = this.pages[x][y].y;
19780
19781        time = time === undefined ? this.options.snapSpeed || Math.max(
19782            Math.max(
19783                Math.min(Math.abs(posX - this.x), 1000),
19784                Math.min(Math.abs(posY - this.y), 1000)
19785            ), 300) : time;
19786
19787        this.currentPage = {
19788            x: posX,
19789            y: posY,
19790            pageX: x,
19791            pageY: y
19792        };
19793
19794        this.scrollTo(posX, posY, time, easing);
19795    },
19796
19797    next: function (time, easing) {
19798        var x = this.currentPage.pageX,
19799            y = this.currentPage.pageY;
19800
19801        x++;
19802
19803        if ( x >= this.pages.length && this.hasVerticalScroll ) {
19804            x = 0;
19805            y++;
19806        }
19807
19808        this.goToPage(x, y, time, easing);
19809    },
19810
19811    prev: function (time, easing) {
19812        var x = this.currentPage.pageX,
19813            y = this.currentPage.pageY;
19814
19815        x--;
19816
19817        if ( x < 0 && this.hasVerticalScroll ) {
19818            x = 0;
19819            y--;
19820        }
19821
19822        this.goToPage(x, y, time, easing);
19823    },
19824
19825    _initKeys: function (e) {
19826        // default key bindings
19827        var keys = {
19828            pageUp: 33,
19829            pageDown: 34,
19830            end: 35,
19831            home: 36,
19832            left: 37,
19833            up: 38,
19834            right: 39,
19835            down: 40
19836        };
19837        var i;
19838
19839        // if you give me characters I give you keycode
19840        if ( typeof this.options.keyBindings == 'object' ) {
19841            for ( i in this.options.keyBindings ) {
19842                if ( typeof this.options.keyBindings[i] == 'string' ) {
19843                    this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 19843-20196
19843deAt(0);
19844                }
19845            }
19846        } else {
19847            this.options.keyBindings = {};
19848        }
19849
19850        for ( i in keys ) {
19851            this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
19852        }
19853
19854        utils.addEvent(window, 'keydown', this);
19855
19856        this.on('destroy', function () {
19857            utils.removeEvent(window, 'keydown', this);
19858        });
19859    },
19860
19861    _key: function (e) {
19862        if ( !this.enabled ) {
19863            return;
19864        }
19865
19866        var snap = this.options.snap,   // we are using this alot, better to cache it
19867            newX = snap ? this.currentPage.pageX : this.x,
19868            newY = snap ? this.currentPage.pageY : this.y,
19869            now = utils.getTime(),
19870            prevTime = this.keyTime || 0,
19871            acceleration = 0.250,
19872            pos;
19873
19874        if ( this.options.useTransition && this.isInTransition ) {
19875            pos = this.getComputedPosition();
19876
19877            this._translate(Math.round(pos.x), Math.round(pos.y));
19878            this.isInTransition = false;
19879        }
19880
19881        this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
19882
19883        switch ( e.keyCode ) {
19884            case this.options.keyBindings.pageUp:
19885                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
19886                    newX += snap ? 1 : this.wrapperWidth;
19887                } else {
19888                    newY += snap ? 1 : this.wrapperHeight;
19889                }
19890                break;
19891            case this.options.keyBindings.pageDown:
19892                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
19893                    newX -= snap ? 1 : this.wrapperWidth;
19894                } else {
19895                    newY -= snap ? 1 : this.wrapperHeight;
19896                }
19897                break;
19898            case this.options.keyBindings.end:
19899                newX = snap ? this.pages.length-1 : this.maxScrollX;
19900                newY = snap ? this.pages[0].length-1 : this.maxScrollY;
19901                break;
19902            case this.options.keyBindings.home:
19903                newX = 0;
19904                newY = 0;
19905                break;
19906            case this.options.keyBindings.left:
19907                newX += snap ? -1 : 5 + this.keyAcceleration>>0;
19908                break;
19909            case this.options.keyBindings.up:
19910                newY += snap ? 1 : 5 + this.keyAcceleration>>0;
19911                break;
19912            case this.options.keyBindings.right:
19913                newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
19914                break;
19915            case this.options.keyBindings.down:
19916                newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
19917                break;
19918            default:
19919                return;
19920        }
19921
19922        if ( snap ) {
19923            this.goToPage(newX, newY);
19924            return;
19925        }
19926
19927        if ( newX > 0 ) {
19928            newX = 0;
19929            this.keyAcceleration = 0;
19930        } else if ( newX < this.maxScrollX ) {
19931            newX = this.maxScrollX;
19932            this.keyAcceleration = 0;
19933        }
19934
19935        if ( newY > 0 ) {
19936            newY = 0;
19937            this.keyAcceleration = 0;
19938        } else if ( newY < this.maxScrollY ) {
19939            newY = this.maxScrollY;
19940            this.keyAcceleration = 0;
19941        }
19942
19943        this.scrollTo(newX, newY, 0);
19944
19945        this.keyTime = now;
19946    },
19947
19948    _animate: function (destX, destY, duration, easingFn) {
19949        var that = this,
19950            startX = this.x,
19951            startY = this.y,
19952            startTime = utils.getTime(),
19953            destTime = startTime + duration;
19954
19955        function step () {
19956            var now = utils.getTime(),
19957                newX, newY,
19958                easing;
19959
19960            if ( now >= destTime ) {
19961                that.isAnimating = false;
19962                that._translate(destX, destY);
19963
19964                if ( !that.resetPosition(that.options.bounceTime) ) {
19965                    that._execEvent('scrollEnd');
19966                }
19967
19968                return;
19969            }
19970
19971            now = ( now - startTime ) / duration;
19972            easing = easingFn(now);
19973            newX = ( destX - startX ) * easing + startX;
19974            newY = ( destY - startY ) * easing + startY;
19975            that._translate(newX, newY);
19976
19977            if ( that.isAnimating ) {
19978                rAF(step);
19979            }
19980        }
19981
19982        this.isAnimating = true;
19983        step();
19984    },
19985    handleEvent: function (e) {
19986        switch ( e.type ) {
19987            case 'touchstart':
19988            case 'pointerdown':
19989            case 'MSPointerDown':
19990            case 'mousedown':
19991                this._start(e);
19992                break;
19993            case 'touchmove':
19994            case 'pointermove':
19995            case 'MSPointerMove':
19996            case 'mousemove':
19997                this._move(e);
19998                break;
19999            case 'touchend':
20000            case 'pointerup':
20001            case 'MSPointerUp':
20002            case 'mouseup':
20003            case 'touchcancel':
20004            case 'pointercancel':
20005            case 'MSPointerCancel':
20006            case 'mousecancel':
20007                this._end(e);
20008                break;
20009            case 'orientationchange':
20010            case 'resize':
20011                this._resize();
20012                break;
20013            case 'transitionend':
20014            case 'webkitTransitionEnd':
20015            case 'oTransitionEnd':
20016            case 'MSTransitionEnd':
20017                this._transitionEnd(e);
20018                break;
20019            case 'wheel':
20020            case 'DOMMouseScroll':
20021            case 'mousewheel':
20022                this._wheel(e);
20023                break;
20024            case 'keydown':
20025                this._key(e);
20026                break;
20027            case 'click':
20028                if ( this.enabled && !e._constructed ) {
20029                    e.preventDefault();
20030                    e.stopPropagation();
20031                }
20032                break;
20033        }
20034    }
20035};
20036function createDefaultScrollbar (direction, interactive, type) {
20037    var scrollbar = document.createElement('div'),
20038        indicator = document.createElement('div');
20039
20040    if ( type === true ) {
20041        scrollbar.style.cssText = 'position:absolute;z-index:9999';
20042        indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';
20043    }
20044
20045    indicator.className = 'iScrollIndicator';
20046
20047    if ( direction == 'h' ) {
20048        if ( type === true ) {
20049            scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
20050            indicator.style.height = '100%';
20051        }
20052        scrollbar.className = 'iScrollHorizontalScrollbar';
20053    } else {
20054        if ( type === true ) {
20055            scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
20056            indicator.style.width = '100%';
20057        }
20058        scrollbar.className = 'iScrollVerticalScrollbar';
20059    }
20060
20061    scrollbar.style.cssText += ';overflow:hidden';
20062
20063    if ( !interactive ) {
20064        scrollbar.style.pointerEvents = 'none';
20065    }
20066
20067    scrollbar.appendChild(indicator);
20068
20069    return scrollbar;
20070}
20071
20072function Indicator (scroller, options) {
20073    this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
20074    this.wrapperStyle = this.wrapper.style;
20075    this.indicator = this.wrapper.children[0];
20076    this.indicatorStyle = this.indicator.style;
20077    this.scroller = scroller;
20078
20079    this.options = {
20080        listenX: true,
20081        listenY: true,
20082        interactive: false,
20083        resize: true,
20084        defaultScrollbars: false,
20085        shrink: false,
20086        fade: false,
20087        speedRatioX: 0,
20088        speedRatioY: 0
20089    };
20090
20091    for ( var i in options ) {
20092        this.options[i] = options[i];
20093    }
20094
20095    this.sizeRatioX = 1;
20096    this.sizeRatioY = 1;
20097    this.maxPosX = 0;
20098    this.maxPosY = 0;
20099
20100    if ( this.options.interactive ) {
20101        if ( !this.options.disableTouch ) {
20102            utils.addEvent(this.indicator, 'touchstart', this);
20103            utils.addEvent(window, 'touchend', this);
20104        }
20105        if ( !this.options.disablePointer ) {
20106            utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
20107            utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
20108        }
20109        if ( !this.options.disableMouse ) {
20110            utils.addEvent(this.indicator, 'mousedown', this);
20111            utils.addEvent(window, 'mouseup', this);
20112        }
20113    }
20114
20115    if ( this.options.fade ) {
20116        this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
20117        var durationProp = utils.style.transitionDuration;
20118        if(!durationProp) {
20119            return;
20120        }
20121        this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
20122        // remove 0.0001ms
20123        var self = this;
20124        if(utils.isBadAndroid) {
20125            rAF(function() {
20126                if(self.wrapperStyle[durationProp] === '0.0001ms') {
20127                    self.wrapperStyle[durationProp] = '0s';
20128                }
20129            });
20130        }
20131        this.wrapperStyle.opacity = '0';
20132    }
20133}
20134
20135Indicator.prototype = {
20136    handleEvent: function (e) {
20137        switch ( e.type ) {
20138            case 'touchstart':
20139            case 'pointerdown':
20140            case 'MSPointerDown':
20141            case 'mousedown':
20142                this._start(e);
20143                break;
20144            case 'touchmove':
20145            case 'pointermove':
20146            case 'MSPointerMove':
20147            case 'mousemove':
20148                this._move(e);
20149                break;
20150            case 'touchend':
20151            case 'pointerup':
20152            case 'MSPointerUp':
20153            case 'mouseup':
20154            case 'touchcancel':
20155            case 'pointercancel':
20156            case 'MSPointerCancel':
20157            case 'mousecancel':
20158                this._end(e);
20159                break;
20160        }
20161    },
20162
20163    destroy: function () {
20164        if ( this.options.fadeScrollbars ) {
20165            clearTimeout(this.fadeTimeout);
20166            this.fadeTimeout = null;
20167        }
20168        if ( this.options.interactive ) {
20169            utils.removeEvent(this.indicator, 'touchstart', this);
20170            utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
20171            utils.removeEvent(this.indicator, 'mousedown', this);
20172
20173            utils.removeEvent(window, 'touchmove', this);
20174            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
20175            utils.removeEvent(window, 'mousemove', this);
20176
20177            utils.removeEvent(window, 'touchend', this);
20178            utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
20179            utils.removeEvent(window, 'mouseup', this);
20180        }
20181
20182        if ( this.options.defaultScrollbars ) {
20183            this.wrapper.parentNode.removeChild(this.wrapper);
20184        }
20185    },
20186
20187    _start: function (e) {
20188        var point = e.touches ? e.touches[0] : e;
20189
20190        e.preventDefault();
20191        e.stopPropagation();
20192
20193        this.transitionTime();
20194
20195        this.initiated = true;
20196        this.moved = false;
vendor: 9,615 bytes, lines 20197-20455
20197        this.lastPointX = point.pageX;
20198        this.lastPointY = point.pageY;
20199
20200        this.startTime  = utils.getTime();
20201
20202        if ( !this.options.disableTouch ) {
20203            utils.addEvent(window, 'touchmove', this);
20204        }
20205        if ( !this.options.disablePointer ) {
20206            utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
20207        }
20208        if ( !this.options.disableMouse ) {
20209            utils.addEvent(window, 'mousemove', this);
20210        }
20211
20212        this.scroller._execEvent('beforeScrollStart');
20213    },
20214
20215    _move: function (e) {
20216        var point = e.touches ? e.touches[0] : e,
20217            deltaX, deltaY,
20218            newX, newY,
20219            timestamp = utils.getTime();
20220
20221        if ( !this.moved ) {
20222            this.scroller._execEvent('scrollStart');
20223        }
20224
20225        this.moved = true;
20226
20227        deltaX = point.pageX - this.lastPointX;
20228        this.lastPointX = point.pageX;
20229
20230        deltaY = point.pageY - this.lastPointY;
20231        this.lastPointY = point.pageY;
20232
20233        newX = this.x + deltaX;
20234        newY = this.y + deltaY;
20235
20236        this._pos(newX, newY);
20237
20238// INSERT POINT: indicator._move
20239
20240        e.preventDefault();
20241        e.stopPropagation();
20242    },
20243
20244    _end: function (e) {
20245        if ( !this.initiated ) {
20246            return;
20247        }
20248
20249        this.initiated = false;
20250
20251        e.preventDefault();
20252        e.stopPropagation();
20253
20254        utils.removeEvent(window, 'touchmove', this);
20255        utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
20256        utils.removeEvent(window, 'mousemove', this);
20257
20258        if ( this.scroller.options.snap ) {
20259            var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
20260
20261            var time = this.options.snapSpeed || Math.max(
20262                    Math.max(
20263                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
20264                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
20265                    ), 300);
20266
20267            if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
20268                this.scroller.directionX = 0;
20269                this.scroller.directionY = 0;
20270                this.scroller.currentPage = snap;
20271                this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
20272            }
20273        }
20274
20275        if ( this.moved ) {
20276            this.scroller._execEvent('scrollEnd');
20277        }
20278    },
20279
20280    transitionTime: function (time) {
20281        time = time || 0;
20282        var durationProp = utils.style.transitionDuration;
20283        if(!durationProp) {
20284            return;
20285        }
20286
20287        this.indicatorStyle[durationProp] = time + 'ms';
20288
20289        if ( !time && utils.isBadAndroid ) {
20290            this.indicatorStyle[durationProp] = '0.0001ms';
20291            // remove 0.0001ms
20292            var self = this;
20293            rAF(function() {
20294                if(self.indicatorStyle[durationProp] === '0.0001ms') {
20295                    self.indicatorStyle[durationProp] = '0s';
20296                }
20297            });
20298        }
20299    },
20300
20301    transitionTimingFunction: function (easing) {
20302        this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
20303    },
20304
20305    refresh: function () {
20306        this.transitionTime();
20307
20308        if ( this.options.listenX && !this.options.listenY ) {
20309            this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
20310        } else if ( this.options.listenY && !this.options.listenX ) {
20311            this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
20312        } else {
20313            this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
20314        }
20315
20316        if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
20317            utils.addClass(this.wrapper, 'iScrollBothScrollbars');
20318            utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
20319
20320            if ( this.options.defaultScrollbars && this.options.customStyle ) {
20321                if ( this.options.listenX ) {
20322                    this.wrapper.style.right = '8px';
20323                } else {
20324                    this.wrapper.style.bottom = '8px';
20325                }
20326            }
20327        } else {
20328            utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
20329            utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
20330
20331            if ( this.options.defaultScrollbars && this.options.customStyle ) {
20332                if ( this.options.listenX ) {
20333                    this.wrapper.style.right = '2px';
20334                } else {
20335                    this.wrapper.style.bottom = '2px';
20336                }
20337            }
20338        }
20339
20340        var r = this.wrapper.offsetHeight;  // force refresh
20341
20342        if ( this.options.listenX ) {
20343            this.wrapperWidth = this.wrapper.clientWidth;
20344            if ( this.options.resize ) {
20345                this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
20346                this.indicatorStyle.width = this.indicatorWidth + 'px';
20347            } else {
20348                this.indicatorWidth = this.indicator.clientWidth;
20349            }
20350
20351            this.maxPosX = this.wrapperWidth - this.indicatorWidth;
20352
20353            if ( this.options.shrink == 'clip' ) {
20354                this.minBoundaryX = -this.indicatorWidth + 8;
20355                this.maxBoundaryX = this.wrapperWidth - 8;
20356            } else {
20357                this.minBoundaryX = 0;
20358                this.maxBoundaryX = this.maxPosX;
20359            }
20360
20361            this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
20362        }
20363
20364        if ( this.options.listenY ) {
20365            this.wrapperHeight = this.wrapper.clientHeight;
20366            if ( this.options.resize ) {
20367                this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
20368                this.indicatorStyle.height = this.indicatorHeight + 'px';
20369            } else {
20370                this.indicatorHeight = this.indicator.clientHeight;
20371            }
20372
20373            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
20374
20375            if ( this.options.shrink == 'clip' ) {
20376                this.minBoundaryY = -this.indicatorHeight + 8;
20377                this.maxBoundaryY = this.wrapperHeight - 8;
20378            } else {
20379                this.minBoundaryY = 0;
20380                this.maxBoundaryY = this.maxPosY;
20381            }
20382
20383            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
20384            this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
20385        }
20386
20387        this.updatePosition();
20388    },
20389
20390    updatePosition: function () {
20391        var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
20392            y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
20393
20394        if ( !this.options.ignoreBoundaries ) {
20395            if ( x < this.minBoundaryX ) {
20396                if ( this.options.shrink == 'scale' ) {
20397                    this.width = Math.max(this.indicatorWidth + x, 8);
20398                    this.indicatorStyle.width = this.width + 'px';
20399                }
20400                x = this.minBoundaryX;
20401            } else if ( x > this.maxBoundaryX ) {
20402                if ( this.options.shrink == 'scale' ) {
20403                    this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
20404                    this.indicatorStyle.width = this.width + 'px';
20405                    x = this.maxPosX + this.indicatorWidth - this.width;
20406                } else {
20407                    x = this.maxBoundaryX;
20408                }
20409            } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
20410                this.width = this.indicatorWidth;
20411                this.indicatorStyle.width = this.width + 'px';
20412            }
20413
20414            if ( y < this.minBoundaryY ) {
20415                if ( this.options.shrink == 'scale' ) {
20416                    this.height = Math.max(this.indicatorHeight + y * 3, 8);
20417                    this.indicatorStyle.height = this.height + 'px';
20418                }
20419                y = this.minBoundaryY;
20420            } else if ( y > this.maxBoundaryY ) {
20421                if ( this.options.shrink == 'scale' ) {
20422                    this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
20423                    this.indicatorStyle.height = this.height + 'px';
20424                    y = this.maxPosY + this.indicatorHeight - this.height;
20425                } else {
20426                    y = this.maxBoundaryY;
20427                }
20428            } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
20429                this.height = this.indicatorHeight;
20430                this.indicatorStyle.height = this.height + 'px';
20431            }
20432        }
20433
20434        this.x = x;
20435        this.y = y;
20436
20437        if ( this.scroller.options.useTransform ) {
20438            this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
20439        } else {
20440            this.indicatorStyle.left = x + 'px';
20441            this.indicatorStyle.top = y + 'px';
20442        }
20443    },
20444
20445    _pos: function (x, y) {
20446        if ( x < 0 ) {
20447            x = 0;
20448        } else if ( x > this.maxPosX ) {
20449            x = this.maxPosX;
20450        }
20451
20452        if ( y < 0 ) {
20453            y = 0;
20454        } else if ( y > this.maxPosY ) {
20455            y = this.maxPosY;
20456        }
20457
20458        x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
20459        y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
20460
20461        this.scroller.scrollTo(x, y);
20462    },
20463
20464    fade: function (val, hold) {
20465        if ( hold && !this.visible ) {
20466            return;
20467        }
20468
20469        clearTimeout(this.fadeTimeout);
20470        this.fadeTimeout = null;
20471
20472        var time = val ? 250 : 500,
20473            delay = val ? 0 : 300;
20474
20475        val = val ? '1' : '0';
20476
20477        this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
20478
20479        this.fadeTimeout = setTimeout((function (val) {
20480            this.wrapperStyle.opacity = val;
20481            this.visible = +val;
20482        }).bind(this, val), delay);
20483    }
20484};
20485
20486IScroll.utils = utils;
20487
20488if ( typeof module != 'undefined' && module.exports ) {
20489    module.exports = IScroll;
20490} else if ( typeof define == 'function' && define.amd ) {
20491        define( function () { return IScroll; } );
20492} else {
20493    window.IScroll = IScroll;
20494}
20495
20496})(window, document, Math);
20497/*!
20498 * fullPage 2.9.4
20499 * https://github.com/alvarotrigo/fullPage.js
20500 * @license MIT licensed
20501 *
20502 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
20503 */
20504(function(global, factory) {
20505    'use strict';
20506    if (typeof define === 'function' && define.amd) {
20507        define(['jquery'], function($) {
20508          return factory($, global, global.document, global.Math);
20509        });
20510    } else if (typeof exports === "object" && exports) {
20511        module.exports = factory(require('jquery'), global, global.document, global.Math);
20512    } else {
20513        factory(jQuery, global, global.document, global.Math);
20514    }
20515})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
20516    'use strict';
20517
20518    // keeping central set of classnames and selectors
20519    var WRAPPER =               'fullpage-wrapper';
20520    var WRAPPER_SEL =           '.' + WRAPPER;
20521
20522    // slimscroll
20523    var SCROLLABLE =            'fp-scrollable';
20524    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
20525
20526    // util
20527    var RESPONSIVE =            'fp-responsive';
20528    var NO_TRANSITION =         'fp-notransition';
20529    var DESTROYED =             'fp-destroyed';
20530    var ENABLED =               'fp-enabled';
20531    var VIEWING_PREFIX =        'fp-viewing';
20532    var ACTIVE =                'active';
20533    var ACTIVE_SEL =            '.' + ACTIVE;
20534    var COMPLETELY =            'fp-completely';
20535    var COMPLETELY_SEL =        '.' + COMPLETELY;
20536
20537    // section
20538    var SECTION_DEFAULT_SEL =   '.section';
20539    var SECTION =               'fp-section';
20540    var SECTION_SEL =           '.' + SECTION;
20541    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
20542    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
20543    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
20544    var TABLE_CELL =            'fp-tableCell';
20545    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
20546    var AUTO_HEIGHT =           'fp-auto-height';
20547    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
20548    var NORMAL_SCROLL =         'fp-normal-scroll';
20549    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
20550
20551    // section nav
20552    var SECTION_NAV =           'fp-nav';
20553    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
20554    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
20555    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
20556    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
20557
20558    // slide
20559    var SLIDE_DEFAULT_SEL =     '.slide';
20560    var SLIDE =                 'fp-slide';
20561    var SLIDE_SEL =             '.' + SLIDE;
20562    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
20563    var SLIDES_WRAPPER =        'fp-slides';
20564    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
20565    var SLIDES_CONTAINER =      'fp-slidesContainer';
20566    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
20567    var TABLE =                 'fp-table';
20568
20569    // slide nav
20570    var SLIDES_NAV =            'fp-slidesNav';
20571    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
20572    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
20573    var SLIDES_ARROW =          'fp-controlArrow';
20574    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
20575    var SLIDES_PREV =           'fp-prev';
20576    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
20577    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
20578    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
20579    var SLIDES_NEXT =           'fp-next';
20580    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
20581    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
20582    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
20583
20584    var $window = $(window);
20585    var $document = $(document);
20586
20587    // Default options for iScroll.js used when using scrollOverflow
20588    var iscrollOptions = {
20589        scrollbars: true,
20590        mouseWheel: true,
20591        hideScrollbars: false,
20592        fadeScrollbars: false,
20593        disableMouse: true,
20594        interactiveScrollbars: true,
20595        bounce: false,
20596    };
20597
20598    $.fn.fullpage = function(options) {
20599        //only once my friend!
20600        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
20601
20602        // common jQuery objects
20603        var $htmlBody = $('html, body');
20604        var $body = $('body');
20605
20606        var FP = $.fn.fullpage;
20607
20608        // Creating some defaults, extending them with any options that were provided
20609        options = $.extend({
20610            //navigation
20611            menu: false,
20612            anchors:[],
20613            lockAnchors: false,
20614            navigation: false,
20615            navigationPosition: 'right',
20616            navigationTooltips: [],
20617            showActiveTooltip: false,
20618            slidesNavigation: false,
20619            slidesNavPosition: 'bottom',
20620            scrollBar: false,
20621            hybrid: false,
20622
20623            //scrolling
20624            css3: true,
20625            scrollingSpeed: 700,
20626            autoScrolling: true,
20627            fitToSection: true,
20628            fitToSectionDelay: 1000,
20629            easing: 'easeInOutCubic',
20630            easingcss3: 'ease',
20631            loopBottom: false,
20632            loopTop: false,
20633            loopHorizontal: true,
20634            continuousVertical: false,
20635            continuousHorizontal: false,
20636            scrollHorizontally: false,
20637            interlockedSlides: false,
20638            dragAndMove: false,
20639            offsetSections: false,
20640            resetSliders: false,
20641            fadingEffect: false,
20642            normalScrollElements: null,
20643            scrollOverflow: false,
20644            scrollOverflowReset: false,
20645            scrollOverflowHandler: iscrollHandler,
20646            scrollOverflowOptions: null,
20647            touchSensitivity: 5,
20648            normalScrollElementTouchThreshold: 5,
20649            bigSectionsDestination: null,
20650
20651            //Accessibility
20652            keyboardScrolling: true,
20653            animateAnchor: true,
20654            recordHistory: true,
20655
20656            //design
20657            controlArrows: true,
20658            controlArrowColor: '#fff',
20659            verticalCentered: true,
20660            sectionsColor : [],
20661            paddingTop: 0,
20662            paddingBottom: 0,
20663            fixedElements: null,
20664            responsive: 0, //backwards compabitility with responsiveWiddth
20665            responsiveWidth: 0,
20666            responsiveHeight: 0,
20667            responsiveSlides: false,
20668            parallax: false,
20669            parallaxOptions: {
20670                type: 'reveal',
20671                percentage: 62,
20672                property: 'translate'
20673            },
20674
20675            //Custom selectors
20676            sectionSelector: SECTION_DEFAULT_SEL,
20677            slideSelector: SLIDE_DEFAULT_SEL,
20678
20679            //events
20680            afterLoad: null,
20681            onLeave: null,
20682            afterRender: null,
20683            afterResize: null,
20684            afterReBuild: null,
20685            afterSlideLoad: null,
20686            onSlideLeave: null,
20687            afterResponsive: null,
20688
20689            lazyLoading: true
20690        }, options);
20691
20692        //flag to avoid very fast sliding for landscape sliders
20693        var slideMoving = false;
20694
20695        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
20696        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
20697        var container = $(this);
20698        var windowsHeight = $window.height();
20699        var isResizing = false;
20700        var isWindowFocused = true;
20701        var lastScrolledDestiny;
20702        var lastScrolledSlide;
20703        var canScroll = true;
20704        var scrollings = [];
20705        var controlPressed;
20706        var startingSection;
20707        var isScrollAllowed = {};
20708        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
20709        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
20710        var MSPointer = getMSPointer();
20711        var events = {
20712            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
20713            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
20714        };
20715
20716        //cheks for passive event support
20717        //added by Uncode from new fullPage updates
20718        var g_supportsPassive = false;
20719        try {
20720          var opts = Object.defineProperty({}, 'passive', {
20721            get: function() {
20722              g_supportsPassive = true;
20723            }
20724          });
20725          window.addEventListener("testPassive", null, opts);
20726          window.removeEventListener("testPassive", null, opts);
20727        } catch (e) {}
20728
20729        //timeouts
20730        var resizeId;
20731        var afterSectionLoadsId;
20732        var afterSlideLoadsId;
20733        var scrollId;
20734        var scrollId2;
20735        var keydownId;
20736        var originals = $.extend(true, {}, options); //deep copy
20737
20738        //Uncode addition
20739        var $masthead = $('#masthead');
20740        var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
20741        var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
20742        var bodyBorder = UNCODE.bodyBorder;
20743        var adminBarHeight = UNCODE.adminBarHeight;
20744
20745        displayWarnings();
20746
20747        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
20748        iscrollOptions.click = isTouch; // see #2035
20749
20750        //extending iScroll options with the user custom ones
20751        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
20752
20753        //easeInOutCubic animation included in the plugin
20754        $.extend($.easing,{ easeInOutCubic: function (x, t, b, c, d) {if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;}});
20755
20756        /**
20757        * Sets the autoScroll option.
20758        * It changes the scroll bar visibility and the history of the site as a result.
20759        */
20760        function setAutoScrolling(value, type){
20761            //removing the transformation
20762            if(!value){
20763                silentScroll(0);
20764            }
20765
20766            setVariableState('autoScrolling', value, type);
20767
20768            var element = $(SECTION_ACTIVE_SEL);
20769
20770            if(options.autoScrolling && !options.scrollBar){
20771                $htmlBody.css({
20772                    'overflow' : 'hidden !important',
20773                    'height' : '100%'
20774                });
20775
20776                //Uncode addition
20777                //setRecordHistory(originals.recordHistory, 'internal');
20778
20779                //for IE touch devices
20780                container.css({
20781                    '-ms-touch-action': 'none',
20782                    'touch-action': 'none'
20783                });
20784
20785                if(element.length){
20786                    //moving the container up
20787                    silentScroll(element.position().top);
20788                }
20789
20790            }else{
20791                $htmlBody.css({
20792                    'overflow' : 'visible !important',
20793                    'height' : 'initial'
20794                });
20795
20796                //Uncode addition
20797                //setRecordHistory(false, 'internal');
20798
20799                //for IE touch devices
20800                container.css({
20801                    '-ms-touch-action': '',
20802                    'touch-action': ''
20803                });
20804
20805                //scrolling the page to the section with no animation
20806                if (element.length) {
20807                    $htmlBody.scrollTop(element.position().top);
20808                }
20809            }
20810        }
20811
20812        /**
20813        * Defines wheter to record the history for each hash change in the URL.
20814        */
20815        function setRecordHistory(value, type){
20816            setVariableState('recordHistory', value, type);
20817        }
20818
20819        /**
20820        * Defines the scrolling speed
20821        */
20822        function setScrollingSpeed(value, type){
20823            setVariableState('scrollingSpeed', value, type);
20824        }
20825
20826        /**
20827        * Sets fitToSection
20828        */
20829        function setFitToSection(value, type){
20830            setVariableState('fitToSection', value, type);
20831        }
20832
20833        /**
20834        * Sets lockAnchors
20835        */
20836        function setLockAnchors(value){
20837            options.lockAnchors = value;
20838        }
20839
20840        /**
20841        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
20842        */
20843        function setMouseWheelScrolling(value){
20844            if(value){
20845                addMouseWheelHandler();
20846                addMiddleWheelHandler();
20847            }else{
20848                removeMouseWheelHandler();
20849                removeMiddleWheelHandler();
20850            }
20851        }
20852
20853        /**
20854        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
20855        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
20856        *
20857        * @param directions string containing the direction or directions separated by comma.
20858        */
20859        function setAllowScrolling(value, directions){
20860            if(typeof directions !== 'undefined'){
20861                directions = directions.replace(/ /g,'').split(',');
20862
20863                $.each(directions, function (index, direction){
20864                    setIsScrollAllowed(value, direction, 'm');
20865                });
20866            }
20867            else if(value){
20868                setMouseWheelScrolling(true);
20869                addTouchHandler();
20870            }else{
20871                setMouseWheelScrolling(false);
20872                removeTouchHandler();
20873            }
20874        }
20875
20876        /**
20877        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
20878        */
20879        function setKeyboardScrolling(value, directions){
20880            if(typeof directions !== 'undefined'){
20881                directions = directions.replace(/ /g,'').split(',');
20882
20883                $.each(directions, function (index, direction){
20884                    setIsScrollAllowed(value, direction, 'k');
20885                });
20886            }else{
20887                options.keyboardScrolling = value;
20888            }
20889        }
20890
20891        /**
20892        * Moves the page up one section.
20893        */
20894        function moveSectionUp(){
20895            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
20896
20897            //looping to the bottom if there's no more sections above
20898            if (!prev.length && (options.loopTop || options.continuousVertical)) {
20899                prev = $(SECTION_SEL).last();
20900            }
20901
20902            if (prev.length) {
20903                scrollPage(prev, null, true);
20904            }
20905        }
20906
20907        /**
20908        * Moves the page down one section.
20909        */
20910        function moveSectionDown(){
20911            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
20912
20913            //looping to the top if there's no more sections below
20914            if(!next.length &&
20915                (options.loopBottom || options.continuousVertical)){
20916                next = $(SECTION_SEL).first();
20917            }
20918
20919            if(next.length){
20920                scrollPage(next, null, false);
20921            }
20922        }
20923
20924        /**
20925        * Moves the page to the given section and slide with no animation.
20926        * Anchors or index positions can be used as params.
20927        */
20928        function silentMoveTo(sectionAnchor, slideAnchor){
20929            setScrollingSpeed (0, 'internal');
20930            moveTo(sectionAnchor, slideAnchor);
20931            setScrollingSpeed (originals.scrollingSpeed, 'internal');
20932        }
20933
20934        /**
20935        * Moves the page to the given section and slide.
20936        * Anchors or index positions can be used as params.
20937        */
20938        function moveTo(sectionAnchor, slideAnchor){
20939            var destiny = getSectionByAnchor(sectionAnchor);
20940
20941            if (typeof slideAnchor !== 'undefined'){
20942                scrollPageAndSlide(sectionAnchor, slideAnchor);
20943            }else if(destiny.length > 0){
20944                scrollPage(destiny);
20945            }
20946        }
20947
20948        /**
20949        * Slides right the slider of the active section.
20950        * Optional `section` param.
20951        */
20952        function moveSlideRight(section){
20953            moveSlide('right', section);
20954        }
20955
20956        /**
20957        * Slides left the slider of the active section.
20958        * Optional `section` param.
20959        */
20960        function moveSlideLeft(section){
20961            moveSlide('left', section);
20962        }
20963
20964        /**
20965         * When resizing is finished, we adjust the slides sizes and positions
20966         */
20967        function reBuild(resizing){
20968            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
20969
20970            isResizing = true;
20971
20972            windowsHeight = $window.height();  //updating global var
20973
20974            $(SECTION_SEL).each(function(){
20975                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
20976                var slides = $(this).find(SLIDE_SEL);
20977
20978                //adjusting the height of the table-cell for IE and Firefox
20979                if(options.verticalCentered){
20980                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
20981                }
20982
20983                $(this).css('height', windowsHeight + 'px');
20984
20985                //resizing the scrolling divs
20986                if(options.scrollOverflow){
20987                    if(slides.length){
20988                        slides.each(function(){
20989                            createScrollBar($(this));
20990                        });
20991                    }else{
20992                        createScrollBar($(this));
20993                    }
20994                }
20995
20996                //adjusting the position fo the FULL WIDTH slides...
20997                if (slides.length > 1) {
20998                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
20999                }
21000            });
21001
21002            var activeSection = $(SECTION_ACTIVE_SEL);
21003            var sectionIndex = activeSection.index(SECTION_SEL);
21004
21005            //isn't it the first section?
21006            if(sectionIndex){
21007                //adjusting the position for the current section
21008                silentMoveTo(sectionIndex + 1);
21009            }
21010
21011            isResizing = false;
21012            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
21013            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
21014        }
21015
21016        /**
21017        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
21018        * are smaller than the set limit values.
21019        */
21020        function setResponsive(active){
21021            var isResponsive = $body.hasClass(RESPONSIVE);
21022
21023            if(active){
21024                if(!isResponsive){
21025                    setAutoScrolling(false, 'internal');
21026                    setFitToSection(false, 'internal');
21027                    $(SECTION_NAV_SEL).hide();
21028                    $body.addClass(RESPONSIVE);
21029                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
21030                }
21031            }
21032            else if(isResponsive){
21033                setAutoScrolling(originals.autoScrolling, 'internal');
21034                setFitToSection(originals.autoScrolling, 'internal');
21035                $(SECTION_NAV_SEL).show();
21036                $body.removeClass(RESPONSIVE);
21037                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
21038            }
21039        }
21040
21041        if($(this).length){
21042            //public functions
21043            FP.setAutoScrolling = setAutoScrolling;
21044            FP.setRecordHistory = setRecordHistory;
21045            FP.setScrollingSpeed = setScrollingSpeed;
21046            FP.setFitToSection = setFitToSection;
21047            FP.setLockAnchors = setLockAnchors;
21048            FP.setMouseWheelScrolling = setMouseWheelScrolling;
21049            FP.setAllowScrolling = setAllowScrolling;
21050            FP.setKeyboardScrolling = setKeyboardScrolling;
21051            FP.moveSectionUp = moveSectionUp;
21052            FP.moveSectionDown = moveSectionDown;
21053            FP.silentMoveTo = silentMoveTo;
21054            FP.moveTo = moveTo;
21055            FP.moveSlideRight = moveSlideRight;
21056            FP.moveSlideLeft = moveSlideLeft;
21057            FP.fitToSection = fitToSection;
21058            FP.reBuild = reBuild;
21059            FP.setResponsive = setResponsive;
21060            FP.destroy = destroy;
21061
21062            init();
21063
21064            bindEvents();
21065        }
21066
21067        function init(){
21068            //if css3 is not supported, it will use jQuery animations
21069            if(options.css3){
21070                options.css3 = support3d();
21071            }
21072
21073            options.scrollBar = options.scrollBar || options.hybrid;
21074
21075            setOptionsFromDOM();
21076            prepareDom();
21077            setAllowScrolling(true);
21078            setAutoScrolling(options.autoScrolling, 'internal');
21079            responsive();
21080
21081            //setting the class for the body element
21082            setBodyClass();
21083
21084            //Uncode addition
21085            // if(document.readyState === 'complete'){
21086            //     scrollToAnchor();
21087            // }
21088            // $window.on('load', scrollToAnchor);
21089        }
21090
21091        function bindEvents(){
21092            $window
21093                //when scrolling...
21094                //.on('scroll', scrollHandler)
21095
21096                //detecting any change on the URL to scroll to the given anchor link
21097                //(a way to detect back history button as we play with the hashes on the URL)
21098                .on('hashchange', hashChangeHandler)
21099
21100                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
21101                .blur(blurHandler)
21102
21103                //when resizing the site, we adjust the heights of the sections, slimScroll...
21104                .resize(resizeHandler);
21105
21106            $document
21107                //Sliding with arrow keys, both, vertical and horizontal
21108                .keydown(keydownHandler)
21109
21110                //to prevent scrolling while zooming
21111                .keyup(keyUpHandler)
21112
21113                //Scrolls to the section when clicking the navigation bullet
21114                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
21115
21116                //Scrolls the slider to the given slide destination for the given section
21117                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
21118
21119                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
21120
21121            //Scrolling horizontally when clicking on the slider controls.
21122            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
21123
21124            /**
21125            * Applying normalScroll elements.
21126            * Ignoring the scrolls over the specified selectors.
21127            */
21128            if(options.normalScrollElements){
21129                $document.on('mouseenter', options.normalScrollElements, function () {
21130                    setMouseWheelScrolling(false);
21131                });
21132
21133                $document.on('mouseleave', options.normalScrollElements, function(){
21134                    setMouseWheelScrolling(true);
21135                });
21136            }
21137        }
21138
21139        /**
21140        * Setting options from DOM elements if they are not provided.
21141        */
21142        function setOptionsFromDOM(){
21143            var sections = container.find(options.sectionSelector);
21144
21145            //no anchors option? Checking for them in the DOM attributes
21146            if(!options.anchors.length){
21147                options.anchors = sections.filter('[data-anchor]').map(function(){
21148                    return $(this).data('anchor').toString();
21149                }).get();
21150            }
21151
21152            //no tooltips option? Checking for them in the DOM attributes
21153            if(!options.navigationTooltips.length){
21154                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
21155                    return $(this).data('tooltip').toString();
21156                }).get();
21157            }
21158        }
21159
21160        /**
21161        * Works over the DOM structure to set it up for the current fullpage options.
21162        */
21163        function prepareDom(){
21164            container.css({
21165                'height': '100%',
21166                'position': 'relative'
21167            });
21168
21169            //adding a class to recognize the container internally in the code
21170            container.addClass(WRAPPER);
21171            $('html').addClass(ENABLED);
21172
21173            windowsHeight = $window.height();
21174
21175            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
21176
21177            addInternalSelectors();
21178
21179             //styling the sections / slides / menu
21180            $(SECTION_SEL).each(function(index){
21181                var section = $(this);
21182                var slides = section.find(SLIDE_SEL);
21183                var numSlides = slides.length;
21184
21185                styleSection(section, index);
21186                styleMenu(section, index);
21187
21188                // if there's any slide
21189                if (numSlides > 0) {
21190                    styleSlides(section, slides, numSlides);
21191                }else{
21192                    if(options.verticalCentered){
21193                        addTableClass(section);
21194                    }
21195                }
21196            });
21197
21198            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
21199            if(options.fixedElements && options.css3){
21200                $(options.fixedElements).appendTo($body);
21201            }
21202
21203            //vertical centered of the navigation + active bullet
21204            if(options.navigation){
21205                addVerticalNavigation();
21206            }
21207
21208            enableYoutubeAPI();
21209
21210            if(options.scrollOverflow){
21211                if(document.readyState === 'complete'){
21212                    createScrollBarHandler();
21213                }
21214                //after DOM and images are loaded
21215                $window.on('load', createScrollBarHandler);
21216            }else{
21217                afterRenderActions();
21218            }
21219        }
21220
21221        /**
21222        * Styles the horizontal slides for a section.
21223        */
21224        function styleSlides(section, slides, numSlides){
21225            var sliderWidth = numSlides * 100;
21226            var slideWidth = 100 / numSlides;
21227
21228            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
21229            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
21230
21231            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
21232
21233            if(numSlides > 1){
21234                if(options.controlArrows){
21235                    createSlideArrows(section);
21236                }
21237
21238                if(options.slidesNavigation){
21239                    addSlidesNavigation(section, numSlides);
21240                }
21241            }
21242
21243            slides.each(function(index) {
21244                $(this).css('width', slideWidth + '%');
21245
21246                if(options.verticalCentered){
21247                    addTableClass($(this));
21248                }
21249            });
21250
21251            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
21252
21253            //if the slide won't be an starting point, the default will be the first one
21254            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
21254ide by default.
21255            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
21256                silentLandscapeScroll(startingSlide, 'internal');
21257            }else{
21258                slides.eq(0).addClass(ACTIVE);
21259            }
21260        }
21261
21262        /**
21263        * Styling vertical sections
21264        */
21265        function styleSection(section, index){
21266            //if no active section is defined, the 1st one will be the default one
21267            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
21268                section.addClass(ACTIVE);
21269            }
21270            startingSection = $(SECTION_ACTIVE_SEL);
21271
21272            section.css('height', windowsHeight + 'px');
21273
21274            if(options.paddingTop){
21275                section.css('padding-top', options.paddingTop);
21276            }
21277
21278            if(options.paddingBottom){
21279                section.css('padding-bottom', options.paddingBottom);
21280            }
21281
21282            if (typeof options.sectionsColor[index] !==  'undefined') {
21283                section.css('background-color', options.sectionsColor[index]);
21284            }
21285
21286            if (typeof options.anchors[index] !== 'undefined') {
21287                section.attr('data-anchor', options.anchors[index]);
21288            }
21289        }
21290
21291        /**
21292        * Sets the data-anchor attributes to the menu elements and activates the current one.
21293        */
21294        function styleMenu(section, index){
21295            if (typeof options.anchors[index] !== 'undefined') {
21296                //activating the menu / nav element on load
21297                if(section.hasClass(ACTIVE)){
21298                    activateMenuAndNav(options.anchors[index], index);
21299                }
21300            }
21301
21302            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
21303            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
21304                $(options.menu).appendTo($body);
21305            }
21306        }
21307
21308        /**
21309        * Adds internal classes to be able to provide customizable selectors
21310        * keeping the link with the style sheet.
21311        */
21312        function addInternalSelectors(){
21313            container.find(options.sectionSelector).addClass(SECTION);
21314            container.find(options.slideSelector).addClass(SLIDE);
21315        }
21316
21317        /**
21318        * Creates the control arrows for the given section
21319        */
21320        function createSlideArrows(section){
21321            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
21322
21323            if(options.controlArrowColor!='#fff'){
21324                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
21325                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
21326            }
21327
21328            if(!options.loopHorizontal){
21329                section.find(SLIDES_ARROW_PREV_SEL).hide();
21330            }
21331        }
21332
21333        /**
21334        * Creates a vertical navigation bar.
21335        */
21336        function addVerticalNavigation(){
21337            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
21338            var nav = $(SECTION_NAV_SEL);
21339
21340            nav.addClass(function() {
21341                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
21342            });
21343
21344            for (var i = 0; i < $(SECTION_SEL).length; i++) {
21345                var link = '';
21346                if (options.anchors.length) {
21347                    link = options.anchors[i];
21348                }
21349
21350                var li = '<li><a href="#' + link + '"><span></span></a>';
21351
21352                // Only add tooltip if needed (defined by user)
21353                var tooltip = options.navigationTooltips[i];
21354
21355                if (typeof tooltip !== 'undefined' && tooltip !== '') {
21356                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
21357                }
21358
21359                li += '</li>';
21360
21361                nav.find('ul').append(li);
21362            }
21363
21364            //centering it vertically
21365            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
21366
21367            //activating the current active section
21368            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
21369        }
21370
21371        /**
21372        * Creates the slim scroll scrollbar for the sections and slides inside them.
21373        */
21374        function createScrollBarHandler(){
21375            $(SECTION_SEL).each(function(){
21376                var slides = $(this).find(SLIDE_SEL);
21377
21378                if(slides.length){
21379                    slides.each(function(){
21380                        createScrollBar($(this));
21381                    });
21382                }else{
21383                    createScrollBar($(this));
21384                }
21385
21386            });
21387            afterRenderActions();
21388        }
21389
21390        /*
21391        * Enables the Youtube videos API so we can control their flow if necessary.
21392        */
21393        function enableYoutubeAPI(){
21394            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
21395                addURLParam($(this), 'enablejsapi=1');
21396            });
21397        }
21398
21399        /**
21400        * Adds a new parameter and its value to the `src` of a given element
21401        */
21402        function addURLParam(element, newParam){
21403            var originalSrc = element.attr('src');
21404            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
21405        }
21406
21407        /*
21408        * Returns the prefix sign to use for a new parameter in an existen URL.
21409        *
21410        * @return {String}  ? | &
21411        */
21412        function getUrlParamSign(url){
21413            return ( !/\?/.test( url ) ) ? '?' : '&';
21414        }
21415
21416        /**
21417        * Actions and callbacks to fire afterRender
21418        */
21419        function afterRenderActions(){
21420            var section = $(SECTION_ACTIVE_SEL);
21421
21422            section.addClass(COMPLETELY);
21423
21424            if(options.scrollOverflowHandler.afterRender){
21425                options.scrollOverflowHandler.afterRender(section);
21426            }
21427            lazyLoad(section);
21428            playMedia(section);
21429            options.scrollOverflowHandler.afterLoad();
21430
21431            if(isDestinyTheStartingSection()){
21432                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
21433            }
21434
21435            $.isFunction( options.afterRender ) && options.afterRender.call(container);
21436        }
21437
21438        /**
21439        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
21440        */
21441        function isDestinyTheStartingSection(){
21442            var anchors =  window.location.hash.replace('#', '').split('/');
21443            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
21444
21445            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
21446        }
21447
21448
21449        var isScrolling = false;
21450        var lastScroll = 0;
21451
21452        //when scrolling...
21453        function scrollHandler(){
21454            var currentSection;
21455
21456            if(!options.autoScrolling || options.scrollBar){
21457                var currentScroll = $window.scrollTop();
21458                var scrollDirection = getScrollDirection(currentScroll);
21459                var visibleSectionIndex = 0;
21460                var screen_mid = currentScroll + ($window.height() / 2.0);
21461                var isAtBottom = $body.height() - $window.height() === currentScroll;
21462                var sections =  document.querySelectorAll(SECTION_SEL);
21463
21464                //when using `auto-height` for a small last section it won't be centered in the viewport
21465                if(isAtBottom){
21466                    visibleSectionIndex = sections.length - 1;
21467                }
21468                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
21469                else if(!currentScroll){
21470                    visibleSectionIndex = 0;
21471                }
21472
21473                //taking the section which is showing more content in the viewport
21474                else{
21475                    for (var i = 0; i < sections.length; ++i) {
21476                        var section = sections[i];
21477
21478                        // Pick the the last section which passes the middle line of the screen.
21479                        if (section.offsetTop <= screen_mid)
21480                        {
21481                            visibleSectionIndex = i;
21482                        }
21483                    }
21484                }
21485
21486                if(isCompletelyInViewPort(scrollDirection)){
21487                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
21488                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
21489                    }
21490                }
21491
21492                //geting the last one, the current one on the screen
21493                currentSection = $(sections).eq(visibleSectionIndex);
21494
21495                //setting the visible section as active when manually scrolling
21496                //executing only once the first time we reach the section
21497                if(!currentSection.hasClass(ACTIVE)){
21498                    isScrolling = true;
21499                    var leavingSection = $(SECTION_ACTIVE_SEL);
21500                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
21501                    var yMovement = getYmovement(currentSection);
21502                    var anchorLink  = currentSection.data('anchor');
21503                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
21504                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
21505                    var slideIndex;
21506                    var slideAnchorLink;
21507
21508                    if(activeSlide.length){
21509                        slideAnchorLink = activeSlide.data('anchor');
21510                        slideIndex = activeSlide.index();
21511                    }
21512
21513                    if(canScroll){
21514                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
21515
21516                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
21517                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
21518
21519                        stopMedia(leavingSection);
21520                        lazyLoad(currentSection);
21521                        playMedia(currentSection);
21522
21523                        activateMenuAndNav(anchorLink, sectionIndex - 1);
21524
21525                        if(options.anchors.length){
21526                            //needed to enter in hashChange event when using the menu with anchor links
21527                            lastScrolledDestiny = anchorLink;
21528                        }
21529                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
21530                    }
21531
21532                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
21533                    clearTimeout(scrollId);
21534                    scrollId = setTimeout(function(){
21535                        isScrolling = false;
21536                    }, 100);
21537                }
21538
21539                if(options.fitToSection){
21540                    //for the auto adjust of the viewport to fit a whole section
21541                    clearTimeout(scrollId2);
21542
21543                    scrollId2 = setTimeout(function(){
21544                        //checking it again in case it changed during the delay
21545                        if(options.fitToSection){
21546                            fitToSection();
21547                        }
21548                    }, options.fitToSectionDelay);
21549                }
21550            }
21551        }
21552
21553        /**
21554        * Fits the site to the nearest active section
21555        */
21556        function fitToSection(){
21557            //checking fitToSection again in case it was set to false before the timeout delay
21558            if(canScroll){
21559                //allows to scroll to an active section and
21560                //if the section is already active, we prevent firing callbacks
21561                isResizing = true;
21562
21563                scrollPage($(SECTION_ACTIVE_SEL));
21564                isResizing = false;
21565            }
21566        }
21567
21568        /**
21569        * Determines whether the active section has seen in its whole or not.
21570        */
21571        function isCompletelyInViewPort(movement){
21572            var top = $(SECTION_ACTIVE_SEL).position().top;
21573            var bottom = top + $window.height();
21574
21575            if(movement == 'up'){
21576                return bottom >= ($window.scrollTop() + $window.height());
21577            }
21578            return top <= $window.scrollTop();
21579        }
21580
21581        /**
21582        * Gets the directon of the the scrolling fired by the scroll event.
21583        */
21584        function getScrollDirection(currentScroll){
21585            var direction = currentScroll > lastScroll ? 'down' : 'up';
21586
21587            lastScroll = currentScroll;
21588
21589            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
21590            previousDestTop = currentScroll;
21591
21592            return direction;
21593        }
21594
21595        /**
21596        * Determines the way of scrolling up or down:
21597        * by 'automatically' scrolling a section or by using the default and normal scrolling.
21598        */
21599        function scrolling(type, scrollable){
21600            if (!isScrollAllowed.m[type]){
21601                return;
21602            }
21603            var check = (type === 'down') ? 'bottom' : 'top';
21604            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
21605
21606            if(scrollable.length > 0 ){
21607                //is the scrollbar at the start/end of the scroll?
21608                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
21609                    scrollSection();
21610                }else{
21611                    return true;
21612                }
21613            }else{
21614                // moved up/down
21615                scrollSection();
21616            }
21617        }
21618
21619        /*
21620        * Preventing bouncing in iOS #2285
21621        */
21622        function preventBouncing(event){
21623            var e = event.originalEvent;
21624            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){
21625                //preventing the easing on iOS devices
21626                event.preventDefault();
21627            }
21628        }
21629
21630        var touchStartY = 0;
21631        var touchStartX = 0;
21632        var touchEndY = 0;
21633        var touchEndX = 0;
21634
21635        /* Detecting touch events
21636
21637        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
21638        * This way, the touchstart and the touch moves shows an small difference between them which is the
21639        * used one to determine the direction.
21640        */
21641        function touchMoveHandler(event){
21642            var e = event.originalEvent;
21643            var activeSection = $(e.target).closest(SECTION_SEL);
21644
21645            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
21646            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
21647
21648                if(options.autoScrolling){
21649                    //preventing the easing on iOS devices
21650                    event.preventDefault();
21651                }
21652
21653                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
21654                var touchEvents = getEventsPage(e);
21655
21656                touchEndY = touchEvents.y;
21657                touchEndX = touchEvents.x;
21658
21659                //if movement in the X axys is greater than in the Y and the currect section has slides...
21660                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
21661
21662                    //is the movement greater than the minimum resistance to scroll?
21663                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
21664                        if (touchStartX > touchEndX) {
21665                            if(isScrollAllowed.m.right){
21666                                moveSlideRight(activeSection); //next
21667                            }
21668                        } else {
21669                            if(isScrollAllowed.m.left){
21670                                moveSlideLeft(activeSection); //prev
21671                            }
21672                        }
21673                    }
21674                }
21675
21676                //vertical scrolling (only when autoScrolling is enabled)
21677                else if(options.autoScrolling && canScroll){
21678
21679                    //is the movement greater than the minimum resistance to scroll?
21680                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
21681                        if (touchStartY > touchEndY) {
21682                            scrolling('down', scrollable);
21683                        } else if (touchEndY > touchStartY) {
21684                            scrolling('up', scrollable);
21685                        }
21686                    }
21687                }
21688            }
21689        }
21690
21691        /**
21692         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
21693         * Currently works well for iOS - Android might need some testing
21694         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
21695         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
21696         * @return {boolean} true if there is a match to options.normalScrollElements
21697         */
21698        function checkParentForNormalScrollElement (el, hop) {
21699            hop = hop || 0;
21700            var parent = $(el).parent();
21701
21702            if (hop < options.normalScrollElementTouchThreshold &&
21703                parent.is(options.normalScrollElements) ) {
21704                return true;
21705            } else if (hop == options.normalScrollElementTouchThreshold) {
21706                return false;
21707            } else {
21708                return checkParentForNormalScrollElement(parent, ++hop);
21709            }
21710        }
21711
21712        /**
21713        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
21714        * this way we make sure that is really a touch event what IE is detecting.
21715        */
21716        function isReallyTouch(e){
21717            //if is not IE   ||  IE is detecting `touch` or `pen`
21718            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
21719        }
21720
21721        /**
21722        * Handler for the touch start event.
21723        */
21724        function touchStartHandler(event){
21725            var e = event.originalEvent;
21726
21727            //stopping the auto scroll to adjust to a section
21728            if(options.fitToSection){
21729                $htmlBody.stop();
21730            }
21731
21732            if(isReallyTouch(e)){
21733                var touchEvents = getEventsPage(e);
21734                touchStartY = touchEvents.y;
21735                touchStartX = touchEvents.x;
21736            }
21737        }
21738
21739        /**
21740        * Gets the average of the last `number` elements of the given array.
21741        */
21742        function getAverage(elements, number){
21743            var sum = 0;
21744
21745            //taking `number` elements from the end to make the average, if there are not enought, 1
21746            var lastElements = elements.slice(Math.max(elements.length - number, 1));
21747
21748            for(var i = 0; i < lastElements.length; i++){
21749                sum = sum + lastElements[i];
21750            }
21751
21752            return Math.ceil(sum/number);
21753        }
21754
21755        /**
21756         * Detecting mousewheel scrolling
21757         *
21758         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
21759         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
21760         */
21761        var prevTime = new Date().getTime();
21762
21763        function MouseWheelHandler(e) {
21764            var curTime = new Date().getTime();
21765            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
21766
21767            //autoscrolling and not zooming?
21768            if(options.autoScrolling && !controlPressed && !isNormalScroll){
21769                // cross-browser wheel delta
21770                e = e || window.event;
21771                var value = e.wheelDelta || -e.deltaY || -e.detail;
21772                var delta = Math.max(-1, Math.min(1, value));
21773
21774                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
21775                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
21776
21777                //Limiting the array to 150 (lets not waste memory!)
21778                if(scrollings.length > 149){
21779                    scrollings.shift();
21780                }
21781
21782                //keeping record of the previous scrollings
21783                scrollings.push(Math.abs(value));
21784
21785                //preventing to scroll the site on mouse wheel when scrollbar is present
21786                if(options.scrollBar){
21787                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
21788                }
21789
21790                var activeSection = $(SECTION_ACTIVE_SEL);
21791                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
21792
21793                //time difference between the last scroll and the current one
21794                var timeDiff = curTime-prevTime;
21795                prevTime = curTime;
21796
21797                //haven't they scrolled in a while?
21798                //(enough to be consider a different scrolling action to scroll another section)
21799                if(timeDiff > 200){
21800                    //emptying the array, we dont care about old scrollings for our averages
21801                    scrollings = [];
21802                }
21803
21804                if(canScroll){
21805                    var averageEnd = getAverage(scrollings, 10);
21806                    var averageMiddle = getAverage(scrollings, 70);
21807                    var isAccelerating = averageEnd >= averageMiddle;
21808
21809                    //to avoid double swipes...
21810                    if(isAccelerating && isScrollingVertically){
21811                        //scrolling down?
21812                        if (delta < 0) {
21813                            scrolling('down', scrollable);
21814
21815                        //scrolling up?
21816                        }else {
21817                            scrolling('up', scrollable);
21818                        }
21819                    }
21820                }
21821
21822                return false;
21823            }
21824
21825            if(options.fitToSection){
21826                //stopping the auto scroll to adjust to a section
21827                $htmlBody.stop();
21828            }
21829        }
21830
21831        /**
21832        * Slides a slider to the given direction.
21833        * Optional `section` param.
21834        */
21835        function moveSlide(direction, section){
21836            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
21837            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
21838            var numSlides = slides.find(SLIDE_SEL).length;
21839
21840            // more than one slide needed and nothing should be sliding
21841            if (!slides.length || slideMoving || numSlides < 2) {
21842                return;
21843            }
21844
21845            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
21846            var destiny = null;
21847
21848            if(direction === 'left'){
21849                destiny = currentSlide.prev(SLIDE_SEL);
21850            }else{
21851                destiny = currentSlide.next(SLIDE_SEL);
21852            }
21853
21854            //isn't there a next slide in the secuence?
21855            if(!destiny.length){
21856                //respect loopHorizontal settin
21857                if (!options.loopHorizontal) return;
21858
21859                if(direction === 'left'){
21860                    destiny = currentSlide.siblings(':last');
21861                }else{
21862                    destiny = currentSlide.siblings(':first');
21863                }
21864            }
21865
21866            slideMoving = true;
21867
21868            landscapeScroll(slides, destiny, direction);
21869        }
21870
21871        /**
21872        * Maintains the active slides in the viewport
21873        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
21874        */
21875        function keepSlidesPosition(){
21876            $(SLIDE_ACTIVE_SEL).each(function(){
21877                silentLandscapeScroll($(this), 'internal');
21878            });
21879        }
21880
21881        var previousDestTop = 0;
21882        /**
21883        * Returns the destination Y position based on the scrolling direction and
21884        * the height of the section.
21885        */
21886        function getDestinationPosition(element){
21887            var elemPosition = element.position();
21888
21889            //top of the desination will be at the top of the viewport
21890            var position = elemPosition.top;
21891            var isScrollingDown =  elemPosition.top > previousDestTop;
21892            var sectionBottom = position - windowsHeight + element.outerHeight();
21893            var bigSectionsDestination = options.bigSectionsDestination;
21894
21895            //Uncode addition
21896            var containerH = container.outerHeight();
21897            var containerPosition = container.offset();
21898
21899            //########### Commented by Uncode - START ###########
21900            //is the destination element bigger than the viewport?
21901            // if(element.outerHeight() > windowsHeight){
21902            //     //scrolling up?
21903            //     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
21904            //         position = sectionBottom;
21905            //     }
21906            // }
21907
21908            // //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
21909            // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
21910            //     //The bottom of the destination will be at the bottom of the viewport
21911            //     position = sectionBottom;
21912            // }
21913            //########### Commented by Uncode - END ###########
21914
21915            //Uncode addition
21916            if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
21917                position += 18;
21918            if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
21919                position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
21920            }
21921
21922            /*
21923            Keeping record of the last scrolled position to determine the scrolling direction.
21924            No conventional methods can be used as the scroll bar might not be present
21925            AND the section might not be active if it is auto-height and didnt reach the middle
21926            of the viewport.
21927            */
21928            previousDestTop = position;
21929            return position;
21930        }
21931
21932        /**
21933        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
21934        */
21935        function scrollPage(element, callback, isMovementUp){
21936            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
21937
21938            var dtop = getDestinationPosition(element);
21939            var slideAnchorLink;
21940            var slideIndex;
21941
21942            //local variables
21943            var v = {
21944                element: element,
21945                callback: callback,
21946                isMovementUp: isMovementUp,
21947                dtop: dtop,
21948                yMovement: getYmovement(element),
21949                anchorLink: element.data('anchor'),
21950                sectionIndex: element.index(SECTION_SEL),
21951                activeSlide: element.find(SLIDE_ACTIVE_SEL),
21952                activeSection: $(SECTION_ACTIVE_SEL),
21953                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
21954
21955                //caching the value of isResizing at the momment the function is called
21956                //because it will be checked later inside a setTimeout and the value might change
21957                localIsResizing: isResizing
21958            };
21959
21960            //quiting when destination scroll is the same as the current one
21961            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
21962
21963            if(v.activeSlide.length){
21964                slideAnchorLink = v.activeSlide.data('anchor');
21965                slideIndex = v.activeSlide.index();
21966            }
21967
21968            // If continuousVertical && we need to wrap around
21969            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
21970                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
21971                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
21972
21973                v = createInfiniteSections(v);
21974            }
21975
21976            //callback (onLeave) if the site is not just resizing and readjusting the slides
21977            if($.isFunction(options.onLeave) && !v.localIsResizing){
21978                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
21979                    return;
21980                }
21981            }
21982
21983            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
21984            if(!v.localIsResizing){
21985                stopMedia(v.activeSection);
21986            }
21987
21988            options.scrollOverflowHandler.beforeLeave();
21989            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
21990            lazyLoad(element);
21991            options.scrollOverflowHandler.onLeave();
21992
21993
21994            //preventing from activating the MouseWheelHandler event
21995            //more than once if the page is scrolling
21996            canScroll = false;
21997
21998            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
21999
22000            performMovement(v);
22001
22002            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
22003            lastScrolledDestiny = v.anchorLink;
22004
22005            //avoid firing it twice (as it does also on scroll)
22006            activateMenuAndNav(v.anchorLink, v.sectionIndex);
22007        }
22008
22009        /**
22010        * Performs the vertical movement (by CSS3 or by jQuery)
22011        */
22012        function performMovement(v){
22013            // using CSS3 translate functionality
22014            if (options.css3 && options.autoScrolling && !options.scrollBar) {
22015
22016                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
22017                // that's why we round it to 0.
22018                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
22019                transformContainer(translate3d, true);
22020
22021                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
22022                //scrollingSpeed to change in case of using silentMoveTo();
22023                if(options.scrollingSpeed){
22024                    clearTimeout(afterSectionLoadsId);
22025                    afterSectionLoadsId = setTimeout(function () {
22026                        afterSectionLoads(v);
22027                    }, options.scrollingSpeed);
22028                }else{
22029                    afterSectionLoads(v);
22030                }
22031            }
22032
22033            // using jQuery animate
22034            else{
22035                var scrollSettings = getScrollSettings(v);
22036
22037                $(scrollSettings.element).animate(
22038                    scrollSettings.options,
22039                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
22040                    if(options.scrollBar){
22041
22042                        /* Hack!
22043                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
22044                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
22045
22046                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
22047                        */
22048                        setTimeout(function(){
22049                            afterSectionLoads(v);
22050                        },30);
22051                    }else{
22052                        afterSectionLoads(v);
22053                    }
22054                });
22055            }
22056        }
22057
22058        /**
22059        * Gets the scrolling settings depending on the plugin autoScrolling option
22060        */
22061        function getScrollSettings(v){
22062            var scroll = {};
22063
22064            if(options.autoScrolling && !options.scrollBar){
22065                scroll.options = { 'top': -v.dtop};
22066                scroll.element = WRAPPER_SEL;
22067            }else{
22068                scroll.options = { 'scrollTop': v.dtop};
22069                scroll.element = 'html, body';
22070            }
22071
22072            return scroll;
22073        }
22074
22075        /**
22076        * Adds sections before or after the current one to create the infinite effect.
22077        */
22078        function createInfiniteSections(v){
22079            // Scrolling down
22080            if (!v.isMovementUp) {
22081                // Move all previous sections to after the active section
22082                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
22083            }
22084            else { // Scrolling up
22085                // Move all next sections to before the active section
22086                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
22087            }
22088
22089            // Maintain the displayed position (now that we changed the element order)
22090            silentScroll($(SECTION_ACTIVE_SEL).position().top);
22091
22092            // Maintain the active slides visible in the viewport
22093            keepSlidesPosition();
22094
22095            // save for later the elements that still need to be reordered
22096            v.wrapAroundElements = v.activeSection;
22097
22098            // Recalculate animation variables
22099            v.dtop = v.element.position().top;
22100            v.yMovement = getYmovement(v.element);
22101
22102            return v;
22103        }
22104
22105        /**
22106        * Fix section order after continuousVertical changes have been animated
22107        */
22108        function continuousVerticalFixSectionOrder (v) {
22109            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
22110            // finish moving the elements around so the direct navigation will function more simply
22111            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
22112                return;
22113            }
22114
22115            if (v.isMovementUp) {
22116                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
22117            }
22118            else {
22119                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
22120            }
22121
22122            silentScroll($(SECTION_ACTIVE_SEL).position().top);
22123
22124            // Maintain the active slides visible in the viewport
22125            keepSlidesPosition();
22126        }
22127
22128
22129        /**
22130        * Actions to do once the section is loaded.
22131        */
22132        function afterSectionLoads (v){
22133            continuousVerticalFixSectionOrder(v);
22134
22135            //callback (afterLoad) if the site is not just resizing and readjusting the slides
22136            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
22137            options.scrollOverflowHandler.afterLoad();
22138
22139            if(!v.localIsResizing){
22140                playMedia(v.element);
22141            }
22142
22143            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
22144
22145            canScroll = true;
22146
22147            $.isFunction(v.callback) && v.callback.call(this);
22148        }
22149
22150        /**
22151        * Sets the value for the given attribute from the `data-` attribute with the same suffix
22152        * ie: data-srcset ==> srcset  |  data-src ==> src
22153        */
22154        function setSrc(element, attribute){
22155            element
22156                .attr(attribute, element.data(attribute))
22157                .removeAttr('data-' + attribute);
22158        }
22159
22160        /**
22161        * Lazy loads image, video and audio elements.
22162        */
22163        function lazyLoad(destiny){
22164            if (!options.lazyLoading){
22165                return;
22166            }
22167
22168            var panel = getSlideOrSection(destiny);
22169            var element;
22170
22171            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
22172                element = $(this);
22173
22174                $.each(['src', 'srcset'], function(index, type){
22175                    var attribute = element.attr('data-' + type);
22176                    if(typeof attribute !== 'undefined' && attribute){
22177                        setSrc(element, type);
22178                    }
22179                });
22180
22181                if(element.is('source')){
22182                    element.closest('video').get(0).load();
22183                }
22184            });
22185        }
22186
22187        /**
22188        * Plays video and audio elements.
22189        */
22190        function playMedia(destiny){
22191            var panel = getSlideOrSection(destiny);
22192
22193            //playing HTML5 media elements
22194            panel.find('video, audio').each(function(){
22195                var element = $(this).get(0);
22196
22197                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
22198                    element.play();
22199                }
22200            });
22201
22202            //youtube videos
22203            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
22204                var element = $(this).get(0);
22205
22206                if ( element.hasAttribute('data-autoplay') ){
22207                    playYoutube(element);
22208                }
22209
22210                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
22211                element.onload = function() {
22212                    if ( element.hasAttribute('data-autoplay') ){
22213                        playYoutube(element);
22214                    }
22215                };
22216            });
22217        }
22218
22219        /**
22220        * Plays a youtube video
22221        */
22222        function playYoutube(element){
22223            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
22224        }
22225
22226        /**
22227        * Stops video and audio elements.
22228        */
22229        function stopMedia(destiny){
22230            var panel = getSlideOrSection(destiny);
22231
22232            //stopping HTML5 media elements
22233            panel.find('video, audio').each(function(){
22234                var element = $(this).get(0);
22235
22236                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
22237                    element.pause();
22238                }
22239            });
22240
22241            //youtube videos
22242            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
22243                var element = $(this).get(0);
22244
22245                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
22246                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
22247                }
22248            });
22249        }
22250
22251        /**
22252        * Gets the active slide (or section) for the given section
22253        */
22254        function getSlideOrSection(destiny){
22255            var slide = destiny.find(SLIDE_ACTIVE_SEL);
22256            if( slide.length ) {
22257                destiny = $(slide);
22258            }
22259
22260            return destiny;
22261        }
22262
22263        /**
22264        * Scrolls to the anchor in the URL when loading the site
22265        */
22266        function scrollToAnchor(){
22267            //getting the anchor link in the URL and deleting the `#`
22268            var value =  window.location.hash.replace('#', '').split('/');
22269            var sectionAnchor = decodeURIComponent(value[0]);
22270            var slideAnchor = decodeURIComponent(value[1]);
22271
22272            if(sectionAnchor){  //if theres any #
22273                if(options.animateAnchor){
22274                    scrollPageAndSlide(sectionAnchor, slideAnchor);
22275                }else{
22276                    silentMoveTo(sectionAnchor, slideAnchor);
22277                }
22278            }
22279        }
22280
22281        /**
22282        * Detecting any change on the URL to scroll to the given anchor link
22283        * (a way to detect back history button as we play with the hashes on the URL)
22284        */
22285        function hashChangeHandler(){
22286            if(!isScrolling && !options.lockAnchors){
22287                var value =  window.location.hash.replace('#', '').split('/');
22288                var sectionAnchor = decodeURIComponent(value[0]);
22289                var slideAnchor = decodeURIComponent(value[1]);
22290
22291                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
22292                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
22293                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
22294
22295
22296                if(sectionAnchor.length){
22297                    /*in order to call scrollpage() only once for each destination at a time
22298                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
22299                    event is fired on every scroll too.*/
22300                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
22301                        scrollPageAndSlide(sectionAnchor, slideAnchor);
22302                    }
22303                }
22304            }
22305        }
22306
22307        //Sliding with arrow keys, both, vertical and horizontal
22308        function keydownHandler(e) {
22309
22310            clearTimeout(keydownId);
22311
22312            var activeElement = $(':focus');
22313
22314            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
22315                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
22316                options.keyboardScrolling && options.autoScrolling){
22317                var keyCode = e.which;
22318
22319                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
22320                var keyControls = [40, 38, 32, 33, 34];
22321                if($.inArray(keyCode, keyControls) > -1){
22322                    e.preventDefault();
22323                }
22324
22325                controlPressed = e.ctrlKey;
22326
22327                keydownId = setTimeout(function(){
22328                    onkeydown(e);
22329                },150);
22330            }
22331        }
22332
22333        function tooltipTextHandler(){
22334            $(this).prev().trigger('click');
22335        }
22336
22337        //to prevent scrolling while zooming
22338        function keyUpHandler(e){
22339            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
22340                controlPressed = e.ctrlKey;
22341            }
22342        }
22343
22344        //binding the mousemove when the mouse's middle button is released
22345        function mouseDownHandler(e){
22346            //middle button
22347            if (e.which == 2){
22348                oldPageY = e.pageY;
22349                container.on('mousemove', mouseMoveHandler);
22350            }
22351        }
22352
22353        //unbinding the mousemove when the mouse's middle button is released
22354        function mouseUpHandler(e){
22355            //middle button
22356            if (e.which == 2){
22357                container.off('mousemove');
22358            }
22359        }
22360
22361        //Scrolling horizontally when clicking on the slider controls.
22362        function slideArrowHandler(){
22363            var section = $(this).closest(SECTION_SEL);
22364
22365            if ($(this).hasClass(SLIDES_PREV)) {
22366                if(isScrollAllowed.m.left){
22367                    moveSlideLeft(section);
22368                }
22369            } else {
22370                if(isScrollAllowed.m.right){
22371                    moveSlideRight(section);
22372                }
22373            }
22374        }
22375
22376        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
22377        function blurHandler(){
22378            isWindowFocused = false;
22379            controlPressed = false;
22380        }
22381
22382        //Scrolls to the section when clicking the navigation bullet
22383        function sectionBulletHandler(e){
22384            e.preventDefault();
22385            var index = $(this).parent().index();
22386            scrollPage($(SECTION_SEL).eq(index));
22387        }
22388
22389        //Scrolls the slider to the given slide destination for the given section
22390        function slideBulletHandler(e){
22391            e.preventDefault();
22392            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
22393            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
22394
22395            landscapeScroll(slides, destiny);
22396        }
22397
22398        /**
22399        * Keydown event
22400        */
22401        function onkeydown(e){
22402            var shiftPressed = e.shiftKey;
22403
22404            //do nothing if we can not scroll or we are not using horizotnal key arrows.
22405            if(!canScroll && [37,39].indexOf(e.which) < 0){
22406                return;
22407            }
22408
22409            switch (e.which) {
22410                //up
22411                case 38:
22412                case 33:
22413                    if(isScrollAllowed.k.up){
22414                        moveSectionUp();
22415                    }
22416                    break;
22417
22418                //down
22419                case 32: //spacebar
22420                    if(shiftPressed && isScrollAllowed.k.up){
22421                        moveSectionUp();
22422                        break;
22423                    }
22424                /* falls through */
22425                case 40:
22426                case 34:
22427                    if(isScrollAllowed.k.down){
22428                        moveSectionDown();
22429                    }
22430                    break;
22431
22432                //Home
22433                case 36:
22434                    if(isScrollAllowed.k.up){
22435                        moveTo(1);
22436                    }
22437                    break;
22438
22439                //End
22440                case 35:
22441                     if(isScrollAllowed.k.down){
22442                        moveTo( $(SECTION_SEL).length );
22443                    }
22444                    break;
22445
22446                //left
22447                case 37:
22448                    if(isScrollAllowed.k.left){
22449                        moveSlideLeft();
22450                    }
22451                    break;
22452
22453                //right
22454                case 39:
22455                    if(isScrollAllowed.k.right){
22456                        moveSlideRight();
22457                    }
22458                    break;
22459
22460                default:
22461                    return; // exit this handler for other keys
22462            }
22463        }
22464
22465        /**
22466        * Detecting the direction of the mouse movement.
22467        * Used only for the middle button of the mouse.
22468        */
22469        var oldPageY = 0;
22470        function mouseMoveHandler(e){
22471            if(canScroll){
22472                // moving up
22473                if (e.pageY < oldPageY && isScrollAllowed.m.up){
22474                    moveSectionUp();
22475                }
22476
22477                // moving down
22478                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
22479                    moveSectionDown();
22480                }
22481            }
22482            oldPageY = e.pageY;
22483        }
22484
22485        /**
22486        * Scrolls horizontal sliders.
22487        */
22488        function landscapeScroll(slides, destiny, direction){
22489            var section = slides.closest(SECTION_SEL);
22490            var v = {
22491                slides: slides,
22492                destiny: destiny,
22493                direction: direction,
22494                destinyPos: destiny.position(),
22495                slideIndex: destiny.index(),
22496                section: section,
22497                sectionIndex: section.index(SECTION_SEL),
22498                anchorLink: section.data('anchor'),
22499                slidesNav: section.find(SLIDES_NAV_SEL),
22500                slideAnchor:  getAnchor(destiny),
22501                prevSlide: section.find(SLIDE_ACTIVE_SEL),
22502                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
22503
22504                //caching the value of isResizing at the momment the function is called
22505                //because it will be checked later inside a setTimeout and the value might change
22506                localIsResizing: isResizing
22507            };
22508            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
22509            v.direction = v.direction ? v.direction : v.xMovement;
22510
22511            //important!! Only do it when not resizing
22512            if(!v.localIsResizing){
22513                //preventing from scrolling to the next/prev section when using scrollHorizontally
22514                canScroll = false;
22515            }
22516
22517            if(options.onSlideLeave){
22518
22519                //if the site is not just resizing and readjusting the slides
22520                if(!v.localIsResizing && v.xMovement!=='none'){
22521                    if($.isFunction( options.onSlideLeave )){
22522                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
22523                            slideMoving = false;
22524                            return;
22525                        }
22526                    }
22527                }
22528            }
22529
22530            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
22531
22532            if(!v.localIsResizing){
22533                stopMedia(v.prevSlide);
22534                lazyLoad(destiny);
22535            }
22536
22537            if(!options.loopHorizontal && options.controlArrows){
22538                //hidding it for the fist slide, showing for the rest
22539                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
22540
22541                //hidding it for the last slide, showing for the rest
22542                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
22543            }
22544
22545            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
22546            if(section.hasClass(ACTIVE) && !v.localIsResizing){
22547                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
22548            }
22549
22550            performHorizontalMove(slides, v, true);
22551        }
22552
22553
22554        function afterSlideLoads(v){
22555            activeSlidesNavigation(v.slidesNav, v.slideIndex);
22556
22557            //if the site is not just resizing and readjusting the slides
22558            if(!v.localIsResizing){
22559                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
22560
22561                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
22562                //and to prevent double scroll right after a windows resize
22563                canScroll = true;
22564
22565                playMedia(v.destiny);
22566            }
22567
22568            //letting them slide again
22569            slideMoving = false;
22570        }
22571
22572        /**
22573        * Performs the horizontal movement. (CSS3 or jQuery)
22574        *
22575        * @param fireCallback {Bool} - determines whether or not to fire the callback
22576        */
22577        function performHorizontalMove(slides, v, fireCallback){
22578            var destinyPos = v.destinyPos;
22579
22580            if(options.css3){
22581                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
22582
22583                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
22584
22585                afterSlideLoadsId = setTimeout(function(){
22586                    fireCallback && afterSlideLoads(v);
22587                }, options.scrollingSpeed, options.easing);
22588            }else{
22589                slides.animate({
22590                    scrollLeft : Math.round(destinyPos.left)
22591                }, options.scrollingSpeed, options.easing, function() {
22592
22593                    fireCallback && afterSlideLoads(v);
22594                });
22595            }
22596        }
22597
22598        /**
22599        * Sets the state for the horizontal bullet navigations.
22600        */
22601        function activeSlidesNavigation(slidesNav, slideIndex){
22602            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
22603            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
22604        }
22605
22606        var previousHeight = windowsHeight;
22607
22608        //when resizing the site, we adjust the heights of the sections, slimScroll...
22609        function resizeHandler(){
22610            //checking if it needs to get responsive
22611            responsive();
22612
22613            // rebuild immediately on touch devices
22614            if (isTouchDevice) {
22615                var activeElement = $(document.activeElement);
22616
22617                //if the keyboard is NOT visible
22618                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
22619                    var currentHeight = $window.height();
22620
22621                    //making sure the change in the viewport size is enough to force a rebuild. (20 % of the window to avoid problems when hidding scroll bars)
22622                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
22623                        reBuild(true);
22624                        previousHeight = currentHeight;
22625                    }
22626                }
22627            }else{
22628                //in order to call the functions only when the resize is finished
22629                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
22630                clearTimeout(resizeId);
22631
22632                resizeId = setTimeout(function(){
22633                    reBuild(true);
22634                }, 350);
22635            }
22636        }
22637
22638        /**
22639        * Checks if the site needs to get responsive and disables autoScrolling if so.
22640        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
22641        */
22642        function responsive(){
22643            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
22644            var heightLimit = options.responsiveHeight;
22645
22646            //only calculating what we need. Remember its called on the resize event.
22647            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
22648            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
22649
22650            if(widthLimit && heightLimit){
22651                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
22652            }
22653            else if(widthLimit){
22654                setResponsive(isBreakingPointWidth);
22655            }
22656            else if(heightLimit){
22657                setResponsive(isBreakingPointHeight);
22658            }
22659        }
22660
22661        /**
22662        * Adds transition animations for the given element
22663        */
22664        function addAnimation(container, element){
22665            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
22666
22667            container.removeClass(NO_TRANSITION);
22668            return container.css({
22669                '-webkit-transition': transition,
22670                'transition': transition
22671            });
22672        }
22673
22674        /**
22675        * Remove transition animations for the given element
22676        */
22677        function removeAnimation(element){
22678            return element.addClass(NO_TRANSITION);
22679        }
22680
22681        /**
22682        * Activating the vertical navigation bullets according to the given slide name.
22683        */
22684        function activateNavDots(name, sectionIndex){
22685            if(options.navigation){
22686                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
22687                if(name){
22688                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
22689                }else{
22690                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
22691                }
22692            }
22693        }
22694
22695        /**
22696        * Activating the website main menu elements according to the given slide name.
22697        */
22698        function activateMenuElement(name){
22699            if(options.menu){
22700                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
22701                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
22702            }
22703        }
22704
22705        /**
22706        * Sets to active the current menu and vertical nav items.
22707        */
22708        function activateMenuAndNav(anchor, index){
22709            activateMenuElement(anchor);
22710            activateNavDots(anchor, index);
22711        }
22712
22713        /**
22714        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
22715        * from the current section.
22716        */
22717        function getYmovement(destiny){
22718            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
22719            var toIndex = destiny.index(SECTION_SEL);
22720            if( fromIndex == toIndex){
22721                return 'none';
22722            }
22723            if(fromIndex > toIndex){
22724                return 'up';
22725            }
22726            return 'down';
22727        }
22728
22729        /**
22730        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
22731        * from the current slide.
22732        */
22733        function getXmovement(fromIndex, toIndex){
22734            if( fromIndex == toIndex){
22735                return 'none';
22736            }
22737            if(fromIndex > toIndex){
22738                return 'left';
22739            }
22740            return 'right';
22741        }
22742
22743        /**
22744        * Checks if the element needs scrollbar and if the user wants to apply it.
22745        * If so it creates it.
22746        *
22747        * @param {Object} element   jQuery object of the section or slide
22748        */
22749        function createScrollBar(element){
22750            //User doesn't want scrollbar here? Sayonara baby!
22751            if(element.hasClass('fp-noscroll')) return;
22752
22753            //needed to make `scrollHeight` work under Opera 12
22754            element.css('overflow', 'hidden');
22755
22756            var scrollOverflowHandler = options.scrollOverflowHandler;
22757            var wrap = scrollOverflowHandler.wrapContent();
22758            //in case element is a slide
22759            var section = element.closest(SECTION_SEL);
22760            var scrollable = scrollOverflowHandler.scrollable(element);
22761            var contentHeight;
22762
22763            //if there was scroll, the contentHeight will be the one in the scrollable section
22764            if(scrollable.length){
22765                contentHeight = scrollOverflowHandler.scrollHeight(element);
22766            }else{
22767                contentHeight = element.get(0).scrollHeight;
22768                if(options.verticalCentered){
22769                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
22770                }
22771            }
22772
22773            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
22774
22775            //needs scroll?
22776            if ( contentHeight > scrollHeight) {
22777                //did we already have an scrollbar ? Updating it
22778                if(scrollable.length){
22779                    scrollOverflowHandler.update(element, scrollHeight);
22780                }
22781                //creating the scrolling
22782                else{
22783                    if(options.verticalCentered){
22784                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
22785                    }else{
22786                        element.wrapInner(wrap);
22787                    }
22788                    scrollOverflowHandler.create(element, scrollHeight);
22789                }
22790            }
22791            //removing the scrolling when it is not necessary anymore
22792            else{
22793                scrollOverflowHandler.remove(element);
22794            }
22795
22796            //undo
22797            element.css('overflow', '');
22798        }
22799
22800        function addTableClass(element){
22801            //In case we are styling for the 2nd time as in with reponsiveSlides
22802            if(!element.hasClass(TABLE)){
22803                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
22804            }
22805        }
22806
22807        function getTableHeight(element){
22808            var sectionHeight = windowsHeight;
22809
22810            if(options.paddingTop || options.paddingBottom){
22811                var section = element;
22812                if(!section.hasClass(SECTION)){
22813                    section = element.closest(SECTION_SEL);
22814                }
22815
22816                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
22817                sectionHeight = (windowsHeight - paddings);
22818            }
22819
22820            return sectionHeight;
22821        }
22822
22823        /**
22824        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
22825        */
22826        function transformContainer(translate3d, animated){
22827            if(animated){
22828                addAnimation(container);
22829            }else{
22830                removeAnimation(container);
22831            }
22832
22833            container.css(getTransforms(translate3d));
22834
22835            //syncronously removing the class after the animation has been applied.
22836            setTimeout(function(){
22837                container.removeClass(NO_TRANSITION);
22838            },10);
22839        }
22840
22841        /**
22842        * Gets a section by its anchor / index
22843        */
22844        function getSectionByAnchor(sectionAnchor){
22845            if(!sectionAnchor) return [];
22846
22847            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
22848            if(!section.length){
22849                section = $(SECTION_SEL).eq( sectionAnchor -1);
22850            }
22851
22852            return section;
22853        }
22854
22855        /**
22856        * Gets a slide inside a given section by its anchor / index
22857        */
22858        function getSlideByAnchor(slideAnchor, section){
22859            var slides = section.find(SLIDES_WRAPPER_SEL);
22860            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
22861
22862            if(!slide.length){
22863                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
22864            }
22865
22866            return slide;
22867        }
22868
22869        /**
22870        * Scrolls to the given section and slide anchors
22871        */
22872        function scrollPageAndSlide(destiny, slide){
22873            var section = getSectionByAnchor(destiny);
22874
22875            //do nothing if there's no section with the given anchor name
22876            if(!section.length) return;
22877
22878            //default slide
22879            if (typeof slide === 'undefined') {
22880                slide = 0;
22881            }
22882
22883            //we need to scroll to the section and then to the slide
22884            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
22885                scrollPage(section, function(){
22886                    scrollSlider(section, slide);
22887                });
22888            }
22889            //if we were already in the section
22890            else{
22891                scrollSlider(section, slide);
22892            }
22893        }
22894
22895        /**
22896        * Scrolls the slider to the given slide destination for the given section
22897        */
22898        function scrollSlider(section, slideAnchor){
22899            if(typeof slideAnchor !== 'undefined'){
22900                var slides = section.find(SLIDES_WRAPPER_SEL);
22901                var destiny =  getSlideByAnchor(slideAnchor, section);
22902
22903                if(destiny.length){
22904                    landscapeScroll(slides, destiny);
22905                }
22906            }
22907        }
22908
22909        /**
22910        * Creates a landscape navigation bar with dots for horizontal sliders.
22911        */
22912        function addSlidesNavigation(section, numSlides){
22913            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
22914            var nav = section.find(SLIDES_NAV_SEL);
22915
22916            //top or bottom
22917            nav.addClass(options.slidesNavPosition);
22918
22919            for(var i=0; i< numSlides; i++){
22920                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
22921            }
22922
22923            //centering it
22924            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
22925
22926            nav.find('li').first().find('a').addClass(ACTIVE);
22927        }
22928
22929
22930        /**
22931        * Sets the state of the website depending on the active section/slide.
22932        * It changes the URL hash when needed and updates the body class.
22933        */
22934        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
22935            var sectionHash = '';
22936
22937            if(options.anchors.length && !options.lockAnchors){
22938
22939                //isn't it the first slide?
22940                if(slideIndex){
22941                    if(typeof anchorLink !== 'undefined'){
22942                        sectionHash = anchorLink;
22943                    }
22944
22945                    //slide without anchor link? We take the index instead.
22946                    if(typeof slideAnchor === 'undefined'){
22947                        slideAnchor = slideIndex;
22948                    }
22949
22950                    lastScrolledSlide = slideAnchor;
22951                    setUrlHash(sectionHash + '/' + slideAnchor);
22952
22953                //first slide won't have slide anchor, just the section one
22954                }else if(typeof slideIndex !== 'undefined'){
22955                    lastScrolledSlide = slideAnchor;
22956                    setUrlHash(anchorLink);
22957                }
22958
22959                //section without slides
22960                else{
22961                    setUrlHash(anchorLink);
22962                }
22963            }
22964
22965            setBodyClass();
22966        }
22967
22968        /**
22969        * Sets the URL hash.
22970        */
22971        function setUrlHash(url){
22972            //Uncode addition
22973            if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
22974                return false;
22975
22976            if(options.recordHistory){
22977                location.hash = url;
22978            }else{
22979                //Uncode addition
22980                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
22981                // if(isTouchDevice || isTouch){
22982                //     window.history.replaceState(undefined, undefined, '#' + url);
22983                // }else{
22984                //     var baseUrl = window.location.href.split('#')[0];
22985                //     window.location.replace( baseUrl + '#' + url );
22986                // }
22987                return false;
22988            }
22989        }
22990
22991        /**
22992        * Gets the anchor for the given slide / section. Its index will be used if there's none.
22993        */
22994        function getAnchor(element){
22995            var anchor = element.data('anchor');
22996            var index = element.index();
22997
22998            //Slide without anchor link? We take the index instead.
22999            if(typeof anchor === 'undefined'){
23000                anchor = index;
23001            }
23002
23003            return anchor;
23004        }
23005
23006        /**
23007        * Sets a class for the body of the page depending on the active section / slide
23008        */
23009        function setBodyClass(){
23010            var section = $(SECTION_ACTIVE_SEL);
23011            var slide = section.find(SLIDE_ACTIVE_SEL);
23012
23013            var sectionAnchor = getAnchor(section);
23014            var slideAnchor = getAnchor(slide);
23015
23016            var text = String(sectionAnchor);
23017
23018            if(slide.length){
23019                text = text + '-' + slideAnchor;
23020            }
23021
23022            //changing slash for dash to make it a valid CSS style
23023            text = text.replace('/', '-').replace('#','');
23024
23025            //removing previous anchor classes
23026            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
23027            $body[0].className = $body[0].className.replace(classRe, '');
23028
23029            //adding the current anchor
23030            $body.addClass(VIEWING_PREFIX + '-' + text);
23031        }
23032
23033        /**
23034        * Checks for translate3d support
23035        * @return boolean
23036        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
23037        */
23038        function support3d() {
23039            var el = document.createElement('p'),
23040                has3d,
23041                transforms = {
23042                    'webkitTransform':'-webkit-transform',
23043                    'OTransform':'-o-transform',
23044                    'msTransform':'-ms-transform',
23045                    'MozTransform':'-moz-transform',
23046                    'transform':'transform'
23047                };
23048
23049            // Add it to the body to get the computed style.
23050            document.body.insertBefore(el, null);
23051
23052            for (var t in transforms) {
23053                if (el.style[t] !== undefined) {
23054                    el.style[t] = 'translate3d(1px,1px,1px)';
23055                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
23056                }
23057            }
23058
23059            document.body.removeChild(el);
23060
23061            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
23062        }
23063
23064        /**
23065        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
23066        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
23067        */
23068        function removeMouseWheelHandler(){
23069            if (document.addEventListener) {
23070                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
23071                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
23072                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
23073            } else {
23074                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
23075            }
23076        }
23077
23078        /**
23079        * Adds the auto scrolling action for the mouse wheel and trackpad.
23080        * After this function is called, the mousewheel and trackpad movements will scroll through sections
23081        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
23082        */
23083        function addMouseWheelHandler(){
23084            var prefix = '';
23085            var _addEventListener;
23086
23087            if (window.addEventListener){
23088                _addEventListener = "addEventListener";
23089            }else{
23090                _addEventListener = "attachEvent";
23091                prefix = 'on';
23092            }
23093
23094             // detect available wheel event
23095            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
23096                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
23097                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
23098            var passiveEvent = g_supportsPassive ? {passive: false }
23098: false;
23099
23100
23101            if(support == 'DOMMouseScroll'){
23102                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent);
23103            }
23104
23105            //handle MozMousePixelScroll in older Firefox
23106            else{
23107                document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent);
23108            }
23109        }
23110
23111        /**
23112        * Binding the mousemove when the mouse's middle button is pressed
23113        */
23114        function addMiddleWheelHandler(){
23115            container
23116                .on('mousedown', mouseDownHandler)
23117                .on('mouseup', mouseUpHandler);
23118        }
23119
23120        /**
23121        * Unbinding the mousemove when the mouse's middle button is released
23122        */
23123        function removeMiddleWheelHandler(){
23124            container
23125                .off('mousedown', mouseDownHandler)
23126                .off('mouseup', mouseUpHandler);
23127        }
23128
23129        /**
23130        * Adds the possibility to auto scroll through sections on touch devices.
23131        */
23132        function addTouchHandler(){
23133            if(isTouchDevice || isTouch){
23134                if(options.autoScrolling){
23135                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
23136                }
23137
23138                $(WRAPPER_SEL)
23139                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
23140                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
23141            }
23142        }
23143
23144        /**
23145        * Removes the auto scrolling for touch devices.
23146        */
23147        function removeTouchHandler(){
23148            if(isTouchDevice || isTouch){
23149                $(WRAPPER_SEL)
23150                    .off(events.touchstart)
23151                    .off(events.touchmove);
23152            }
23153        }
23154
23155        /*
23156        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
23157        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
23158        */
23159        function getMSPointer(){
23160            var pointer;
23161
23162            //IE >= 11 & rest of browsers
23163            if(window.PointerEvent){
23164                pointer = { down: 'pointerdown', move: 'pointermove'};
23165            }
23166
23167            //IE < 11
23168            else{
23169                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
23170            }
23171
23172            return pointer;
23173        }
23174
23175        /**
23176        * Gets the pageX and pageY properties depending on the browser.
23177        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
23178        */
23179        function getEventsPage(e){
23180            var events = [];
23181
23182            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
23183            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
23184
23185            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
23186            if(isTouch && isReallyTouch(e) && options.scrollBar){
23187                events.y = e.touches[0].pageY;
23188                events.x = e.touches[0].pageX;
23189            }
23190
23191            return events;
23192        }
23193
23194        /**
23195        * Slides silently (with no animation) the active slider to the given slide.
23196        * @param noCallback {bool} true or defined -> no callbacks
23197        */
23198        function silentLandscapeScroll(activeSlide, noCallbacks){
23199            setScrollingSpeed (0, 'internal');
23200
23201            if(typeof noCallbacks !== 'undefined'){
23202                //preventing firing callbacks afterSlideLoad etc.
23203                isResizing = true;
23204            }
23205
23206            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
23207
23208            if(typeof noCallbacks !== 'undefined'){
23209                isResizing = false;
23210            }
23211
23212            setScrollingSpeed(originals.scrollingSpeed, 'internal');
23213        }
23214
23215        /**
23216        * Scrolls silently (with no animation) the page to the given Y position.
23217        */
23218        function silentScroll(top){
23219            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
23220            // that's why we round it to 0.
23221            var roundedTop = Math.round(top);
23222
23223            if (options.css3 && options.autoScrolling && !options.scrollBar){
23224                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
23225                transformContainer(translate3d, false);
23226            }
23227            else if(options.autoScrolling && !options.scrollBar){
23228                container.css('top', -roundedTop);
23229            }
23230            else{
23231                $htmlBody.scrollTop(roundedTop);
23232            }
23233        }
23234
23235        /**
23236        * Returns the cross-browser transform string.
23237        */
23238        function getTransforms(translate3d){
23239            return {
23240                '-webkit-transform': translate3d,
23241                '-moz-transform': translate3d,
23242                '-ms-transform':translate3d,
23243                'transform': translate3d
23244            };
23245        }
23246
23247        /**
23248        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
23249        * @type  m (mouse) or k (keyboard)
23250        */
23251        function setIsScrollAllowed(value, direction, type){
23252            switch (direction){
23253                case 'up': isScrollAllowed[type].up = value; break;
23254                case 'down': isScrollAllowed[type].down = value; break;
23255                case 'left': isScrollAllowed[type].left = value; break;
23256                case 'right': isScrollAllowed[type].right = value; break;
23257                case 'all':
23258                    if(type == 'm'){
23259                        setAllowScrolling(value);
23260                    }else{
23261                        setKeyboardScrolling(value);
23262                    }
23263            }
23264        }
23265
23266        /*
23267        * Destroys fullpage.js plugin events and optinally its html markup and styles
23268        */
23269        function destroy(all){
23270            setAutoScrolling(false, 'internal');
23271            setAllowScrolling(false);
23272            setKeyboardScrolling(false);
23273            container.addClass(DESTROYED);
23274
23275            clearTimeout(afterSlideLoadsId);
23276            clearTimeout(afterSectionLoadsId);
23277            clearTimeout(resizeId);
23278            clearTimeout(scrollId);
23279            clearTimeout(scrollId2);
23280
23281            $window
23282                .off('scroll', scrollHandler)
23283                .off('hashchange', hashChangeHandler)
23284                .off('resize', resizeHandler);
23285
23286            $document
23287                .off('click touchstart', SECTION_NAV_SEL + ' a')
23288                .off('mouseenter', SECTION_NAV_SEL + ' li')
23289                .off('mouseleave', SECTION_NAV_SEL + ' li')
23290                .off('click touchstart', SLIDES_NAV_LINK_SEL)
23291                .off('mouseover', options.normalScrollElements)
23292                .off('mouseout', options.normalScrollElements);
23293
23294            $(SECTION_SEL)
23295                .off('click touchstart', SLIDES_ARROW_SEL);
23296
23297            clearTimeout(afterSlideLoadsId);
23298            clearTimeout(afterSectionLoadsId);
23299
23300            //lets make a mess!
23301            if(all){
23302                destroyStructure();
23303            }
23304        }
23305
23306        /*
23307        * Removes inline styles added by fullpage.js
23308        */
23309        function destroyStructure(){
23310            //reseting the `top` or `translate` properties to 0
23311            silentScroll(0);
23312
23313            //loading all the lazy load content
23314            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
23315                setSrc($(this), 'src');
23316            });
23317
23318            container.find('img[data-srcset]').each(function(){
23319                setSrc($(this), 'srcset');
23320            });
23321
23322            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
23323
23324            //removing inline styles
23325            $(SECTION_SEL).css( {
23326                'height': '',
23327                'background-color' : '',
23328                'padding': ''
23329            });
23330
23331            $(SLIDE_SEL).css( {
23332                'width': ''
23333            });
23334
23335            container.css({
23336                'height': '',
23337                'position': '',
23338                '-ms-touch-action': '',
23339                'touch-action': ''
23340            });
23341
23342            $htmlBody.css({
23343                'overflow': '',
23344                'height': ''
23345            });
23346
23347            // remove .fp-enabled class
23348            $('html').removeClass(ENABLED);
23349
23350            // remove .fp-responsive class
23351            $body.removeClass(RESPONSIVE);
23352
23353            // remove all of the .fp-viewing- classes
23354            $.each($body.get(0).className.split(/\s+/), function (index, className) {
23355                if (className.indexOf(VIEWING_PREFIX) === 0) {
23356                    $body.removeClass(className);
23357                }
23358            });
23359
23360            //removing added classes
23361            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
23362                options.scrollOverflowHandler.remove($(this));
23363                $(this).removeClass(TABLE + ' ' + ACTIVE);
23364            });
23365
23366            removeAnimation(container);
23367
23368            //Unwrapping content
23369            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
23370                //unwrap not being use in case there's no child element inside and its just text
23371                $(this).replaceWith(this.childNodes);
23372            });
23373
23374            //removing the applied transition from the fullpage wrapper
23375            container.css({
23376                '-webkit-transition': 'none',
23377                'transition': 'none'
23378            });
23379
23380            //scrolling the page to the top with no animation
23381            $htmlBody.scrollTop(0);
23382
23383            //removing selectors
23384            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
23385            $.each(usedSelectors, function(index, value){
23386                $('.' + value).removeClass(value);
23387            });
23388        }
23389
23390        /*
23391        * Sets the state for a variable with multiple states (original, and temporal)
23392        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
23393        * This function is used to keep track of both states, the original and the temporal one.
23394        * If type is not 'internal', then we assume the user is globally changing the variable.
23395        */
23396        function setVariableState(variable, value, type){
23397            options[variable] = value;
23398            if(type !== 'internal'){
23399                originals[variable] = value;
23400            }
23401        }
23402
23403        /**
23404        * Displays warnings
23405        */
23406        function displayWarnings(){
23407            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
23408            //UNCODE.addition
23409            // if($('html').hasClass(ENABLED)){
23410            //     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
23411            //     return;
23412            // }
23413
23414            // Disable mutually exclusive settings
23415            //UNCODE.addition
23416            // if (options.continuousVertical &&
23417            //     (options.loopTop || options.loopBottom)) {
23418            //     options.continuousVertical = false;
23419            //     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
23420            // }
23421
23422            // if(options.scrollBar && options.scrollOverflow){
23423            //     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
23424            // }
23425
23426            // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
23427            //     options.continuousVertical = false;
23428            //     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
23429            // }
23430
23431            //using extensions? Wrong file!
23432            $.each(extensions, function(index, extension){
23433                //is the option set to true?
23434                if(options[extension]){
23435                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
23436                }
23437            });
23438
23439            //anchors can not have the same value as any element ID or NAME
23440            $.each(options.anchors, function(index, name){
23441
23442                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
23443                var nameAttr = $document.find('[name]').filter(function() {
23444                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
23445                });
23446
23447                var idAttr = $document.find('[id]').filter(function() {
23448                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
23449                });
23450
23451                if(idAttr.length || nameAttr.length ){
23452                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
23453                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
23454                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
23455                }
23456            });
23457        }
23458
23459        /**
23460        * Shows a message in the console of the given type.
23461        */
23462        function showError(type, text){
23463            console && console[type] && console[type]('fullPage: ' + text);
23464        }
23465
23466    }; //end of $.fn.fullpage
23467
23468    if(typeof IScroll !== 'undefined'){
23469        /*
23470        * Turns iScroll `mousewheel` option off dynamically
23471        * https://github.com/cubiq/iscroll/issues/1036
23472        */
23473        IScroll.prototype.wheelOn = function () {
23474            this.wrapper.addEventListener('wheel', this);
23475            this.wrapper.addEventListener('mousewheel', this);
23476            this.wrapper.addEventListener('DOMMouseScroll', this);
23477        };
23478
23479        /*
23480        * Turns iScroll `mousewheel` option on dynamically
23481        * https://github.com/cubiq/iscroll/issues/1036
23482        */
23483        IScroll.prototype.wheelOff = function () {
23484            this.wrapper.removeEventListener('wheel', this);
23485            this.wrapper.removeEventListener('mousewheel', this);
23486            this.wrapper.removeEventListener('DOMMouseScroll', this);
23487        };
23488    }
23489
23490    /**
23491     * An object to handle overflow scrolling.
23492     * This uses jquery.slimScroll to accomplish overflow scrolling.
23493     * It is possible to pass in an alternate scrollOverflowHandler
23494     * to the fullpage.js option that implements the same functions
23495     * as this handler.
23496     *
23497     * @type {Object}
23498     */
23499    var iscrollHandler = {
23500        refreshId: null,
23501        iScrollInstances: [],
23502
23503        // Enables or disables the mouse wheel for the active section or all slides in it
23504        toggleWheel: function(value){
23505            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
23506            scrollable.each(function(){
23507                var iScrollInstance = $(this).data('iscrollInstance');
23508                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
23509                    if(value){
23510                        iScrollInstance.wheelOn();
23511                    }
23512                    else{
23513                        iScrollInstance.wheelOff();
23514                    }
23515                }
23516            });
23517        },
23518
23519        /**
23520        * Turns off iScroll for the destination section.
23521        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
23522        * scroll the destination section/slide before the sections animations ends.
23523        */
23524        onLeave: function(){
23525            iscrollHandler.toggleWheel(false);
23526        },
23527
23528        // Turns off iScroll for the leaving section
23529        beforeLeave: function(){
23530            iscrollHandler.onLeave()
23531        },
23532
23533        // Turns on iScroll on section load
23534        afterLoad: function(){
23535            iscrollHandler.toggleWheel(true);
23536        },
23537
23538        /**
23539         * Called when overflow scrolling is needed for a section.
23540         *
23541         * @param  {Object} element      jQuery object containing current section
23542         * @param  {Number} scrollHeight Current window height in pixels
23543         */
23544        create: function(element, scrollHeight) {
23545            var scrollable = element.find(SCROLLABLE_SEL);
23546
23547            scrollable.height(scrollHeight);
23548            scrollable.each(function() {
23549                var $this = $(this);
23550                var iScrollInstance = $this.data('iscrollInstance');
23551                if (iScrollInstance) {
23552                    $.each(iscrollHandler.iScrollInstances, function(){
23553                        $(this).destroy();
23554                    });
23555                }
23556
23557                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
23558                iscrollHandler.iScrollInstances.push(iScrollInstance);
23559
23560                //off by default until the section gets active
23561                iScrollInstance.wheelOff();
23562
23563                $this.data('iscrollInstance', iScrollInstance);
23564            });
23565        },
23566
23567        /**
23568         * Return a boolean depending on whether the scrollable element is a
23569         * the end or at the start of the scrolling depending on the given type.
23570         *
23571         * @param  {String}  type       Either 'top' or 'bottom'
23572         * @param  {Object}  scrollable jQuery object for the scrollable element
23573         * @return {Boolean}
23574         */
23575        isScrolled: function(type, scrollable) {
23576            var scroller = scrollable.data('iscrollInstance');
23577
23578            //no scroller?
23579            if (!scroller) {
23580                return true;
23581            }
23582
23583            if (type === 'top') {
23584                return scroller.y >= 0 && !scrollable.scrollTop();
23585            } else if (type === 'bottom') {
23586                return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
23587            }
23588        },
23589
23590        /**
23591         * Returns the scrollable element for the given section.
23592         * If there are landscape slides, will only return a scrollable element
23593         * if it is in the active slide.
23594         *
23595         * @param  {Object}  activeSection jQuery object containing current section
23596         * @return {Boolean}
23597         */
23598        scrollable: function(activeSection){
23599            // if there are landscape slides, we check if the scrolling bar is in the current one or not
23600            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
23601                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
23602            }
23603            return activeSection.find(SCROLLABLE_SEL);
23604        },
23605
23606        /**
23607         * Returns the scroll height of the wrapped content.
23608         * If this is larger than the window height minus section padding,
23609         * overflow scrolling is needed.
23610         *
23611         * @param  {Object} element jQuery object containing current section
23612         * @return {Number}
23613         */
23614        scrollHeight: function(element) {
23615            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
23616        },
23617
23618        /**
23619         * Called when overflow scrolling is no longer needed for a section.
23620         *
23621         * @param  {Object} element      jQuery object containing current section
23622         */
23623        remove: function(element) {
23624            var scrollable = element.find(SCROLLABLE_SEL);
23625            if (scrollable.length) {
23626                var iScrollInstance = scrollable.data('iscrollInstance');
23627                iScrollInstance.destroy();
23628
23629                scrollable.data('iscrollInstance', null);
23630            }
23631            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
23632        },
23633
23634        /**
23635         * Called when overflow scrolling has already been setup but the
23636         * window height has potentially changed.
23637         *
23638         * @param  {Object}
vendor: 16,384 bytes, lines 23638-24189
23638 element      jQuery object containing current section
23639         * @param  {Number} scrollHeight Current window height in pixels
23640         */
23641        update: function(element, scrollHeight) {
23642            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
23643            //short period of time.
23644            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
23645            clearTimeout(iscrollHandler.refreshId);
23646            iscrollHandler.refreshId = setTimeout(function(){
23647                $.each(iscrollHandler.iScrollInstances, function(){
23648                    $(this).get(0).refresh();
23649                });
23650            }, 150);
23651
23652            //updating the wrappers height
23653            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
23654        },
23655
23656        /**
23657         * Called to get any additional elements needed to wrap the section
23658         * content in order to facilitate overflow scrolling.
23659         *
23660         * @return {String|Object} Can be a string containing HTML,
23661         *                         a DOM element, or jQuery object.
23662         */
23663        wrapContent: function() {
23664            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
23665        }
23666    };
23667});
23668
23669/* ========================================================================
23670 * Bootstrap: collapse.js v3.1.1
23671 * http://getbootstrap.com/javascript/#collapse
23672 * ========================================================================
23673 * Copyright 2011-2014 Twitter, Inc.
23674 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
23675 * ======================================================================== */
23676
23677
23678+function ($) {
23679	'use strict';
23680
23681	// COLLAPSE PUBLIC CLASS DEFINITION
23682	// ================================
23683
23684	var Collapse = function (element, options) {
23685		this.$element      = $(element)
23686		this.options       = $.extend({}, Collapse.DEFAULTS, options)
23687		this.transitioning = null
23688
23689		if (this.options.parent) this.$parent = $(this.options.parent)
23690		if (this.options.toggle) this.toggle()
23691	}
23692
23693	Collapse.DEFAULTS = {
23694		toggle: true
23695	}
23696
23697	Collapse.prototype.dimension = function () {
23698		var hasWidth = this.$element.hasClass('width')
23699		return hasWidth ? 'width' : 'height'
23700	}
23701
23702	Collapse.prototype.show = function () {
23703		if (this.transitioning || this.$element.hasClass('in')) return
23704
23705		var startEvent = $.Event('show.bs.collapse')
23706		this.$element.trigger(startEvent)
23707		if (startEvent.isDefaultPrevented()) return
23708
23709		var actives = this.$parent && this.$parent.find('> .panel > .in')
23710
23711		if (actives && actives.length) {
23712			var hasData = actives.data('bs.collapse')
23713			if (hasData && hasData.transitioning) return
23714			actives.collapse('hide')
23715			hasData || actives.data('bs.collapse', null)
23716		}
23717
23718		var dimension = this.dimension()
23719
23720		this.$element
23721			.removeClass('collapse')
23722			.addClass('collapsing')[dimension](0)
23723
23724		this.transitioning = 1
23725
23726		var complete = function (e) {
23727			if (e && e.target != this.$element[0]) return
23728			this.$element
23729				.removeClass('collapsing')
23730				.addClass('collapse in')[dimension]('auto')
23731			this.transitioning = 0
23732			this.$element.trigger('shown.bs.collapse')
23733		}
23734
23735		if (!$.support.transition) return complete.call(this)
23736
23737		var scrollSize = $.camelCase(['scroll', dimension].join('-'))
23738
23739		this.$element
23740			.one($.support.transition.end, $.proxy(complete, this))
23741			.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
23742	}
23743
23744	Collapse.prototype.hide = function () {
23745		if (this.transitioning || !this.$element.hasClass('in')) return
23746
23747		var startEvent = $.Event('hide.bs.collapse')
23748		this.$element.trigger(startEvent)
23749		if (startEvent.isDefaultPrevented()) return
23750
23751		var dimension = this.dimension()
23752
23753		this.$element[dimension](this.$element[dimension]())[0].offsetHeight
23754
23755		this.$element
23756			.addClass('collapsing')
23757			.removeClass('collapse')
23758			.removeClass('in')
23759
23760		this.transitioning = 1
23761
23762		var complete = function (e) {
23763			if (e && e.target != this.$element[0]) return
23764			this.transitioning = 0
23765			this.$element
23766				.trigger('hidden.bs.collapse')
23767				.removeClass('collapsing')
23768				.addClass('collapse')
23769		}
23770
23771		if (!$.support.transition) return complete.call(this)
23772
23773		this.$element
23774			[dimension](0)
23775			.one($.support.transition.end, $.proxy(complete, this))
23776			.emulateTransitionEnd(350)
23777	}
23778
23779	Collapse.prototype.toggle = function () {
23780		this[this.$element.hasClass('in') ? 'hide' : 'show']()
23781	}
23782
23783
23784	// COLLAPSE PLUGIN DEFINITION
23785	// ==========================
23786
23787	var old = $.fn.collapse
23788
23789	$.fn.collapse = function (option) {
23790		return this.each(function () {
23791			var $this   = $(this)
23792			var data    = $this.data('bs.collapse')
23793			var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
23794
23795			if (!data && options.toggle && option == 'show') option = !option
23796			if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
23797			if (typeof option == 'string') data[option]()
23798		})
23799	}
23800
23801	$.fn.collapse.Constructor = Collapse
23802
23803
23804	// COLLAPSE NO CONFLICT
23805	// ====================
23806
23807	$.fn.collapse.noConflict = function () {
23808		$.fn.collapse = old
23809		return this
23810	}
23811
23812
23813	// COLLAPSE DATA-API
23814	// =================
23815
23816	$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
23817		var $this   = $(this), href
23818		var target  = $this.attr('data-target')
23819				|| e.preventDefault()
23820				|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
23821		//Edited by Uncode to replace ID in panel [START]
23822		var _target = href.replace(/^#/, "");
23823		if ( $('[data-id="' + _target + '"]').length ) {
23824			var $target = $('[data-id="' + _target + '"]')
23825		} else {
23826			var $target = $(target)
23827		}
23828		//Edited by Uncode to replace ID in panel [END]
23829		var data    = $target.data('bs.collapse')
23830		var option  = data ? 'toggle' : $this.data()
23831		var parent  = $this.attr('data-parent')
23832		var $parent = parent && $(parent)
23833
23834		if (!data || !data.transitioning) {
23835			if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
23836			$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
23837		}
23838
23839		$target.collapse(option)
23840	})
23841
23842}(jQuery);
23843
23844/* ========================================================================
23845 * Bootstrap: tab.js v3.1.1
23846 * http://getbootstrap.com/javascript/#tabs
23847 * ========================================================================
23848 * Copyright 2011-2014 Twitter, Inc.
23849 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
23850 * ======================================================================== */
23851
23852
23853+function ($) {
23854  'use strict';
23855
23856  // TAB CLASS DEFINITION
23857  // ====================
23858
23859  var Tab = function (element) {
23860    this.element = $(element)
23861  }
23862
23863  Tab.prototype.show = function () {
23864    var $this    = this.element
23865    var $ul      = $this.closest('ul:not(.dropdown-menu)')
23866    var selector = $this.data('target')
23867
23868    if (!selector) {
23869      selector = $this.attr('href')
23870      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
23871    }
23872
23873    if ($this.parent('li').hasClass('active')) return
23874
23875    var previous = $ul.find('.active:last a')[0]
23876    var e        = $.Event('show.bs.tab', {
23877      relatedTarget: previous
23878    })
23879
23880    $this.trigger(e)
23881
23882    if (e.isDefaultPrevented()) return
23883
23884    //Edited by Uncode to replace ID in panel [START]
23885    var _target = selector.replace(/^#/, "");
23886    if ( $('[data-id="' + _target + '"]').length )
23887      var $target = $('[data-id="' + _target + '"]')
23888    else
23889      var $target = $(selector)
23890    //Edited by Uncode to replace ID in panel [END]
23891
23892    this.activate($this.parent('li'), $ul)
23893    this.activate($target, $target.parent(), function () {
23894      $this.trigger({
23895        type: 'shown.bs.tab',
23896        relatedTarget: previous
23897      })
23898    })
23899  }
23900
23901  Tab.prototype.activate = function (element, container, callback) {
23902    var $active    = container.find('> .active')
23903    var transition = callback
23904      && $.support.transition
23905      && $active.hasClass('fade')
23906
23907    function next() {
23908      $active
23909        .removeClass('active')
23910        .find('> .dropdown-menu > .active')
23911        .removeClass('active')
23912
23913      element.addClass('active')
23914
23915      if (transition) {
23916        element[0].offsetWidth // reflow for transition
23917        element.addClass('in')
23918      } else {
23919        element.removeClass('fade')
23920      }
23921
23922      if (element.parent('.dropdown-menu')) {
23923        element.closest('li.dropdown').addClass('active')
23924      }
23925
23926      callback && callback()
23927    }
23928
23929    transition ?
23930      $active
23931        .one($.support.transition.end, next)
23932        .emulateTransitionEnd(150) :
23933      next()
23934
23935    $active.removeClass('in')
23936  }
23937
23938
23939  // TAB PLUGIN DEFINITION
23940  // =====================
23941
23942  var old = $.fn.tab
23943
23944  $.fn.tab = function ( option ) {
23945    return this.each(function () {
23946      var $this = $(this)
23947      var data  = $this.data('bs.tab')
23948
23949      if (!data) $this.data('bs.tab', (data = new Tab(this)))
23950      if (typeof option == 'string') data[option]()
23951    })
23952  }
23953
23954  $.fn.tab.Constructor = Tab
23955
23956
23957  // TAB NO CONFLICT
23958  // ===============
23959
23960  $.fn.tab.noConflict = function () {
23961    $.fn.tab = old
23962    return this
23963  }
23964
23965
23966  // TAB DATA-API
23967  // ============
23968
23969  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
23970    e.preventDefault()
23971    $(this).tab('show')
23972  })
23973
23974}(jQuery);
23975
23976/* ========================================================================
23977 * Bootstrap: tooltip.js v3.1.1
23978 * http://getbootstrap.com/javascript/#tooltip
23979 * Inspired by the original jQuery.tipsy by Jason Frame
23980 * ========================================================================
23981 * Copyright 2011-2014 Twitter, Inc.
23982 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
23983 * ======================================================================== */
23984
23985
23986+function ($) {
23987  'use strict';
23988
23989  // TOOLTIP PUBLIC CLASS DEFINITION
23990  // ===============================
23991
23992  var Tooltip = function (element, options) {
23993    this.type       =
23994    this.options    =
23995    this.enabled    =
23996    this.timeout    =
23997    this.hoverState =
23998    this.$element   = null
23999
24000    this.init('tooltip', element, options)
24001  }
24002
24003  Tooltip.DEFAULTS = {
24004    animation: true,
24005    placement: 'top',
24006    selector: false,
24007    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
24008    trigger: 'hover focus',
24009    title: '',
24010    delay: 0,
24011    html: false,
24012    container: false,
24013    viewport: {
24014      selector: 'body',
24015      padding: 0
24016    }
24017  }
24018
24019  Tooltip.prototype.init = function (type, element, options) {
24020    this.enabled   = true
24021    this.type      = type
24022    this.$element  = $(element)
24023    this.options   = this.getOptions(options)
24024    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
24025
24026    var triggers = this.options.trigger.split(' ')
24027
24028    for (var i = triggers.length; i--;) {
24029      var trigger = triggers[i]
24030
24031      if (trigger == 'click') {
24032        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
24033      } else if (trigger != 'manual') {
24034        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
24035        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
24036
24037        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
24038        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
24039      }
24040    }
24041
24042    this.options.selector ?
24043      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
24044      this.fixTitle()
24045  }
24046
24047  Tooltip.prototype.getDefaults = function () {
24048    return Tooltip.DEFAULTS
24049  }
24050
24051  Tooltip.prototype.getOptions = function (options) {
24052    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
24053
24054    if (options.delay && typeof options.delay == 'number') {
24055      options.delay = {
24056        show: options.delay,
24057        hide: options.delay
24058      }
24059    }
24060
24061    return options
24062  }
24063
24064  Tooltip.prototype.getDelegateOptions = function () {
24065    var options  = {}
24066    var defaults = this.getDefaults()
24067
24068    this._options && $.each(this._options, function (key, value) {
24069      if (defaults[key] != value) options[key] = value
24070    })
24071
24072    return options
24073  }
24074
24075  Tooltip.prototype.enter = function (obj) {
24076    var self = obj instanceof this.constructor ?
24077      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
24078
24079    clearTimeout(self.timeout)
24080
24081    self.hoverState = 'in'
24082
24083    if (!self.options.delay || !self.options.delay.show) return self.show()
24084
24085    self.timeout = setTimeout(function () {
24086      if (self.hoverState == 'in') self.show()
24087    }, self.options.delay.show)
24088  }
24089
24090  Tooltip.prototype.leave = function (obj) {
24091    var self = obj instanceof this.constructor ?
24092      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
24093
24094    clearTimeout(self.timeout)
24095
24096    self.hoverState = 'out'
24097
24098    if (!self.options.delay || !self.options.delay.hide) return self.hide()
24099
24100    self.timeout = setTimeout(function () {
24101      if (self.hoverState == 'out') self.hide()
24102    }, self.options.delay.hide)
24103  }
24104
24105  Tooltip.prototype.show = function () {
24106    var e = $.Event('show.bs.' + this.type)
24107
24108    if (this.hasContent() && this.enabled) {
24109      this.$element.trigger(e)
24110
24111      if (e.isDefaultPrevented()) return
24112      var that = this;
24113
24114      var $tip = this.tip()
24115
24116      this.setContent()
24117
24118      if (this.options.animation) $tip.addClass('fade')
24119
24120      var placement = typeof this.options.placement == 'function' ?
24121        this.options.placement.call(this, $tip[0], this.$element[0]) :
24122        this.options.placement
24123
24124      var autoToken = /\s?auto?\s?/i
24125      var autoPlace = autoToken.test(placement)
24126      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
24127
24128      $tip
24129        .detach()
24130        .css({ top: 0, left: 0, display: 'block' })
24131        .addClass(placement)
24132
24133      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
24134
24135      var pos          = this.getPosition()
24136      var actualWidth  = $tip[0].offsetWidth
24137      var actualHeight = $tip[0].offsetHeight
24138
24139      if (autoPlace) {
24140        var orgPlacement = placement
24141        var $parent      = this.$element.parent()
24142        var parentDim    = this.getPosition($parent)
24143
24144        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
24145                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
24146                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
24147                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
24148                    placement
24149
24150        $tip
24151          .removeClass(orgPlacement)
24152          .addClass(placement)
24153      }
24154
24155      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
24156
24157      this.applyPlacement(calculatedOffset, placement)
24158      this.hoverState = null
24159
24160      var complete = function() {
24161        that.$element.trigger('shown.bs.' + that.type)
24162      }
24163
24164      $.support.transition && this.$tip.hasClass('fade') ?
24165        $tip
24166          .one($.support.transition.end, complete)
24167          .emulateTransitionEnd(150) :
24168        complete()
24169    }
24170  }
24171
24172  Tooltip.prototype.applyPlacement = function (offset, placement) {
24173    var $tip   = this.tip()
24174    var width  = $tip[0].offsetWidth
24175    var height = $tip[0].offsetHeight
24176
24177    // manually read margins because getBoundingClientRect includes difference
24178    var marginTop = parseInt($tip.css('margin-top'), 10)
24179    var marginLeft = parseInt($tip.css('margin-left'), 10)
24180
24181    // we must check for NaN for ie 8/9
24182    if (isNaN(marginTop))  marginTop  = 0
24183    if (isNaN(marginLeft)) marginLeft = 0
24184
24185    offset.top  = offset.top  + marginTop
24186    offset.left = offset.left + marginLeft
24187
24188    // $.fn.offset doesn't round pixel values
24189    // so we use setOff
24189set directly with our own function B-0
24190    $.offset.setOffset($tip[0], $.extend({
24191      using: function (props) {
24192        $tip.css({
24193          top: Math.round(props.top),
24194          left: Math.round(props.left)
24195        })
24196      }
24197    }, offset), 0)
24198
24199    $tip.addClass('in')
24200
24201    // check to see if placing tip in new offset caused the tip to resize itself
24202    var actualWidth  = $tip[0].offsetWidth
24203    var actualHeight = $tip[0].offsetHeight
24204
24205    if (placement == 'top' && actualHeight != height) {
24206      offset.top = offset.top + height - actualHeight
24207    }
24208
24209    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
24210
24211    if (delta.left) offset.left += delta.left
24212    else offset.top += delta.top
24213
24214    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
24215    var arrowPosition       = delta.left ? 'left'        : 'top'
24216    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
24217
24218    $tip.offset(offset)
24219    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
24220  }
24221
24222  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
24223    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
24224  }
24225
24226  Tooltip.prototype.setContent = function () {
24227    var $tip  = this.tip()
24228    var title = this.getTitle()
24229
24230    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
24231    $tip.removeClass('fade in top bottom left right')
24232  }
24233
24234  Tooltip.prototype.hide = function () {
24235    var that = this
24236    var $tip = this.tip()
24237    var e    = $.Event('hide.bs.' + this.type)
24238
24239    function complete() {
24240      if (that.hoverState != 'in') $tip.detach()
24241      that.$element.trigger('hidden.bs.' + that.type)
24242    }
24243
24244    this.$element.trigger(e)
24245
24246    if (e.isDefaultPrevented()) return
24247
24248    $tip.removeClass('in')
24249
24250    $.support.transition && this.$tip.hasClass('fade') ?
24251      $tip
24252        .one($.support.transition.end, complete)
24253        .emulateTransitionEnd(150) :
24254      complete()
24255
24256    this.hoverState = null
24257
24258    return this
24259  }
24260
24261  Tooltip.prototype.fixTitle = function () {
24262    var $e = this.$element
24263    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
24264      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
24265    }
24266  }
24267
24268  Tooltip.prototype.hasContent = function () {
24269    return this.getTitle()
24270  }
24271
24272  Tooltip.prototype.getPosition = function ($element) {
24273    $element   = $element || this.$element
24274    var el     = $element[0]
24275    var isBody = el.tagName == 'BODY'
24276    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
24277      scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
24278      width:  isBody ? $(window).width()  : $element.outerWidth(),
24279      height: isBody ? $(window).height() : $element.outerHeight()
24280    }, isBody ? {top: 0, left: 0} : $element.offset())
24281  }
24282
24283  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
24284    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
24285           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
24286           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
24287        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
24288
24289  }
24290
24291  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
24292    var delta = { top: 0, left: 0 }
24293    if (!this.$viewport) return delta
24294
24295    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
24296    var viewportDimensions = this.getPosition(this.$viewport)
24297
24298    if (/right|left/.test(placement)) {
24299      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
24300      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
24301      if (topEdgeOffset < viewportDimensions.top) { // top overflow
24302        delta.top = viewportDimensions.top - topEdgeOffset
24303      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
24304        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
24304EdgeOffset
24305      }
24306    } else {
24307      var leftEdgeOffset  = pos.left - viewportPadding
24308      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
24309      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
24310        delta.left = viewportDimensions.left - leftEdgeOffset
24311      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
24312        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
24313      }
24314    }
24315
24316    return delta
24317  }
24318
24319  Tooltip.prototype.getTitle = function () {
24320    var title
24321    var $e = this.$element
24322    var o  = this.options
24323
24324    title = $e.attr('data-original-title')
24325      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
24326
24327    return title
24328  }
24329
24330  Tooltip.prototype.tip = function () {
24331    return this.$tip = this.$tip || $(this.options.template)
24332  }
24333
24334  Tooltip.prototype.arrow = function () {
24335    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
24336  }
24337
24338  Tooltip.prototype.validate = function () {
24339    if (!this.$element[0].parentNode) {
24340      this.hide()
24341      this.$element = null
24342      this.options  = null
24343    }
24344  }
24345
24346  Tooltip.prototype.enable = function () {
24347    this.enabled = true
24348  }
24349
24350  Tooltip.prototype.disable = function () {
24351    this.enabled = false
24352  }
24353
24354  Tooltip.prototype.toggleEnabled = function () {
24355    this.enabled = !this.enabled
24356  }
24357
24358  Tooltip.prototype.toggle = function (e) {
24359    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
24360    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
24361  }
24362
24363  Tooltip.prototype.destroy = function () {
24364    clearTimeout(this.timeout)
24365    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
24366  }
24367
24368
24369  // TOOLTIP PLUGIN DEFINITION
24370  // =========================
24371
24372  var old = $.fn.tooltip
24373
24374  $.fn.tooltip = function (option) {
24375    return this.each(function () {
24376      var $this   = $(this)
24377      var data    = $this.data('bs.tooltip')
24378      var options = typeof option == 'object' && option
24379
24380      if (!data && option == 'destroy') return
24381      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
24382      if (typeof option == 'string') data[option]()
24383    })
24384  }
24385
24386  $.fn.tooltip.Constructor = Tooltip
24387
24388
24389  // TOOLTIP NO CONFLICT
24390  // ===================
24391
24392  $.fn.tooltip.noConflict = function () {
24393    $.fn.tooltip = old
24394    return this
24395  }
24396
24397}(jQuery);
24398
24399/* ========================================================================
24400 * Bootstrap: transition.js v3.1.1
24401 * http://getbootstrap.com/javascript/#transitions
24402 * ========================================================================
24403 * Copyright 2011-2014 Twitter, Inc.
24404 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
24405 * ======================================================================== */
24406
24407
24408+function ($) {
24409  'use strict';
24410
24411  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
24412  // ============================================================
24413
24414  function transitionEnd() {
24415    var el = document.createElement('bootstrap')
24416
24417    var transEndEventNames = {
24418      WebkitTransition : 'webkitTransitionEnd',
24419      MozTransition    : 'transitionend',
24420      OTransition      : 'oTransitionEnd otransitionend',
24421      transition       : 'transitionend'
24422    }
24423
24424    for (var name in transEndEventNames) {
24425      if (el.style[name] !== undefined) {
24426        return { end: transEndEventNames[name] }
24427      }
24428    }
24429
24430    return false // explicit for ie8 (  ._.)
24431  }
24432
24433  // http://blog.alexmaccaw.com/css-transitions
24434  $.fn.emulateTransitionEnd = function (duration) {
24435    var called = false, $el = this
24436    $(this).one($.support.transition.end, function () { called = true })
24437    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
24438    setTimeout(callback, duration)
24439    return this
24440  }
24441
24442  $(function () {
24443    $.support.transition = transitionEnd()
24444  })
24445
24446}(jQuery);

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.