PageSourceSearch

https://www.locosquad.de/wp-content/themes/uncode/library/js/plugins.js?ver=205743600

js locosquad.de collected 2026-10-10 02:34:45 UTC 794,014 bytes, 24,438 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				if ( $('body').hasClass('vmenu') ) return;
7322				if (this.showTimeout) {
7323					clearTimeout(this.showTimeout);
7324					this.showTimeout = 0;
7325				}
7326				// hide all subs
7327				for (var i = this.visibleSubMenus.length - 1; i > 0; i--) {
7328					this.menuHide(this.visibleSubMenus[i]);
7329				}
7330				// hide root if it's popup
7331				if (this.opts.isPopup) {
7332					this.$root.stop(true, true);
7333					if (this.$root.is(':visible')) {
7334						if (this.opts.hideFunction) {
7335							this.opts.hideFunction.call(this, this.$root);
7336						} else {
7337							this.$root.hide(this.opts.hideDuration);
7338						}
7339						// remove IE iframe shim
7340						if (this.$root.dataSM('ie-shim')) {
7341							this.$root.dataSM('ie-shim').remove();
7342						}
7343					}
7344				}
7345				this.activatedItems = [];
7346				this.visibleSubMenus = [];
7347				this.clickActivated = false;
7348				// reset z-index increment
7349				this.zIndexInc = 0;
7350			},
7351			menuIframeShim: function($ul) {
7352				// create iframe shim for the menu
7353				if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
7354					$ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
7355						.css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
7356					);
7357				}
7358			},
7359			menuInit: function($ul) {
7360				if (!$ul.dataSM('in-mega')) {
7361					this.subMenus.push($ul);
7362					// mark UL's in mega drop downs (if any) so we can neglect them
7363					if ($ul.hasClass('mega-menu')) {
7364						$ul.find('ul').dataSM('in-mega', true);
7365					}
7366					// get level (much faster than, for example, using parentsUntil)
7367					var level = 2,
7368						par = $ul[0];
7369					while ((par = par.parentNode.parentNode) != this.$root[0]) {
7370						level++;
7371					}
7372					// cache stuff
7373					$ul.dataSM('parent-a', $ul.prevAll('a').eq(-1))
7374						.dataSM('level', level)
7375						.parent().dataSM('sub', $ul);
7376					// add sub indicator to parent item
7377					if (this.opts.subIndicators) {
7378						$ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone());
7379					}
7380				}
7381			},
7382			menuPosition: function($sub) {
7383				var fixIE = $('html.ie').length;
7384				// if (fixIE) {
7385				// 	var $rowParent = $($sub).closest('.main-menu-container');
7386				// 	$rowParent.height($rowParent.height());
7387				// }
7388				var $a = $sub.dataSM('parent-a'),
7389					$li = $sub.parent(),
7390					$ul = $sub.parent().parent(),
7391					$container = $ul.closest('.row-menu-inner').length ? $ul.closest('.row-menu-inner') : $ul.closest('.uncol'),
7392					level = $sub.dataSM('level'),
7393					subW = this.getWidth($sub),
7394					subH = this.getHeight($sub),
7395					itemOffset = $a.offset(),
7396					itemX = itemOffset.left,
7397					itemY = itemOffset.top,
7398					itemW = this.getWidth($a),
7399					itemH = this.getHeight($a),
7400					$win = $(window),
7401					winX = $win.scrollLeft(),
7402					winY = $win.scrollTop(),
7403					winW = $win.width(),
7404					winH = $win.height(),
7405					containerW = $container.width(),
7406					containerOffsetX = containerW + ((winW - containerW) / 2),
7407					horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'),
7408					subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
7409					subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
7410					x, y, leftPos;
7411				if (horizontalParent) {
7412					x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX;
7413					y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
7414				} else {
7415					x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX;
7416					y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
7417				}
7418				if (this.opts.keepInViewport && !this.isCollapsible()) {
7419					if (this.isFixed()) {
7420						itemX -= winX;
7421						itemY -= winY;
7422						winX = winY = 0;
7423					}
7424					var absX = itemX + x,
7425						absY = itemY + y;
7426					if (this.opts.rightToLeftSubMenus && absX < winX) {
7427						x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
7428					} else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) {
7429						x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW;
7430					}
7431					if (!horizontalParent) {
7432						if (subH < winH && absY + subH > winY + winH) {
7433							y += winY + winH - subH - absY;
7434						} else if (subH >= winH || absY < winY) {
7435							y += winY - absY;
7436						}
7437					}
7438					// do we need scrolling?
7439					// 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH"
7440					if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) {
7441						var self = this;
7442						if (!$sub.dataSM('scroll-arrows')) {
7443							$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]])
7444								.bind({
7445									mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); },
7446									mouseleave: function(e) {
7447										self.menuScrollStop($sub);
7448										self.menuScrollOut($sub, e);
7449									},
7450									'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
7451								})
7452								.insertAfter($sub)
7453							);
7454						}
7455						// bind events to show/hide arrows on hover and save scrolling data for this sub
7456						var vportY = winY - (itemY + itemH);
7457						$sub.dataSM('scroll', {
7458								vportY: vportY,
7459								subH: subH,
7460								winH: winH,
7461								step: 1
7462							})
7463							.bind({
7464								'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); },
7465								'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); },
7466								'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); }
7467							})
7468							.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
7468StartZIndex() + this.zIndexInc })
7469							.eq(0).css('margin-top', vportY).end()
7470							.eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end()
7471							.eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
7472					}
7473				}
7474				// if ($sub.hasClass('mega-menu-inner')) {
7475				// 	if ($('.menu-wrapper .megamenu-diff').length > 0) {
7476				// 		leftPos = parseFloat($('.menu-wrapper .megamenu-diff').outerWidth());
7477				// 		leftPos = -leftPos;
7478				// 	} else leftPos = parseFloat($('.menu-wrapper .main-menu-container').css('paddingLeft'));
7479
7480				// 	if ($('body.header-full-width').length > 0) {
7481				// 		$sub.css({ width: $('.box-container').width()});
7482				// 		leftPos = (leftPos - parseFloat($('.menu-wrapper .row-menu-inner').css('paddingLeft')));
7483				// 	} else $sub.css({ width: containerW});
7484				// 	leftPos = leftPos + 'px';
7485
7486				// } else {
7487				// 	leftPos = $li.position().left + 'px';
7488				// }
7489				var rightPos = 'auto';
7490				if ( $sub.parents('.isotope-filters').length ) {
7491					if ( $sub.parents('.text-right').eq(0).length ) {
7492						leftPos = '0px';
7493						rightPos = 'auto';
7494					} else {
7495						leftPos = 'auto';
7496						rightPos = '0px';
7497					}
7498					x = 0;
7499				} else {
7500					if ($sub.hasClass('mega-menu-inner')) {
7501						$sub.css({ width: containerW});
7502						if ( $('body.hmenu-center-double').length ) {
7503							leftPos = '0px';
7504						} else {
7505							if ( $('body.hmenu-center-split').length > 0 && !$sub.closest('.navbar-cta').length && ! $('body.hormenu-position-right').length ) {
7506								leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px';
7507							} else {
7508								if ( $sub.closest('.navbar-cta').length && !$('body.hmenu').length && !$('body.hmenu-center').length ) {
7509									leftPos = - ( parseFloat($sub.closest('.navbar-cta').offset().left) - parseFloat($sub.closest('.row-menu-inner').find('.logo-container').offset().left) ) + 'px';
7510								} else if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0 && !$('body.hmenu-center-split').length) {
7511									leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px';
7512								} else {
7513									leftPos = '0px';
7514								}
7515							}
7516						}
7517					} else {
7518						leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px';
7519						x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1;
7520					}
7521				}
7522
7523
7524				$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) });
7525				// IE iframe shim
7526				this.menuIframeShim($sub);
7527				if ($sub.dataSM('ie-shim')) {
7528					$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) });
7529				}
7530			},
7531			menuScroll: function($sub, up, wheel) {
7532				var y = parseFloat($sub.css('margin-top')),
7533					scroll = $sub.dataSM('scroll'),
7534					end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH),
7535					step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
7536				$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
7537				y = parseFloat($sub.css('margin-top'));
7538				// show opposite arrow if appropriate
7539				if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
7540					$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
7541				}
7542				// accelerate when not using mousewheel to scroll
7543				if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
7544					$sub.dataSM('scroll').step += 0.5;
7545				}
7546				// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
7547				if (Math.abs(y - end) < 1) {
7548					$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
7549					$sub.dataSM('scroll').step = 1;
7550				} else if (!wheel) {
7551					var self = this;
7552					this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
7553				}
7554			},
7555			menuScrollMousewheel: function($sub, e) {
7556				var $closestSub = $(e.target).closest('ul');
7557				while ($closestSub.dataSM('in-mega')) {
7558					$closestSub = $closestSub.parent().closest('ul');
7559				}
7560				if ($closestSub[0] == $sub[0]) {
7561					var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
7562					if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
7563						this.menuScroll($sub, up, true);
7564					}
7565				}
7566				e.preventDefault();
7567			},
7568			menuScrollOut: function($sub, e) {
7569				var reClass = /^scroll-(up|down)/,
7570					$closestSub = $(e.relatedTarget).closest('ul');
7571				while ($closestSub.dataSM('in-mega')) {
7572					$closestSub = $closestSub.parent().closest('ul');
7573				}
7574				if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
7575					$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
7576				}
7577			},
7578			menuScrollOver: function($sub, e) {
7579				var reClass = /^scroll-(up|down)/,
7580					$closestSub = $(e.target).closest('ul');
7581				while ($closestSub.dataSM('in-mega')) {
7582					$closestSub = $closestSub.parent().closest('ul');
7583				}
7584				if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
7585					$sub.dataSM('scroll-arrows').css('visibility', 'visible');
7586				}
7587			},
7588			menuScrollStop: function($sub) {
7589				if (this.scrollTimeout) {
7590					clearTimeout(this.scrollTimeout);
7591					this.scrollTimeout = 0;
7592					$sub.dataSM('scroll').step = 1;
7593				}
7594			},
7595			menuShow: function($sub) {
7596				if (!$sub.dataSM('beforefirstshowfired')) {
7597					$sub.dataSM('beforefirstshowfired', true);
7598					if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
7599						return;
7600					}
7601				}
7602				if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
7603					return;
7604				}
7605				this.menuFixLayout($sub);
7606				$sub.stop(true, true);
7607				if (!$sub.is(':visible')) {
7608					// set z-index - for IE < 9 set it to the parent LI
7609					var zIndex = this.getStartZIndex() + (++this.zIndexInc);
7610					if (IElt9) {
7611						$sub.parent().css('z-index', zIndex);
7612					} else {
7613						$sub.css('z-index', zIndex);
7614					}
7615					// highlight parent item
7616					if (this.opts.keepHighlighted || this.isCollapsible()) {
7617						if ($sub.dataSM('parent-a').attr('data-type') != 'title')
7618							$sub.dataSM('parent-a').addClass('highlighted');
7619					}
7620					// min/max-width fix - no way to rely purely on CSS as all UL's are nested
7621					if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
7622						if (!IElt8) {
7623							$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
7624							if (this.opts.subMenusMinWidth) {
7625							 	$sub.css('min-width', this.opts.subMenusMinWidth);
7626							}
7627							if (this.opts.subMenusMaxWidth) {
7628							 	var noMaxWidth = this.getWidth($sub);
7629							 	$sub.css('max-width', this.opts.subMenusMaxWidth);
7630								if (noMaxWidth > this.getWidth($sub)) {
7631									$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
7632								}
7633							}
7634						// IE6,7
7635 						} else {
7636							$sub.children().css('styleFloat', 'none');
7637							if (IE6) {
7638								$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
7639									.children().children('a').css('white-space', 'nowrap');
7640							} else { // IE7
7641								$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
7642								if (this.opts.subMenusMinWidth) {
7643							    $sub.css('min-width', this.opts.subMenusMinWidth);
7644								}
7645							}
7646							if (this.opts.subMenusMaxWidth) {
7647								var noMaxWidth = $sub.width();
7648								if (IE6) {
7649							 		var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
7650									if (noMaxWidth > maxWidth) {
7651										$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
7652									} else {
7653										$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
7654									}
7655								} else { // IE7
7656									$sub.css('max-width', this.opts.subMenusMaxWidth);
7657									if (noMaxWidth > $sub.width()) {
7658										$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
7659									} else {
7660										$sub.width(noMaxWidth);
7661									}
7662								}
7663							} else {
7664							 	$sub.width($sub.width());
7665							}
7666							$sub.children().css('styleFloat', 'left');
7667						}
7668					}
7669					this.menuPosition($sub);
7670					// insert IE iframe shim
7671					if ($sub.dataSM('ie-shim')) {
7672						$sub.dataSM('ie-shim').insertBefore($sub);
7673					}
7674					var complete = function() {
7675						// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
7676						$sub.css('overflow', '');
7677					};
7678					// if sub is collapsible (mobile view)
7679					if (this.isCollapsible()) {
7680						if (this.opts.collapsibleShowFunction) {
7681							this.opts.collapsibleShowFunction.call(this, $sub, complete);
7682						} else {
7683							$sub.show(this.opts.collapsibleShowDuration, complete);
7684						}
7685					} else {
7686						if (this.opts.showFunction) {
7687							this.opts.showFunction.call(this, $sub, complete);
7688						} else {
7689							$sub.show(this.opts.showDuration, complete);
7690						}
7691					}
7692					// save new sub menu for this level
7693					this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
7694					this.$root.triggerHandler('show.smapi', $sub[0]);
7695				}
7696			},
7697			popupHide: function(noHideTimeout) {
7698				if (this.hideTimeout) {
7699					clearTimeout(this.hideTimeout);
7700					this.hideTimeout = 0;
7701				}
7702				var self = this;
7703				this.hideTimeout = setTimeout(function() {
7704					self.menuHideAll();
7705				}, noHideTimeout ? 1 : this.opts.hideTimeout);
7706			},
7707			popupShow: function(left, top) {
7708				if (!this.opts.isPopup) {
7709					alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
7710					return;
7711				}
7712				if (this.hideTimeout) {
7713					clearTimeout(this.hideTimeout);
7714					this.hideTimeout = 0;
7715				}
7716				this.menuFixLayout(this.$root);
7717				this.$root.stop(true, true);
7718				if (!this.$root.is(':visible')) {
7719					this.$root.css({ left: left, top: top });
7720					// IE iframe shim
7721					this.menuIframeShim(this.$root);
7722					if (this.$root.dataSM('ie-shim')) {
7723						this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
7723: left, top: top }).insertBefore(this.$root);
7724					}
7725					// show menu
7726					if (this.opts.showFunction) {
7727						this.opts.showFunction.call(this, this.$root);
7728					} else {
7729						this.$root.show(this.opts.showDuration);
7730					}
7731					this.visibleSubMenus[0] = this.$root;
7732				}
7733			},
7734			refresh: function() {
7735				this.menuHideAll();
7736				this.$root.find('ul').each(function() {
7737						var $this = $(this);
7738						if ($this.dataSM('scroll-arrows')) {
7739							$this.dataSM('scroll-arrows').remove();
7740						}
7741					})
7742					.removeDataSM('in-mega')
7743					.removeDataSM('shown-before')
7744					.removeDataSM('ie-shim')
7745					.removeDataSM('scroll-arrows')
7746					.removeDataSM('parent-a')
7747					.removeDataSM('level')
7748					.removeDataSM('beforefirstshowfired');
7749				this.$root.find('a.has-submenu').removeClass('has-submenu')
7750					.parent().removeDataSM('sub');
7751				if (this.opts.subIndicators) {
7752					this.$root.find('span.sub-arrow').remove();
7753				}
7754				if (this.opts.markCurrentItem) {
7755					this.$root.find('a.current').removeClass('current');
7756				}
7757				this.subMenus = [];
7758				this.init(true);
7759			},
7760			rootOut: function(e) {
7761				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
7762					return;
7763				}
7764				if (this.hideTimeout) {
7765					clearTimeout(this.hideTimeout);
7766					this.hideTimeout = 0;
7767				}
7768				if (!this.opts.showOnClick || !this.opts.hideOnClick) {
7769					var self = this;
7770					this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
7771				}
7772			},
7773			rootOver: function(e) {
7774				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
7775					return;
7776				}
7777				if (this.hideTimeout) {
7778					clearTimeout(this.hideTimeout);
7779					this.hideTimeout = 0;
7780				}
7781			},
7782			winResize: function(e) {
7783				if (!this.handleEvents()) {
7784					// we still need to resize the disable overlay if it's visible
7785					if (this.$disableOverlay) {
7786						var pos = this.$root.offset();
7787	 					this.$disableOverlay.css({
7788							top: pos.top,
7789							left: pos.left,
7790							width: this.$root.outerWidth(),
7791							height: this.$root.outerHeight()
7792						});
7793					}
7794					return;
7795				}
7796				// hide sub menus on resize - on mobile do it only on orientation change
7797				if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
7798					if (this.activatedItems.length) {
7799						this.activatedItems[this.activatedItems.length - 1][0].blur();
7800					}
7801					this.menuHideAll();
7802				}
7803			}
7804		}
7805	});
7806
7807	$.fn.dataSM = function(key, val) {
7808		if (val) {
7809			return this.data(key + '_smartmenus', val);
7810		}
7811		return this.data(key + '_smartmenus');
7812	}
7813
7814	$.fn.removeDataSM = function(key) {
7815		return this.removeData(key + '_smartmenus');
7816	}
7817
7818	$.fn.smartmenus = function(options) {
7819		if (typeof options == 'string') {
7820			var args = arguments,
7821				method = options;
7822			Array.prototype.shift.call(args);
7823			return this.each(function() {
7824				var smartmenus = $(this).data('smartmenus');
7825				if (smartmenus && smartmenus[method]) {
7826					smartmenus[method].apply(smartmenus, args);
7827				}
7828			});
7829		}
7830		var opts = $.extend({}, $.fn.smartmenus.defaults, options);
7831		return this.each(function() {
7832			new $.SmartMenus(this, opts);
7833		});
7834	}
7835
7836	// default settings
7837	$.fn.smartmenus.defaults = {
7838		isPopup:		false,		// is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
7839		mainMenuSubOffsetX:	0,		// pixels offset from default position
7840		mainMenuSubOffsetY:	0,		// pixels offset from default position
7841		subMenusSubOffsetX:	0,		// pixels offset from default position
7842		subMenusSubOffsetY:	0,		// pixels offset from default position
7843		subMenusMinWidth:	'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
7844		subMenusMaxWidth:	'20em',		// max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
7845		subIndicators: 		true,		// create sub menu indicators - creates a SPAN and inserts it in the A
7846		subIndicatorsPos: 	'prepend',	// position of the SPAN relative to the menu item content ('prepend', 'append')
7847		subIndicatorsText:	'+',		// [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
7848		scrollStep: 		30,		// pixels step when scrolling long sub menus that do not fit in the viewport height
7849		scrollInterval:		30,		// interval between each scrolling step
7850		scrollAccelerate:	true,		// accelerate scrolling or use a fixed step
7851		showTimeout:		250,		// timeout before showing the sub menus
7852		hideTimeout:		500,		// timeout before hiding the sub menus
7853		showDuration:		0,		// duration for show animation - set to 0 for no animation - matters only if showFunction:null
7854		showFunction:		null,		// custom function to use when showing a sub menu (the default is the jQuery 'show')
7855							// don't forget to call complete() at the end of whatever you do
7856							// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
7857		hideDuration:		0,		// duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
7858		hideFunction:		function($ul, complete) { $ul.fadeOut(200, complete); },	// custom function to use when hiding a sub menu (the default is the jQuery 'hide')
7859							// don't forget to call complete() at the end of whatever you do
7860							// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
7861		collapsibleShowDuration:0,		// duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
7862		collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); },	// custom function to use when showing a collapsible sub menu
7863							// (i.e. when mobile styles are used to make the sub menus collapsible)
7864		collapsibleHideDuration:0,		// duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
7865		collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); },	// custom function to use when hiding a collapsible sub menu
7866							// (i.e. when mobile styles are used to make the sub menus collapsible)
7867		showOnClick:		false,		// show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
7868		hideOnClick:		true,		// hide the sub menus on click/tap anywhere on the page
7869		keepInViewport:		true,		// reposition the sub menus if needed to make sure they always appear inside the viewport
7870		keepHighlighted:	true,		// keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
7871		markCurrentItem:	false,		// automatically add the 'current' class to the A element of the item linking to the current URL
7872		markCurrentTree:	true,		// add the 'current' class also to the A elements of all ancestor items of the current item
7873		rightToLeftSubMenus:	false,		// right to left display of the sub menus (check the CSS for the sub indicators' position)
7874		bottomToTopSubMenus:	false,		// bottom to top display of the sub menus
7875		overlapControlsInIE:	true		// make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
7876	};
7877
7878})(jQuery);
7879
7880/*
7881 * jQuery Easing v1.4.1 - http://gsgd.co.uk/sandbox/jquery/easing/
7882 * Open source under the BSD License.
7883 * Copyright © 2008 George McGinley Smith
7884 * All rights reserved.
7885 * https://raw.github.com/gdsmith/jquery.easing/master/LICENSE
7886*/
7887
7888/* globals jQuery, define, module, require */
7889(function (factory) {
7890	if (typeof define === "function" && define.amd) {
7891		define(['jquery'], function ($) {
7892			return factory($);
7893		});
7894	} else if (typeof module === "object" && typeof module.exports === "object") {
7895		module.exports = factory(require('jquery'));
7896	} else {
7897		factory(jQuery);
7898	}
7899})(function($){
7900
7901	// Preserve the original jQuery "swing" easing as "jswing"
7902	if (typeof $.easing !== 'undefined') {
7903		$.easing['jswing'] = $.easing['swing'];
7904	}
7905
7906	var pow = Math.pow,
7907		sqrt = Math.sqrt,
7908		sin = Math.sin,
7909		cos = Math.cos,
7910		PI = Math.PI,
7911		c1 = 1.70158,
7912		c2 = c1 * 1.525,
7913		c3 = c1 + 1,
7914		c4 = ( 2 * PI ) / 3,
7915		c5 = ( 2 * PI ) / 4.5;
7916
7917	// x is the fraction of animation progress, in the range 0..1
7918	function bounceOut(x) {
7919		var n1 = 7.5625,
7920			d1 = 2.75;
7921		if ( x < 1/d1 ) {
7922			return n1*x*x;
7923		} else if ( x < 2/d1 ) {
7924			return n1*(x-=(1.5/d1))*x + .75;
7925		} else if ( x < 2.5/d1 ) {
7926			return n1*(x-=(2.25/d1))*x + .9375;
7927		} else {
7928			return n1*(x-=(2.625/d1))*x + .984375;
7929		}
7930	}
7931
7932	$.extend( $.easing, {
7933		def: 'easeOutQuad',
7934		swing: function (x) {
7935			return $.easing[$.easing.def](x);
7936		},
7937		easeInQuad: function (x) {
7938			return x * x;
7939		},
7940		easeOutQuad: function (x) {
7941			return 1 - ( 1 - x ) * ( 1 - x );
7942		},
7943		easeInOutQuad: function (x) {
7944			return x < 0.5 ?
7945				2 * x * x :
7946				1 - pow( -2 * x + 2, 2 ) / 2;
7947		},
7948		easeInCubic: function (x) {
7949			return x * x * x;
7950		},
7951		easeOutCubic: function (x) {
7952			return 1 - pow( 1 - x, 3 );
7953		},
7954		easeInOutCubic: function (x) {
7955			return x < 0.5 ?
7956				4 * x * x * x :
7957				1 - pow( -2 * x + 2, 3 ) / 2;
7958		},
7959		easeInQuart: function (x) {
7960			return x * x * x * x;
7961		},
7962		easeOutQuart: function (x) {
7963			return 1 - pow( 1 - x, 4 );
7964		},
7965		easeInOutQuart: function (x) {
7966			return x < 0.5 ?
7967				8 * x * x * x * x :
7968				1 - pow( -2 * x + 2, 4 ) / 2;
7969		},
7970		easeInQuint: function (x) {
7971			return x * x * x * x * x;
7972		},
7973		easeOutQuint: function (x) {
7974			return 1 - pow( 1 - x, 5 );
7975		},
7976		easeInOutQuint: function (x) {
7977			return x < 0.5 ?
7978				16 * x * x * x * x * x :
7979				1 - pow( -2 * x + 2, 5 ) / 2;
7980		},
7981		easeInSine: function (x) {
7982			return 1 - cos( x * PI/2 );
7983		},
7984		easeOutSine: function (x) {
7985			return sin( x * PI/2 );
7986		},
7987		easeInOutSine: function (x) {
7988			return -( cos( PI * x ) - 1 ) / 2;
7989		},
7990		easeInExpo: function (x) {
7991			return x === 0 ? 0 : pow( 2, 10 * x - 10 );
7992		},
7993		easeOutExpo: function (x) {
7994			return x === 1 ? 1 : 1 - pow( 2, -10 * x );
7995		},
7996		easeInOutExpo: function (x) {
7997			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
7998				pow( 2, 20 * x - 10 ) / 2 :
7999				( 2 - pow( 2, -20 * x + 10 ) ) / 2;
8000		},
8001		easeInCirc: function (x) {
8002			return 1 - sqrt( 1 - pow( x, 2 ) );
8003		},
8004		easeOutCirc: function (x) {
8005			return sqrt( 1 - pow( x - 1, 2 ) );
8006		},
8007		easeInOutCirc: function (x) {
8008			return x < 0.5 ?
8009				( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 :
8010				( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2;
8011		},
8012		easeInElastic: function (x) {
8013			return x === 0 ? 0 : x === 1 ? 1 :
8014				-pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 );
8015		},
8016		easeOutElastic: function (x) {
8017			return x === 0 ? 0 : x === 1 ? 1 :
8018				pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1;
8019		},
8020		easeInOutElastic: function (x) {
8021			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
8022				-( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 :
8023				pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1;
8024		},
8025		easeInBack: function (x) {
8026			return c3 * x * x * x - c1 * x * x;
8027		},
8028		easeOutBack: function (x) {
8029			return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 );
8030		},
8031		easeInOutBack: function (x) {
8032			return x < 0.5 ?
8033				( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 :
8034				( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2;
8035		},
8036		easeInBounce: function (x) {
8037			return 1 - bounceOut( 1 - x );
8038		},
8039		easeOutBounce: bounceOut,
8040		easeInOutBounce: function (x) {
8041			return x < 0.5 ?
8042				( 1 - bounceOut( 1 - 2 * x ) ) / 2 :
8043				( 1 + bounceOut( 2 * x - 1 ) ) / 2;
8044		}
8045	});
8046	return $;
8047});
8048
8049(function($, window, undefined) {
8050    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
8051    // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
8052 
8053    // requestAnimationFrame polyfill by Erik Möller
8054    // fixes from Paul Irish and Tino Zijdel
8055 
8056    var lastTime = 0,
8057        running,
8058        animate = function (elem) {
8059            if (running) {
8060                window.requestAnimationFrame(animate, elem);
8061                jQuery.fx.tick();
8062            }
8063        },
8064        vendors = ['ms', 'moz', 'webkit', 'o'];
8065 
8066    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
8067        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
8068        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
8069            || window[vendors[x]+'CancelRequestAnimationFrame'];
8070    }
8071 
8072    if (!window.requestAnimationFrame)
8073        window.requestAnimationFrame = function(fn, element) {
8074            var currTime = new Date().getTime(),
8075                delta = currTime - lastTime,
8076                timeToCall = Math.max(0, 16 - delta);
8077 
8078            var id = window.setTimeout(function() {
8079                    fn(currTime + timeToCall);
8080                },
8081                timeToCall
8082            );
8083 
8084            lastTime = currTime + timeToCall;
8085 
8086            return id;
8087        };
8088 
8089    if (!window.cancelAnimationFrame) {
8090        window.cancelAnimationFrame = function(id) {
8091            clearTimeout(id);
8092        };
8093    }
8094 
8095    jQuery.fx.timer = function (timer) {
8096        if (timer() && jQuery.timers.push(timer) && !running) {
8097            running = true;
8098            animate(timer.elem);
8099        }
8100    };
8101 
8102    jQuery.fx.stop = function() {
8103        running = false;
8104    };
8105 
8106}(jQuery, this));
8107/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
8108 * Licensed under the MIT License (LICENSE.txt).
8109 *
8110 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
8111 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
8112 * Thanks to: Seamus Leahy for adding deltaX and deltaY
8113 *
8114 * Version: 3.0.6
8115 *
8116 * Requires: 1.2.2+
8117 */
8118(function($) {
8119    var types = ['DOMMouseScroll', 'mousewheel'];
8120    if ($.event.fixHooks) {
8121        for (var i = types.length; i;) {
8122            $.event.fixHooks[types[--i]] = $.event.mouseHooks;
8123        }
8124    }
8125    $.event.special.mousewheel = {
8126        setup: function() {
8127            if (this.addEventListener) {
8128                for (var i = types.length; i;) {
8129                    this.addEventListener(types[--i], handler, false);
8130                }
8131            } else {
8132                this.onmousewheel = handler;
8133            }
8134        },
8135        teardown: function() {
8136            if (this.removeEventListener) {
8137                for (var i = types.length; i;) {
8138                    this.removeEventListener(types[--i], handler, false);
8139                }
8140            } else {
8141                this.onmousewheel = null;
8142            }
8143        }
8144    };
8145    $.fn.extend({
8146        mousewheel: function(fn) {
8147            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
8148        },
8149        unmousewheel: function(fn) {
8150            return this.unbind("mousewheel", fn);
8151        }
8152    });
8153
8154    function handler(event) {
8155        var orgEvent = event || window.event,
8156            args = [].slice.call(arguments, 1),
8157            delta = 0,
8158            returnValue = true,
8159            deltaX = 0,
8160            deltaY = 0;
8161        event = $.event.fix(orgEvent);
8162        event.type = "mousewheel";
8163        // Old school scrollwheel delta
8164        if (orgEvent.wheelDelta) {
8165            delta = orgEvent.wheelDelta / 120;
8166        }
8167        if (orgEvent.detail) {
8168            delta = -orgEvent.detail / 3;
8169        }
8170        // New school multidimensional scroll (touchpads) deltas
8171        deltaY = delta;
8172        // Gecko
8173        if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
8174            deltaY = 0;
8175            deltaX = -1 * delta;
8176        }
8177        // Webkit
8178        if (orgEvent.wheelDeltaY !== undefined) {
8179            deltaY = orgEvent.wheelDeltaY / 120;
8180        }
8181        if (orgEvent.wheelDeltaX !== undefined) {
8182            deltaX = -1 * orgEvent.wheelDeltaX / 120;
8183        }
8184        // Add event and delta to the front of the arguments
8185        args.unshift(event, delta, deltaX, deltaY);
8186        return ($.event.dispatch || $.event.handle).apply(this, args);
8187    }
8188})(jQuery);
8189/**
8190 * jQuery iLightBox - Revolutionary Lightbox Plugin
8191 * http://www.ilightbox.net/
8192 *
8193 * @version: 2.2.4 - October 14, 2017
8194 *
8195 * @author: iProDev (Hemn Chawroka)
8196 *          http://www.iprodev.com/
8197 *
8198 */
8199(function($, window, undefined) {
8200
8201	var extensions = {
8202			flash: ['swf'],
8203			image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'],
8204			iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'],
8205			video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v']
8206		},
8207
8208		// Global DOM elements
8209		$win = $(window),
8210		$doc = $(document),
8211
8212		// Support indicators
8213		browser,
8214		transform,
8215		gpuAcceleration,
8216		fullScreenApi = '',
8217		userAgent = navigator.userAgent || navigator.vendor || window.opera,
8218        supportTouch = "ontouchstart" in window || navigator.msMaxTouchPoints || (navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1),
8219        ishybrid = navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1,
8220        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 )|
8220sy(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)),
8221
8222		// Events
8223		clickEvent = ishybrid ? "itap.iLightBox click.iLightBox" : supportTouch ? "itap.iLightBox" : "click.iLightBox",
8224		touchStartEvent = ishybrid ? "touchstart.iLightBox mousedown.iLightBox" : supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox",
8225		touchStopEvent = ishybrid ? "touchend.iLightBox mouseup.iLightBox" : supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox",
8226		touchMoveEvent = ishybrid ? "touchmove.iLightBox mousemove.iLightBox" : supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox",
8227
8228		// Math shorthands
8229		abs = Math.abs,
8230		sqrt = Math.sqrt,
8231		round = Math.round,
8232		max = Math.max,
8233		min = Math.min,
8234		floor = Math.floor,
8235		random = Math.random,
8236
8237		pluginspages = {
8238			quicktime: 'http://www.apple.com/quicktime/download',
8239			flash: 'http://www.adobe.com/go/getflash'
8240		},
8241
8242		iLightBox = function(el, options, items, instant) {
8243			var iL = this;
8244
8245			iL.options = options,
8246				iL.selector = options.selector || el,
8247				iL.context = document,
8248				iL.instant = instant;
8249
8250			if (items.length < 1) iL.attachItems();
8251			else iL.items = items;
8252
8253			iL.vars = {
8254				total: iL.items.length,
8255				start: 0,
8256				current: null,
8257				next: null,
8258				prev: null,
8259				BODY: $('body'),
8260				loadRequests: 0,
8261				overlay: $('<div class="ilightbox-overlay"></div>'),
8262				loader: $('<div class="ilightbox-loader"><div></div></div>'),
8263				toolbar: $('<div class="ilightbox-toolbar"></div>'),
8264				innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'),
8265				title: $('<div class="ilightbox-title"></div>'),
8266				closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'),
8267				fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'),
8268				innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'),
8269				innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'),
8270				innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'),
8271				holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
8272				nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
8273				prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
8274				nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'),
8275				prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
8276				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>'),
8277				thumbs: false,
8278				nextLock: false,
8279				prevLock: false,
8280				hashLock: false,
8281				isMobile: false,
8282				mobileMaxWidth: 980,
8283				isInFullScreen: false,
8284				isSwipe: false,
8285				mouseID: 0,
8286				cycleID: 0,
8287				isPaused: 0,
8288				captionHeight: 39,
8289			};
8290
8291			// Hideable elements with mousemove event
8292			iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton);
8293
8294			iL.normalizeItems();
8295
8296			//Check necessary plugins
8297			iL.availPlugins();
8298
8299			//Set startFrom
8300			iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom;
8301
8302			//If randomStart
8303			iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom;
8304			iL.vars.start = iL.options.startFrom;
8305
8306			if (instant) iL.instantCall();
8307			else iL.patchItemsEvents();
8308
8309			if (iL.options.linkId) {
8310				iL.hashChangeHandler();
8311				$win.iLightBoxHashChange(function() {
8312					iL.hashChangeHandler();
8313				});
8314			}
8315
8316			if (supportTouch) {
8317				var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig,
8318					replace = "itap";
8319				iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace),
8320					iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace),
8321					iL.options.social.show = iL.options.social.show.replace(RegExp, replace),
8322					iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace);
8323			}
8324
8325			if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) {
8326				$.extend(iL.options.styles, {
8327					nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
8328					prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
8329					nextOpacity: 0,
8330					prevOpacity: 0
8331				});
8332			}
8333		};
8334
8335	//iLightBox helpers
8336	iLightBox.prototype = {
8337		showLoader: function() {
8338			var iL = this;
8339			iL.vars.loadRequests += 1;
8340			if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({
8341				//top: '-30px'
8342				opacity: '1'
8343			}, iL.options.show.speed, 'easeOutCirc');
8344			else iL.vars.loader.addClass('ilightbox-show').stop().animate({
8345				//left: '-30px'
8346				opacity: '1'
8347			}, iL.options.show.speed, 'easeOutCirc');
8348		},
8349
8350		hideLoader: function() {
8351			var iL = this;
8352			iL.vars.loadRequests -= 1;
8353			iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests;
8354			if (iL.options.path.toLowerCase() == "horizontal") {
8355				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
8356					//top: '-192px'
8357					opacity: '0'
8358				}, iL.options.show.speed, 'easeInCirc');
8359			} else {
8360				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
8361					//left: '-192px'
8362					opacity: '0'
8363				}, iL.options.show.speed, 'easeInCirc');
8364			}
8365		},
8366
8367		createUI: function() {
8368			var iL = this;
8369
8370			iL.ui = {
8371				currentElement: iL.vars.holder,
8372				nextElement: iL.vars.nextPhoto,
8373				prevElement: iL.vars.prevPhoto,
8374				currentItem: iL.vars.current,
8375				nextItem: iL.vars.next,
8376				prevItem: iL.vars.prev,
8377				hide: function() {
8378					iL.closeAction();
8379				},
8380				refresh: function() {
8381					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
8382				},
8383				fullscreen: function() {
8384					iL.fullScreenAction();
8385				}
8386			};
8387		},
8388
8389		attachItems: function() {
8390			var iL = this,
8391				itemsObject = new Array(),
8392				items = new Array();
8393
8394			$(iL.selector, iL.context).each(function() {
8395				var t = $(this),
8396					URL = t.attr(iL.options.attr) || null,
8397					options = t.data("options") && eval("({" + t.data("options") + "})") || {},
8398					caption = t.data('caption'),
8399					title = t.data('title'),
8400					type = t.data('type') || getTypeByExtension(URL),
8401					clone = t.data('lbox-clone') || false;
8402
8403				//Uncode addition ##START##
8404				if (type === false) {
8405					return;
8406				}
8407				//Uncode addition ##END##
8408
8409				if (t.data('lbox-clone') != undefined) return;
8410
8411				//Uncode addition ##START##
8412				if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) {
8413					var ALBUM_URLS = JSON.parse(t.attr('data-album')),
8414						URL_i,
8415						URLS_LENGHT = ALBUM_URLS.length;
8416
8417					for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) {
8418						if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) {
8419							var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\'';
8420							item_opts = item_opts && eval("({" + item_opts + "})") || {},
8421							items.push({
8422								URL: ALBUM_URLS[URL_i].url,
8423								caption: ALBUM_URLS[URL_i].caption,
8424								title: ALBUM_URLS[URL_i].title,
8425								type: getTypeByExtension(ALBUM_URLS[URL_i].url),
8426								options: item_opts,
8427								clone: clone
8428							});
8429							var newT = t;
8430							newT.attr('href',ALBUM_URLS[URL_i].url);
8431							if (!iL.instant) itemsObject.push(newT);
8432						}
8433					}
8434				} else {
8435				//Uncode addition ##END##
8436					items.push({
8437						URL: URL,
8438						caption: caption,
8439						title: title,
8440						type: type,
8441						options: options,
8442						clone: clone
8443					});
8444				}
8445
8446
8447				if (iL.vars != undefined) iL.vars.total = items.length;
8448
8449				if (!iL.instant) itemsObject.push(t);
8450			});
8451
8452			iL.items = items,
8453				iL.itemsObject = itemsObject;
8454
8455		},
8456
8457		normalizeItems: function() {
8458			var iL = this,
8459				newItems = new Array();
8460
8461			$.each(iL.items, function(key, val) {
8462
8463				if (typeof val == "string") val = {
8464					url: val
8465				};
8466
8467				var URL = val.url || val.URL || null,
8468					options = val.options || {},
8469					caption = val.caption || null,
8470					title = val.title || null,
8471					type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL),
8472					ext = (typeof URL != 'object') ? getExtension(URL) : '';
8473
8474				options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
8475				options.videoType = options.videoType || null,
8476				options.skin = options.skin || iL.options.skin,
8477				options.width = options.width || null,
8478				options.height = options.height || null,
8479				options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true,
8480				options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true,
8481				options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons);
8482
8483				if (type == "video") {
8484					options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {};
8485
8486					options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null;
8487					options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls";
8488					options.html5video.preload = options.html5video.preload || "metadata";
8489					options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false;
8490					//UNCODE addition
8491					options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false;
8492				}
8493
8494				if (!options.width || !options.height) {
8495					if (type == "video") options.width = 1280, options.height = 720;
8496					else if (type == "iframe") options.width = '100%', options.height = '90%';
8497					else if (type == "flash") options.width = 1280, options.height = 720;
8498				}
8499
8500				delete val.url;
8501				val.index = key;
8502				val.URL = URL;
8503				val.caption = caption;
8504				val.title = title;
8505				val.type = type;
8506				val.options = options;
8507				val.ext = ext;
8508
8509				newItems.push(val);
8510			});
8511
8512			iL.items = newItems;
8513		},
8514
8515		instantCall: function() {
8516			var iL = this,
8517				key = iL.vars.start;
8518
8519			iL.vars.current = key;
8520			iL.vars.next = (iL.items[key + 1]) ? key + 1 : null;
8521			iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null;
8522
8523			iL.addContents();
8524			iL.patchEvents();
8525		},
8526
8527		addContents: function() {
8528			var iL = this,
8529				vars = iL.vars,
8530				opts = iL.options,
8531				viewport = getViewport(),
8532				path = opts.path.toLowerCase(),
8533				recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) {
8534					return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition);
8535				}),
8536				needRecognition = recognizingItems.length > 0;
8537
8538			if (opts.mobileOptimizer && !opts.innerToolbar)
8539				vars.isMobile = viewport.width <= vars.mobileMaxWidth;
8540
8541			vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity);
8542
8543			if (opts.linkId)
8544				vars.overlay[0].setAttribute('linkid', opts.linkId);
8545
8546			//Add Toolbar Buttons
8547			if (opts.controls.toolbar) {
8548				vars.toolbar.addClass(opts.skin).append(vars.closeButton);
8549				if (opts.controls.fullscreen)
8550					vars.toolbar.append(vars.fullScreenButton);
8551				if (opts.controls.slideshow)
8552					vars.toolbar.append(vars.innerPlayButton);
8553				if (vars.total > 1)
8554					vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton);
8555			}
8556
8557			//Append elements to body
8558			vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto);
8559
8560			if (!opts.innerToolbar)
8561				vars.BODY.append(vars.toolbar);
8562			if (opts.controls.arrows)
8563				vars.BODY.append(vars.nextButton).append(vars.prevButton);
8564
8565			if (opts.controls.thumbnail && vars.total > 1) {
8566				vars.BODY.append(vars.thumbnails);
8567				vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path);
8568				$('div.ilightbox-thumbnails-grid', vars.thumbnails).empty();
8569				vars.thumbs = true;
8570			}
8571
8572			//Configure loader and arrows
8573			var loaderCss = (opts.path.toLowerCase() == "horizontal") ? {
8574				left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2))
8575			} : {
8576				top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2))
8577			};
8578			vars.loader.addClass(opts.skin).css(loaderCss);
8579			vars.nextButton.add(vars.prevButton).addClass(opts.skin);
8580			if (path == "horizontal")
8581				vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal');
8582
8583			// Configure arrow buttons
8584			vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
8585
8586			if (!opts.infinite) {
8587				vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8588
8589				if (vars.current == 0)
8590					vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8591				if (vars.current >= vars.total - 1)
8592					vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8593			}
8594
8595			if (opts.show.effect) {
8596				vars.overlay.stop().fadeIn(opts.show.speed);
8597				vars.toolbar.stop().fadeIn(opts.show.speed);
8598			} else {
8599				vars.overlay.show();
8600				vars.toolbar.show();
8601			}
8602
8603			var length = recognizingItems.length;
8604			if (needRecognition) {
8605				iL.showLoader();
8606
8607				$.each(recognizingItems, function(key, val) {
8608					var resultFnc = function(result) {
8609							var key = -1,
8610								filter = iL.items.filter(function(e, i, arr) {
8611									if (e.URL == result.url)
8612										key = i;
8613
8614									return e.URL == result.url;
8615								}),
8616								self = iL.items[key];
8617
8618							if (result)
8619								$.extend(true, self, {
8620									URL: result.source,
8621									type: result.type,
8622									recognized: true,
8623									options: {
8624										html5video: result.html5video,
8625										width: (result.type == "image") ? 0 : (result.width || self.width),
8626										height: (result.type == "image") ? 0 : (result.height || self.height),
8627										thumbnail: self.options.thumbnail || result.thumbnail
8628									}
8629								});
8630
8631							length--;
8632
8633							if (length == 0) {
8634								iL.hideLoader();
8635
8636								vars.dontGenerateThumbs = false;
8637								iL.generateThumbnails();
8638
8639								if (opts.show.effect)
8640									setTimeout(function() {
8641										iL.generateBoxes();
8642									}, opts.show.speed);
8643								else
8644									iL.generateBoxes();
8645							}
8646						};
8647
8648					iL.ogpRecognition(this, resultFnc);
8649				});
8650			}
8651			else {
8652				if (opts.show.effect)
8653					setTimeout(function() {
8654						iL.generateBoxes();
8655					}, opts.show.speed);
8656				else
8657					iL.generateBoxes();
8658			}
8659
8660			iL.createUI();
8661
8662			window.iLightBox = {
8663				close: function() {
8664					iL.closeAction();
8665				},
8666				fullscreen: function() {
8667					iL.fullScreenAction();
8668				},
8669				moveNext: function() {
8670					iL.moveTo('next');
8671				},
8672				movePrev: function() {
8673					iL.moveTo('prev');
8674				},
8675				goTo: function(index) {
8676					iL.goTo(index);
8677				},
8678				refresh: function() {
8679					iL.refresh();
8680				},
8681				reposition: function() {
8682					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
8683				},
8684				setOption: function(options) {
8685					iL.setOption(options);
8686				},
8687				destroy: function() {
8688					iL.closeAction();
8689					iL.dispatchItemsEvents();
8690				}
8691			};
8692
8693			if (opts.linkId) {
8694				vars.hashLock = true;
8695				window.location.hash = opts.linkId + '/' + vars.current;
8696				setTimeout(function() {
8697					vars.hashLock = false;
8698				}, 55);
8699			}
8700
8701			if (!opts.slideshow.startPaused) {
8702				iL.resume();
8703				vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause');
8704			}
8705
8706			//Trigger the onOpen callback
8707			if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL);
8708		},
8709
8710		loadContent: function(obj, opt, speed) {
8711			var iL = this,
8712				holder, item;
8713
8714			iL.createUI();
8715
8716			obj.speed = speed || iL.options.effects.loadedFadeSpeed;
8717
8718			if (opt == 'current') {
8719				if (!obj.options.mousewheel) iL.vars.lockWheel = true;
8720				else iL.vars.lockWheel = false;
8721
8722				if (!obj.options.swipe) iL.vars.lockSwipe = true;
8723				else iL.vars.lockSwipe = false;
8724			}
8725
8726			switch (opt) {
8727				case 'current':
8728					holder = iL.vars.holder, item = iL.vars.current;
8729					break;
8730				case 'next':
8731					holder = iL.vars.nextPhoto, item = iL.vars.next;
8732					break;
8733				case 'prev':
8734					holder = iL.vars.prevPhoto, item = iL.vars.prev;
8735					break;
8736			}
8737
8738			holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin);
8739			$('div.ilightbox-inner-toolbar', holder).remove();
8740
8741			if (obj.title || iL.options.innerToolbar) {
8742				var innerToolbar = iL.vars.innerToolbar.clone();
8743				if (obj.title && iL.options.show.title) {
8744					var title = iL.vars.title.clone();
8745					title.empty().html(obj.title);
8746					innerToolbar.append(title);
8747				}
8748				if (iL.options.innerToolbar) {
8749					innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar);
8750				}
8751				holder.prepend(innerToolbar);
8752			}
8753
8754			//console.warn('loadContent', arguments);
8755
8756			iL.loadSwitcher(obj, holder, item, opt);
8757		},
8758
8759		loadSwitcher: function(obj, holder, item, opt) {
8760			var iL = this,
8761				opts = iL.options,
8762				api = {
8763					element: holder,
8764					position: item
8765				};
8766
8767			switch (obj.type) {
8768				case 'image':
8769					//Trigger the onBeforeLoad callback
8770					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8771					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8772
8773					iL.loadImage(obj.URL, function(img) {
8774						//Trigger the onAfterLoad callback
8775						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8776						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8777
8778						var width = (img) ? img.width : 400,
8779							height = (img) ? img.height : 200;
8780
8781						holder.data({
8782							naturalWidth: width,
8783							naturalHeight: height
8784						});
8785
8786						$('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>');
8787
8788						//Trigger the onRender callback
8789						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8790						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8791
8792						iL.configureHolder(obj, opt, holder);
8793					});
8794
8795					break;
8796
8797				case 'video':
8798					holder.data({
8799						naturalWidth: obj.options.width,
8800						naturalHeight: obj.options.height
8801					});
8802
8803					if (opt === 'current') {
8804						iL.addContent(holder, obj);
8805
8806						//Trigger the onRender callback
8807						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8808						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8809					} else {
8810						$('div.ilightbox-container', holder).empty();
8811					}
8812
8813					iL.configureHolder(obj, opt, holder);
8814
8815					break;
8816
8817				case 'iframe':
8818					//iL.showLoader();
8819					holder.data({
8820						naturalWidth: obj.options.width,
8821						naturalHeight: obj.options.height
8822					});
8823
8824					iL.configureHolder(obj, opt, holder);
8825
8826					if (opt === 'current') {
8827						var el = iL.addContent(holder, obj);
8828
8829						//Trigger the onRender callback
8830						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8831						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8832
8833						//Trigger the onBeforeLoad callback
8834						if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8835						if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8836
8837						el.bind('load', function() {
8838							//Trigger the onAfterLoad callback
8839							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8840							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8841
8842							//iL.hideLoader();
8843							el.unbind('load');
8844						});
8845					} else {
8846						$('div.ilightbox-container', holder).empty();
8847					}
8848
8849					break;
8850
8851				case 'inline':
8852					var el = $(obj.URL),
8853						content = iL.addContent(holder, obj),
8854						images = findImageInElement(holder);
8855
8856					holder.data({
8857						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
8858						naturalHeight: (iL.items[item].options.height || el.outerHeight())
8859					});
8860					content.children().eq(0).show();
8861
8862					//Trigger the onRender callback
8863					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8864					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8865
8866					//Trigger the onBeforeLoad callback
8867					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8868					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8869
8870					iL.loadImage(images, function() {
8871						//Trigger the onAfterLoad callback
8872						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8873						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8874
8875						iL.configureHolder(obj, opt, holder);
8876					});
8877
8878					break;
8879
8880				case 'flash':
8881					var el = iL.addContent(holder, obj);
8882
8883					holder.data({
8884						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
8885						naturalHeight: (iL.items[item].options.height || el.outerHeight())
8886					});
8887
8888					//Trigger the onRender callback
8889					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8890					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8891
8892					iL.configureHolder(obj, opt, holder);
8893
8894					break;
8895
8896				case 'ajax':
8897					var ajax = obj.options.ajax || {};
8898					//Trigger the onBeforeLoad callback
8899					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8900					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8901
8902					iL.showLoader();
8903					$.ajax({
8904						url: obj.URL || opts.ajaxSetup.url,
8905						data: ajax.data || null,
8906						dataType: ajax.dataType || "html",
8907						type: ajax.type || opts.ajaxSetup.type,
8908						cache: ajax.cache || opts.ajaxSetup.cache,
8909						crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain,
8910						global: ajax.global || opts.ajaxSetup.global,
8911						ifModified: ajax.ifModified || opts.ajaxSetup.ifModified,
8912						username: ajax.username || opts.ajaxSetup.username,
8913						password: ajax.password || opts.ajaxSetup.password,
8914						beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend,
8915						complete: ajax.complete || opts.ajaxSetup.complete,
8916						success: function(data, textStatus, jqXHR) {
8917							iL.hideLoader();
8918
8919							var el = $(data),
8920								container = $('div.ilightbox-container', holder),
8921								elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')),
8922								elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')),
8923								css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? {
8924									'overflow': 'hidden'
8925								} : {};
8926
8927							container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el));
8928							holder.show().data({
8929								naturalWidth: (elWidth || container.outerWidth()),
8930								naturalHeight: (elHeight || container.outerHeight())
8931							}).hide();
8932
8933							//Trigger the onRender callback
8934							if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8935							if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8936
8937							var images = findImageInElement(holder);
8938							iL.loadImage(images, function() {
8939								//Trigger the onAfterLoad callback
8940								if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8941								if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8942
8943								iL.configureHolder(obj, opt, holder);
8944							});
8945
8946							opts.ajaxSetup.success(data, textStatus, jqXHR);
8947							if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR);
8948						},
8949						error: function(jqXHR, textStatus, errorThrown) {
8950							//Trigger the onAfterLoad callback
8951							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8952							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8953
8954							iL.hideLoader();
8955							$('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>');
8956							iL.configureHolder(obj, opt, holder);
8957
8958							opts.ajaxSetup.error(jqXHR, textStatus, errorThrown);
8959							if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown);
8960						}
8961					});
8962
8963					break;
8964
8965				case 'html':
8966					var object = obj.URL,
8967						el
8968					container = $('div.ilightbox-container', holder);
8969
8970					if (object[0].nodeName) el = object.clone();
8971					else {
8972						var dom = $(object);
8973						if (dom.selector) el = $('<div>' + dom + '</div>');
8974						else el = dom;
8975					}
8976
8977					var elWidth = iL.items[item].options.width || parseInt(el.attr('width')),
8978						elHeight = iL.items[item].options.height || parseInt(el.attr('height'));
8979
8980					iL.addContent(holder, obj);
8981
8982					el.appendTo(document.documentElement).hide();
8983
8984					//Trigger the onRender callback
8985					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
8986					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
8987
8988					var images = findImageInElement(holder);
8989
8990					//Trigger the onBeforeLoad callback
8991					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
8992					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
8993
8994					iL.loadImage(images, function() {
8995						//Trigger the onAfterLoad callback
8996						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
8997						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
8998
8999						holder.show().data({
9000							naturalWidth: (elWidth || container.outerWidth()),
9001							naturalHeight: (elHeight || container.outerHeight())
9002						}).hide();
9003						el.remove();
9004
9005						iL.configureHolder(obj, opt, holder);
9006					});
9007
9008					break;
9009			}
9010		},
9011
9012		configureHolder: function(obj, opt, holder) {
9013			var iL = this,
9014				vars = iL.vars,
9015				opts = iL.options;
9016
9017			if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev');
9018
9019			if (opt == "current")
9020				var item = vars.current;
9021			else if (opt == "next")
9022				var opacity = opts.styles.nextOpacity,
9023					item = vars.next;
9024			else
9025				var opacity = opts.styles.prevOpacity,
9026					item = vars.prev;
9027
9028			var api = {
9029				element: holder,
9030				position: item
9031			};
9032
9033			iL.items[item].options.width = iL.items[item].options.width || 0,
9034			iL.items[item].options.height = iL.items[item].options.height || 0;
9035
9036			if (opt == "current") {
9037				if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() {
9038					holder.css(transform, '');
9039					if (obj.caption) {
9040						iL.setCaption(obj, holder);
9041						var caption = $('div.ilightbox-caption', holder),
9042							percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100);
9043						if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
9043Speed);
9044					}
9045
9046					var social = obj.options.social;
9047					if (social) {
9048						iL.setSocial(social, obj.URL, holder);
9049						if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed);
9050					}
9051
9052					//Generate thumbnails
9053					iL.generateThumbnails();
9054
9055					//Trigger the onShow callback
9056					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9057					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9058				});
9059				else {
9060					holder.show();
9061
9062					//Generate thumbnails
9063					iL.generateThumbnails();
9064
9065					//Trigger the onShow callback
9066					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9067					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9068				}
9069			} else {
9070				if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() {
9071					if (opt == "next") vars.nextLock = false;
9072					else vars.prevLock = false;
9073
9074					//Generate thumbnails
9075					iL.generateThumbnails();
9076
9077					//Trigger the onShow callback
9078					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9079					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9080				});
9081				else {
9082					holder.css({
9083						opacity: opacity
9084					}).show();
9085					if (opt == "next") vars.nextLock = false;
9086					else vars.prevLock = false;
9087
9088					//Generate thumbnails
9089					iL.generateThumbnails();
9090
9091					//Trigger the onShow callback
9092					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
9093					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
9094				}
9095			}
9096
9097			setTimeout(function() {
9098				iL.repositionPhoto();
9099			}, 0);
9100		},
9101
9102		generateBoxes: function() {
9103			var iL = this,
9104				vars = iL.vars,
9105				opts = iL.options;
9106
9107			if (opts.infinite && vars.total >= 3) {
9108				if (vars.current == vars.total - 1) vars.next = 0;
9109				if (vars.current == 0) vars.prev = vars.total - 1;
9110			} else opts.infinite = false;
9111
9112			//UNCODE addition
9113			if ( typeof iL.items[vars.current] == 'undefined' )
9114				vars.current = 0;
9115
9116			iL.loadContent(iL.items[vars.current], 'current', opts.show.speed);
9117
9118			if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed);
9119			if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed);
9120		},
9121
9122		generateThumbnails: function() {
9123			var iL = this,
9124				vars = iL.vars,
9125				opts = iL.options,
9126				timeOut = null;
9127
9128			if (vars.thumbs && !iL.vars.dontGenerateThumbs) {
9129				var thumbnails = vars.thumbnails,
9130					container = $('div.ilightbox-thumbnails-container', thumbnails),
9131					grid = $('div.ilightbox-thumbnails-grid', container),
9132					i = 0;
9133
9134				grid.removeAttr('style').empty();
9135
9136				$.each(iL.items, function(key, val) {
9137					var isActive = (vars.current == key) ? 'ilightbox-active' : '',
9138						opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity,
9139						thumb = val.options.thumbnail,
9140						thumbnail = $('<div class="ilightbox-thumbnail"></div>'),
9141						icon = $('<div class="ilightbox-thumbnail-icon"></div>');
9142
9143					thumbnail.css({
9144						opacity: 0
9145					}).addClass(isActive);
9146
9147					if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') {
9148						icon.addClass('ilightbox-thumbnail-video');
9149						thumbnail.append(icon);
9150					} else if (val.options.icon) {
9151						icon.addClass('ilightbox-thumbnail-' + val.options.icon);
9152						thumbnail.append(icon);
9153					}
9154
9155					if (thumb) iL.loadImage(thumb, function(img) {
9156						i++;
9157						if (img) thumbnail.data({
9158							naturalWidth: img.width,
9159							naturalHeight: img.height
9160						}).append('<img src="' + thumb + '" border="0" />');
9161						else thumbnail.data({
9162							naturalWidth: opts.thumbnails.maxWidth,
9163							naturalHeight: opts.thumbnails.maxHeight
9164						});
9165
9166						clearTimeout(timeOut);
9167						timeOut = setTimeout(function() {
9168							iL.positionThumbnails(thumbnails, container, grid);
9169						}, 20);
9170						setTimeout(function() {
9171							thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity);
9172						}, i * 20);
9173					});
9174
9175					grid.append(thumbnail);
9176				});
9177				iL.vars.dontGenerateThumbs = true;
9178			}
9179		},
9180
9181		positionThumbnails: function(thumbnails, container, grid) {
9182			var iL = this,
9183				vars = iL.vars,
9184				opts = iL.options,
9185				viewport = getViewport(),
9186				path = opts.path.toLowerCase();
9187
9188			if (!thumbnails) thumbnails = vars.thumbnails;
9189			if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails);
9190			if (!grid) grid = $('div.ilightbox-thumbnails-grid', container);
9191
9192			var thumbs = $('.ilightbox-thumbnail', grid),
9193				widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX,
9194				heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY,
9195				gridWidth = (path == 'horizontal') ? 0 : widthAvail,
9196				gridHeight = (path == 'horizontal') ? heightAvail : 0,
9197				active = $('.ilightbox-active', grid),
9198				gridCss = {},
9199				css = {};
9200
9201			if (arguments.length < 3) {
9202				thumbs.css({
9203					opacity: opts.thumbnails.normalOpacity
9204				});
9205				active.css({
9206					opacity: opts.thumbnails.activeOpacity
9207				});
9208			}
9209
9210			thumbs.each(function(i) {
9211				var t = $(this),
9212					data = t.data(),
9213					width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth;
9214				height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0;
9215				dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true);
9216
9217				t.css({
9218					width: dims.width,
9219					height: dims.height
9220				});
9221				if (path == 'horizontal') t.css({
9222					'float': 'left'
9223				});
9224
9225				(path == 'horizontal') ? (
9226					gridWidth += t.outerWidth()
9227				) : (
9228					gridHeight += t.outerHeight()
9229				);
9230			});
9231
9232			gridCss = {
9233				width: gridWidth,
9234				height: gridHeight
9235			};
9236
9237			grid.css(gridCss);
9238
9239			gridCss = {};
9240
9241			var gridOffset = grid.offset(),
9242				activeOffset = (active.length) ? active.offset() : {
9243					top: parseInt(heightAvail / 2),
9244					left: parseInt(widthAvail / 2)
9245				};
9246
9247			gridOffset.top = (gridOffset.top - $doc.scrollTop()),
9248				gridOffset.left = (gridOffset.left - $doc.scrollLeft()),
9249				activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()),
9250				activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft());
9251
9252			(path == 'horizontal') ? (
9253				gridCss.top = 0,
9254				gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2))
9255			) : (
9256				gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))),
9257				gridCss.left = 0
9258			);
9259
9260			if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc');
9261			else grid.css(gridCss);
9262		},
9263
9264		loadImage: function(image, callback) {
9265			if (!$.isArray(image)) image = [image];
9266
9267			var iL = this,
9268				length = image.length;
9269
9270			if (length > 0) {
9271				iL.showLoader();
9272				$.each(image, function(index, value) {
9273					var img = new Image();
9274					img.onload = function() {
9275						length -= 1;
9276						if (length == 0) {
9277							iL.hideLoader();
9278							callback(img);
9279						}
9280					};
9281					img.onerror = img.onabort = function() {
9282						length -= 1;
9283						if (length == 0) {
9284							iL.hideLoader();
9285							callback(false);
9286						}
9287					};
9288					img.src = image[index];
9289				});
9290			} else callback(false);
9291		},
9292
9293		patchItemsEvents: function() {
9294			var iL = this,
9295				vars = iL.vars,
9296				clickEvent = ishybrid ? "itap.iL click.iL" : supportTouch ? "itap.iL" : "click.iL",
9297				vEvent = ishybrid ? "click.iL itap.iL" : supportTouch ? "click.iL" : "itap.iL";
9298
9299			if (iL.context && iL.selector) {
9300				var $items = $(iL.selector, iL.context);
9301
9302				$(iL.context).on(clickEvent, iL.selector, function() {
9303					var $this = $(this),
9304						//UNCODE addition
9305						key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this);
9306					if (UNCODE.isMobile) {
9307						var isCarousel = $this.closest('.owl-carousel');
9308						if (isCarousel.length) {
9309							if (isCarousel.hasClass('owl-translating')) return false;
9310						}
9311					}
9312
9313					vars.current = key;
9314					vars.next = iL.items[key + 1] ? key + 1 : null;
9315					vars.prev = iL.items[key - 1] ? key - 1 : null;
9316
9317					//UNCODE addition
9318					if ( vars.BODY.hasClass('fp-slide-scrolling') )
9319						return false;
9320
9321					iL.addContents();
9322					iL.patchEvents();
9323
9324					return false;
9325				}).on(vEvent, iL.selector, function() {
9326					return false;
9327				});
9328			} else
9329				$.each(iL.itemsObject, function(key, val) {
9330					val.on(clickEvent, function() {
9331						vars.current = key;
9332						vars.next = iL.items[key + 1] ? key + 1 : null;
9333						vars.prev = iL.items[key - 1] ? key - 1 : null;
9334
9335						iL.addContents();
9336						iL.patchEvents();
9337
9338						return false;
9339					}).on(vEvent, function() {
9340						return false;
9341					});
9342				});
9343		},
9344
9345		dispatchItemsEvents: function() {
9346			var iL = this,
9347				vars = iL.vars,
9348				opts = iL.options;
9349
9350			if (iL.context && iL.selector)
9351				$(iL.context).off('.iL', iL.selector);
9352			else
9353				$.each(iL.itemsObject, function(key, val) {
9354					val.off('.iL');
9355				});
9356		},
9357
9358		refresh: function() {
9359			var iL = this;
9360
9361			iL.dispatchItemsEvents();
9362			iL.attachItems();
9363			iL.normalizeItems();
9364			iL.patchItemsEvents();
9365		},
9366
9367		patchEvents: function() {
9368			var iL = this,
9369				vars = iL.vars,
9370				opts = iL.options,
9371				path = opts.path.toLowerCase(),
9372				holders = $('.ilightbox-holder'),
9373				fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox',
9374				durationThreshold = 1000,
9375				horizontalDistanceThreshold =
9376				verticalDistanceThreshold = 100,
9377				buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild];
9378
9379			$win.bind('resize.iLightBox', function() {
9380				var viewport = getViewport();
9381
9382				if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth;
9383				vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
9384
9385				iL.repositionPhoto(null);
9386				if (supportTouch) {
9387					clearTimeout(vars.setTime);
9388					vars.setTime = setTimeout(function() {
9389						var scrollTop = getScrollXY().y;
9390						window.scrollTo(0, scrollTop - 30);
9391						window.scrollTo(0, scrollTop + 30);
9392						window.scrollTo(0, scrollTop);
9393					}, 2000);
9394				}
9395				if (vars.thumbs) iL.positionThumbnails();
9396			}).bind('keydown.iLightBox', function(event) {
9397				if (opts.controls.keyboard) {
9398					switch (event.keyCode) {
9399						case 13:
9400							if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction();
9401							break;
9402						case 27:
9403							if (opts.keyboard.esc) iL.closeAction();
9404							break;
9405						case 37:
9406							if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev');
9407							break;
9408						case 38:
9409							if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev');
9410							break;
9411						case 39:
9412							if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next');
9413							break;
9414						case 40:
9415							if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next');
9416							break;
9417					}
9418				}
9419			});
9420
9421			if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() {
9422				iL.doFullscreen();
9423			});
9424
9425			var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) {
9426					return arr.lastIndexOf(e) === i;
9427				}),
9428				holderEvents = "";
9429
9430			$.each(holderEventsArr, function(key, val) {
9431				if (key != 0) holderEvents += ' ';
9432				holderEvents += val;
9433			});
9434
9435			$doc.on(clickEvent, '.ilightbox-overlay', function() {
9436				if (opts.overlay.blur) iL.closeAction();
9437			}).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() {
9438				iL.moveTo('next');
9439			}).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() {
9440				iL.moveTo('prev');
9441			}).on(clickEvent, '.ilightbox-thumbnail', function() {
9442				var t = $(this),
9443					thumbs = $('.ilightbox-thumbnail', vars.thumbnails),
9444					index = thumbs.index(t);
9445
9446				if (index != vars.current) iL.goTo(index);
9447			}).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
9448				var caption = $('div.ilightbox-caption', vars.holder),
9449					social = $('div.ilightbox-social', vars.holder),
9450					fadeSpeed = opts.effects.fadeSpeed;
9451
9452				if (vars.nextLock || vars.prevLock) {
9453					if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed);
9454					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed);
9455
9456					if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed);
9457					else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed);
9458				} else {
9459					if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed);
9460					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed);
9461
9462					if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed);
9463					else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed);
9464				}
9465			}).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) {
9466				if (e.type == 'mouseenter') vars.lockWheel = true;
9467				else vars.lockWheel = false;
9468			}).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() {
9469				var t = $(this);
9470
9471				if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction();
9472				else if (t.hasClass('ilightbox-play')) {
9473					iL.resume();
9474					t.addClass('ilightbox-pause').removeClass('ilightbox-play');
9475				} else if (t.hasClass('ilightbox-pause')) {
9476					iL.pause();
9477					t.addClass('ilightbox-play').removeClass('ilightbox-pause');
9478				} else iL.closeAction();
9479			}).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) {
9480				// prevent scrolling
9481				e.preventDefault();
9482			});
9483
9484			function mouseMoveHandler(e) {
9485				if (!vars.isMobile) {
9486					if (!vars.mouseID) {
9487						vars.hideableElements.show();
9488					}
9489
9490					vars.mouseID = clearTimeout(vars.mouseID);
9491
9492					if (buttonsArray.indexOf(e.target) === -1)
9493						vars.mouseID = setTimeout(function() {
9494							vars.hideableElements.hide();
9495							vars.mouseID = clearTimeout(vars.mouseID);
9496						}, 3000);
9497				}
9498			}
9499
9500			if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler);
9501
9502			if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
9503				if (e.type == 'mouseenter' && vars.cycleID) iL.pause();
9504				else if (e.type == 'mouseleave' && vars.isPaused) iL.resume();
9505			});
9506
9507			var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'),
9508				delay = false;
9509
9510			if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) {
9511				event.preventDefault();
9512				if (delay) return;
9513				delay = true;
9514				if (!vars.lockWheel) {
9515					event.preventDefault();
9516					if (delta < 0) {
9517						iL.moveTo('next');
9518					} else if (delta > 0) {
9519						iL.moveTo('prev');
9520					}
9521				}
9522				setTimeout(function(){
9523					delay = false;
9524				}, 2000);
9525			});
9526
9527			if (opts.controls.swipe) holders.on(touchStartEvent, function(event) {
9528				if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return;
9529
9530				vars.BODY.addClass('ilightbox-closedhand');
9531
9532				var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event,
9533					scrollTop = $doc.scrollTop(),
9534					scrollLeft = $doc.scrollLeft(),
9535					offsets = [
9536						holders.eq(0).offset(),
9537						holders.eq(1).offset(),
9538						holders.eq(2).offset()
9539					],
9540					offSet = [{
9541						top: offsets[0].top - scrollTop,
9542						left: offsets[0].left - scrollLeft
9543					}, {
9544						top: offsets[1].top - scrollTop,
9545						left: offsets[1].left - scrollLeft
9546					}, {
9547						top: offsets[2].top - scrollTop,
9548						left: offsets[2].left - scrollLeft
9549					}],
9550					start = {
9551						time: (new Date()).getTime(),
9552						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
9553					},
9554					stop;
9555
9556				function moveEachHandler(i) {
9557					var t = $(this),
9558						offset = offSet[i],
9559						scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])];
9560
9561					t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px';
9562				}
9563
9564				function moveHandler(event) {
9565
9566					if (!start) return;
9567
9568					var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event;
9569
9570					stop = {
9571						time: (new Date()).getTime(),
9572						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
9573					};
9574
9575					holders.each(moveEachHandler);
9576
9577					// prevent scrolling
9578					event.preventDefault();
9579				}
9580
9581				function repositionHolders() {
9582					holders.each(function() {
9583						var t = $(this),
9584							offset = t.data('offset') || {
9585								top: t.offset().top - scrollTop,
9586								left: t.offset().left - scrollLeft
9587							},
9588							top = offset.top,
9589							left = offset.left;
9590
9591						t.css(transform, gpuAcceleration).stop().animate({
9592							top: top,
9593							left: left
9594						}, 500, 'easeOutCirc', function() {
9595							t.css(transform, '');
9596						});
9597					});
9598				}
9599
9600				holders.bind(touchMoveEvent, moveHandler);
9601				$doc.one(touchStopEvent, function(event) {
9602					holders.unbind(touchMoveEvent, moveHandler);
9603
9604					vars.BODY.removeClass('ilightbox-closedhand');
9605
9606					if (start && stop) {
9607						if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) {
9608							if (start.coords[0] > stop.coords[0]) {
9609								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
9610								else {
9611									vars.isSwipe = true;
9612									iL.moveTo('next');
9613								}
9614							} else {
9615								if (vars.current == 0 && !opts.infinite) repositionHolders();
9616								else {
9617									vars.isSwipe = true;
9618									iL.moveTo('prev');
9619								}
9620							}
9621						} 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) {
9622							if (start.coords[1] > stop.coords[1]) {
9623								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
9624								else {
9625									vars.isSwipe = true;
9626									iL.moveTo('next');
9627								}
9628							} else {
9629								if (vars.current == 0 && !opts.infinite) repositionHolders();
9630								else {
9631									vars.isSwipe = true;
9632									iL.moveTo('prev');
9633								}
9634							}
9635						} else repositionHolders();
9636					}
9637					start = stop = undefined;
9638				});
9639			});
9640
9641		},
9642
9643		goTo: function(index) {
9644			var iL = this,
9645				vars = iL.vars,
9646				opts = iL.options,
9647				diff = (index - vars.current);
9648
9649			if (opts.infinite) {
9650				if (index == vars.total - 1 && vars.current == 0) diff = -1;
9651				if (vars.current == vars.total - 1 && index == 0) diff = 1;
9652			}
9653
9654			if (diff == 1) iL.moveTo('next');
9655			else if (diff == -1) iL.moveTo('prev');
9656			else {
9657
9658				if (vars.nextLock || vars.prevLock) return false;
9659
9660				//Trigger the onBeforeChange callback
9661				if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui);
9662
9663				if (opts.linkId) {
9664					vars.hashLock = true;
9665					window.location.hash = opts.linkId + '/' + index;
9666				}
9667
9668				if (iL.items[index]) {
9669					if (!iL.items[index].options.mousewheel) vars.lockWheel = true;
9670					else iL.vars.lockWheel = false;
9671
9672					if (!iL.items[index].options.swipe) vars.lockSwipe = true;
9673					else vars.lockSwipe = false;
9674				}
9675
9676				$.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) {
9677					val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed);
9678				});
9679
9680				vars.current = index;
9681				vars.next = index + 1;
9682				vars.prev = index - 1;
9683
9684				iL.createUI();
9685
9686				setTimeout(function() {
9687					iL.generateBoxes();
9688				}, opts.effects.loadedFadeSpeed + 50);
9689
9690				$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active');
9691				iL.positionThumbnails();
9692
9693				if (opts.linkId) setTimeout(function() {
9694					vars.hashLock = false;
9695				}, 55);
9696
9697				// Configure arrow buttons
9698				if (!opts.infinite) {
9699					vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
9700
9701					if (vars.current == 0) {
9702						vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
9703					}
9704					if (vars.current >= vars.total - 1) {
9705						vars.nextButton.add(vars.innerNextButton).addClass('disabled');
9706					}
9707				}
9708
9709				// Reset next cycle timeout
9710				iL.resetCycle();
9711
9712				//Trigger the onAfterChange callback
9713				if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui);
9714			}
9715		},
9716
9717		moveTo: function(side) {
9718			var iL = this,
9719				vars = iL.vars,
9720				opts = iL.options,
9721				path = opts.path.toLowerCase(),
9722				viewport = getViewport(),
9723				switchSpeed = opts.effects.switchSpeed;
9724
9725			if (vars.nextLock || vars.prevLock) return false;
9726			else {
9727
9728				var item = (side == "next") ? vars.next : vars.prev;
9729
9730				if (opts.linkId) {
9731					vars.hashLock = true;
9732					window.location.hash = opts.linkId + '/' + item;
9733				}
9734
9735				if (side == "next") {
9736					if (!iL.items[item]) return false;
9737					var firstHolder = vars.nextPhoto,
9738						secondHolder = vars.holder,
9739						lastHolder = vars.prevPhoto,
9740						firstClass = 'ilightbox-prev',
9741						secondClass = 'ilightbox-next';
9742				} else if (side == "prev") {
9743					if (!iL.items[item]) return false;
9744					var firstHolder = vars.prevPhoto,
9745						secondHolder = vars.holder,
9746						lastHolder = vars.nextPhoto,
9747						firstClass = 'ilightbox-next',
9748						secondClass = 'ilightbox-prev';
9749				}
9750
9751				//Trigger the onBeforeChange callback
9752				if (typeof opts.callback.onBeforeChange == 'function')
9753					opts.callback.onBeforeChange.call(iL, iL.ui);
9754
9755				(side == "next") ? vars.nextLock = true: vars.prevLock = true;
9756
9757				var captionFirst = $('div.ilightbox-caption', secondHolder),
9758					socialFirst = $('div.ilightbox-social', secondHolder);
9759
9760				if (captionFirst.length)
9761					captionFirst.stop().fadeOut(switchSpeed, function() {
9762						$(this).remove();
9763					});
9764				if (socialFirst.length)
9765					socialFirst.stop().fadeOut(switchSpeed, function() {
9766						$(this).remove();
9767					});
9768
9769				if (iL.items[item].caption) {
9770					iL.setCaption(iL.items[item], firstHolder);
9771					var caption = $('div.ilightbox-caption', firstHolder),
9772						percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100);
9773					if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed);
9774				}
9775
9776				var social = iL.items[item].options.social;
9777				if (social) {
9778					iL.setSocial(social, iL.items[item].URL, firstHolder);
9779					if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed);
9780				}
9781
9782				$.each([firstHolder, secondHolder, lastHolder], function(key, val) {
9783					val.removeClass('ilightbox-next ilightbox-prev');
9784				});
9785
9786				var firstOffset = firstHolder.data('offset'),
9787					winW = (viewport.width - (opts.styles.pageOffsetX)),
9788					winH = (viewport.height - (opts.styles.pageOffsetY)),
9789					width = firstOffset.newDims.width,
9790					height = firstOffset.newDims.height,
9791					thumbsOffset = firstOffset.thumbsOffset,
9792					diff = firstOffset.diff,
9793					top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)),
9794					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
9795
9796				var secondOffset = secondHolder.data('offset'),
9797					object = secondOffset.object;
9798
9799				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
9800					var objRatio = width / height;
9801					height = height - vars.captionHeight;
9802					width = height * objRatio;
9803					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top,
9804					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
9805				}*/
9806
9807				firstHolder.show().css(transform, gpuAcceleration).animate({
9808					top: top,
9809					left: left,
9810					opacity: 1
9811				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
9812					firstHolder.css(transform, '');
9813				});
9814
9815				$('div.ilightbox-container', firstHolder).animate({
9816					width: width,
9817					height: height
9818				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
9819
9820				diff = secondOffset.diff;
9821
9822				width = secondOffset.newDims.width,
9823					height = secondOffset.newDims.height;
9824
9825				width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
9826					height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
9827					top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2));
9828
9829				if (side == 'prev')
9830					left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2));
9831				else {
9832					top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)),
9833					left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2));
9834				}
9835
9836				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
9837					var objRatio = width / height;
9838					height = height - vars.captionHeight;
9839					width = height * objRatio;
9840					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top;
9841				}*/
9842
9843				$('div.ilightbox-container', secondHolder).animate({
9844					width: width,
9845					height: height
9846				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
9847
9848				secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({
9849					top: top,
9850					left: left,
9851					opacity: opts.styles.prevOpacity,
9852				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
9853					secondHolder.css(transform, '');
9854
9855					$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active');
9856					iL.positionThumbnails();
9857
9858					if (iL.items[item]) {
9859						if (!iL.items[item].options.mousewheel) vars.lockWheel = true;
9860						else vars.lockWheel = false;
9861
9862						if (!iL.items[item].options.swipe) vars.lockSwipe = true;
9863						else vars.lockSwipe = false;
9864					}
9865
9866					vars.isSwipe = false;
9867
9868					// Remove iframe & video from previous slide
9869					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
9870						$('div.ilightbox-container', secondHolder).empty();
9871					}
9872
9873					if (side == "next") {
9874						vars.nextPhoto = lastHolder,
9875							vars.prevPhoto = secondHolder,
9876							vars.holder = firstHolder;
9877
9878						vars.nextPhoto.hide();
9879
9880						vars.next = vars.next + 1,
9881							vars.prev = vars.current,
9882							vars.current = vars.current + 1;
9883
9884						if (opts.infinite) {
9885							if (vars.current > vars.total - 1) vars.current = 0;
9886							if (vars.current == vars.total - 1) vars.next = 0;
9887							if (vars.current == 0) vars.prev = vars.total - 1;
9888						}
9889
9890						iL.createUI();
9891
9892						if (!iL.items[vars.next])
9893							vars.nextLock = false;
9894						else
9895							iL.loadContent(iL.items[vars.next], 'next');
9896					} else {
9897						vars.prevPhoto = lastHolder;
9898						vars.nextPhoto = secondHolder;
9899						vars.holder = firstHolder;
9900
9901						vars.prevPhoto.hide();
9902
9903						vars.next = vars.current;
9904						vars.current = vars.prev;
9905						vars.prev = vars.current - 1;
9906
9907						if (opts.infinite) {
9908							if (vars.current == vars.total - 1) vars.next = 0;
9909							if (vars.current == 0) vars.prev = vars.total - 1;
9910						}
9911
9912						iL.createUI();
9913
9914						if (!iL.items[vars.prev])
9915							vars.prevLock = false;
9916						else
9917							iL.loadContent(iL.items[vars.prev], 'prev');
9918					}
9919
9920					// Add iframe & video content for current slide
9921					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
9922						iL.loadContent(iL.items[vars.current], 'current');
9923					}
9924
9925					if (opts.linkId) setTimeout(function() {
9926						vars.hashLock = false;
9927					}, 55);
9928
9929					// Configure arrow buttons
9930					if (!opts.infinite) {
9931						vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
9932
9933						if (vars.current == 0)
9934							vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
9935						if (vars.current >= vars.total - 1)
9936							vars.nextButton.add(vars.innerNextButton).addClass('disabled');
9937					}
9938
9939					iL.repositionPhoto();
9940
9941					// Reset next cycle timeout
9942					iL.resetCycle();
9943
9944					//Trigger the onAfterChange callback
9945					if (typeof opts.callback.onAfterChange == 'function')
9946						opts.callback.onAfterChange.call(iL, iL.ui);
9947				});
9948
9949				top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)),
9950					left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left');
9951
9952				lastHolder.css(transform, gpuAcceleration).animate({
9953					top: top,
9954					left: left,
9955					opacity: opts.styles.nextOpacity
9956				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
9957					lastHolder.css(transform, '');
9958				}).addClass(secondClass);
9959			}
9960		},
9961
9962		setCaption: function(obj, target) {
9963			var iL = this,
9964				caption = $('<div class="ilightbox-caption"></div>');
9965
9966			if (obj.caption) {
9967				caption.html(obj.caption);
9968				$('div.ilightbox-container', target).append(caption);
9969			}
9970		},
9971
9972		normalizeSocial: function(obj, url) {
9973			var iL = this,
9974				vars = iL.vars,
9975				opts = iL.options,
9976				baseURL = window.location.href;
9977
9978			$.each(obj, function(key, value) {
9979				if (!value)
9980					return true;
9981
9982				var item = key.toLowerCase(),
9983					source, text;
9984
9985				switch (item) {
9986					case 'facebook':
9987						source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}",
9988							text = "Share on Facebook";
9989						break;
9990					case 'twitter':
9991						source = "http://twitter.com/home?status={URL}",
9992							text = "Share on Twitter";
9993						break;
9994					case 'googleplus':
9995						source = "https://plus.google.com/share?url={URL}",
9996							text = "Share on Google+";
9997						break;
9998					case 'delicious':
9999						source = "http://delicious.com/post?url={URL}",
10000							text = "Share on Delicious";
10001						break;
10002					case 'digg':
10003						source = "http://digg.com/submit?phase=2&url={URL}",
10004							text = "Share on Digg";
10005						break;
10006					case 'reddit':
10007						source = "http://reddit.com/submit?url={URL}",
10008							text = "Share on reddit";
10009						break;
10010				}
10011
10012				obj[key] = {
10013					URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL,
10014					source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url),
10015					text: value.text || text || "Share on " + key,
10016					width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640,
10017					height: value.height || 360
10018				};
10019
10020			});
10021
10022			return obj;
10023		},
10024
10025		setSocial: function(obj, url, target) {
10026			var iL = this,
10027				socialBar = $('<div class="ilightbox-social"></div>'),
10028				buttons = '<ul>';
10029
10030			obj = iL.normalizeSocial(obj, url);
10031
10032			$.each(obj, function(key, value) {
10033				var item = key.toLowerCase(),
10034					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, '+'));
10035				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>';
10036			});
10037
10038			buttons += '</ul>';
10039
10040			socialBar.html(buttons);
10041			$('div.ilightbox-container', target).append(socialBar);
10042		},
10043
10044		fullScreenAction: function() {
10045			var iL = this,
10046				vars = iL.vars;
10047
10048			if (fullScreenApi.supportsFullScreen) {
10049				if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement);
10050				else fullScreenApi.requestFullScreen(document.documentElement);
10051			} else {
10052				iL.doFullscreen();
10053			}
10054		},
10055
10056		doFullscreen: function() {
10057			var iL = this,
10058				vars = iL.vars,
10059				viewport = getViewport(),
10060				opts = iL.options;
10061
10062			if (opts.fullAlone) {
10063				var currentHolder = vars.holder,
10064					current = iL.items[vars.current],
10065					windowWidth = viewport.width,
10066					windowHeight = viewport.height,
10067					elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader],
10068					hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
10069
10070				if (!vars.isInFullScreen) {
10071					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true;
10072					vars.overlay.css({
10073						opacity: 1
10074					});
10075
10076					$.each(hideElements, function(i, element) {
10077						element.hide();
10078					});
10079
10080					vars.fullScreenButton.attr('title', opts.text.exitFullscreen);
10081
10082					if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
10083						naturalWidthOld: currentHolder.data('naturalWidth'),
10084						naturalHeightOld: currentHolder.data('naturalHeight'),
10085						naturalWidth: windowWidth,
10086						naturalHeight: windowHeight
10087					});
10088					else {
10089						var viewport = current.options.fullViewPort || opts.fullViewPort || '',
10090							newWidth = windowWidth,
10091							newHeight = windowHeight,
10092							width = currentHolder.data('naturalWidth'),
10093							height = currentHolder.data('naturalHeight');
10094
10095						if (viewport.toLowerCase() == 'fill') {
10096							newHeight = (newWidth / width) * height;
10097
10098							if (newHeight < windowHeight) {
10099								newWidth = (windowHeight / height) * width,
10100									newHeight = windowHeight;
10101							}
10102						} else if (viewport.toLowerCase() == 'fit') {
10103							var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true);
10104
10105							newWidth = dims.width,
10106								newHeight = dims.height;
10107						} else if (viewport.toLowerCase() == 'stretch') {
10108							newWidth = newWidth,
10109								newHeight = newHeight;
10110						} else {
10111							var scale = (width > newWidth || height > newHeight) ? true : false,
10112								dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale);
10113							newWidth = dims.width,
10114								newHeight = dims.height;
10115						}
10116
10117						currentHolder.data({
10118							naturalWidthOld: currentHolder.data('naturalWidth'),
10119							naturalHeightOld: currentHolder.data('naturalHeight'),
10120							naturalWidth: newWidth,
10121							naturalHeight: newHeight
10122						});
10123					}
10124
10125					$.each(elements, function(key, val) {
10126						val.addClass('ilightbox-fullscreen');
10127					});
10128
10129					//Trigger the onEnterFullScreen callback
10130					if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui);
10131				} else {
10132					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false;
10133					vars.overlay.css({
10134						opacity: iL.options.overlay.opacity
10135					});
10136
10137					$.each(hideElements, function(i, element) {
10138						element.show();
10139					});
10140
10141					vars.fullScreenButton.attr('title', opts.text.enterFullscreen);
10142
10143					currentHolder.data({
10144						naturalWidth: currentHolder.data('naturalWidthOld'),
10145						naturalHeight: currentHolder.data('naturalHeightOld'),
10146						naturalWidthOld: null,
10147						naturalHeightOld: null
10148					});
10149
10150					$.each(elements, function(key, val) {
10151						val.removeClass('ilightbox-fullscreen');
10152					});
10153
10154					//Trigger the onExitFullScreen callback
10155					if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui);
10156				}
10157			} else {
10158				if (!vars.isInFullScreen) vars.isInFullScreen = true;
10159				else vars.isInFullScreen = false;
10160			}
10161			iL.repositionPhoto(true);
10162		},
10163
10164		closeAction: function() {
10165			var iL = this,
10166				vars = iL.vars,
10167				opts = iL.options;
10168
10169			$win.unbind('.iLightBox');
10170			$doc.off('.iLightBox');
10171
10172			if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement);
10173
10174			$('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox');
10175
10176			if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() {
10177				vars.overlay.remove();
10178				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
10179			});
10180			else {
10181				vars.overlay.remove();
10182				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
10183			}
10184
10185			var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
10186
10187			$.each(fadeOuts, function(i, element) {
10188				element.removeAttr('style').remove();
10189			});
10190
10191			vars.dontGenerateThumbs = vars.isInFullScreen = false;
10192
10193			window.iLightBox = null;
10194
10195			if (opts.linkId) {
10196				vars.hashLock = true;
10197				removeHash();
10198				setTimeout(function() {
10199					vars.hashLock = false;
10200				}, 55);
10201			}
10202
10203			vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
10204
10205			//Trigger the onHide callback
10206			if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui);
10207		},
10208
10209		repositionPhoto: function() {
10210			var iL = this,
10211				vars = iL.vars,
10212				opts = iL.options,
10213				path = opts.path.toLowerCase(),
10214				viewport = getViewport(),
10215				winWidth = viewport.width,
10216				winHeight = viewport.height;
10217
10218			if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0;
10219
10220			var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()),
10221				thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)),
10222				width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)),
10223				height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)),
10224				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,
10225				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)));
10226
10227			var elObject = {
10228				type: 'current',
10229				width: width,
10230				height: height,
10231				item: iL.items[vars.current],
10232				offsetW: offsetW,
10233				offsetH: offsetH,
10234				thumbsOffsetW: thumbsOffsetW,
10235				thumbsOffsetH: thumbsOffsetH,
10236				animate: arguments.length,
10237				holder: vars.holder
10238			};
10239
10240			iL.repositionEl(elObject);
10241
10242			if (iL.items[vars.next]) {
10243				elObject = $.extend(elObject, {
10244					type: 'next',
10245					item: iL.items[vars.next],
10246					offsetX: opts.styles.nextOffsetX,
10247					offsetY: opts.styles.nextOffsetY,
10248					holder: vars.nextPhoto
10249				});
10250
10251				iL.repositionEl(elObject);
10252			}
10253
10254			if (iL.items[vars.prev]) {
10255				elObject = $.extend(elObject, {
10256					type: 'prev',
10257					item: iL.items[vars.prev],
10258					offsetX: opts.styles.nextOffsetX,
10259					offsetY: opts.styles.prevOffsetY,
10260					holder: vars.prevPhoto
10261				});
10262
10263				iL.repositionEl(elObject);
10264			}
10265
10266			var loaderCss = (path == "horizontal") ? {
10267				left: parseInt((width / 2) - (vars.loader.outerWidth() / 2))
10268			} : {
10269				top: parseInt((height / 2) - (vars.loader.outerHeight() / 2))
10270			};
10271			vars.loader.css(loaderCss);
10272		},
10273
10274		repositionEl: function(obj) {
10275			var iL = this,
10276				vars = iL.vars,
10277				opts = iL.options,
10278				path = opts.path.toLowerCase(),
10279				widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW),
10280				heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH),
10281				itemParent = obj.item,
10282				item = obj.item.options,
10283				holder = obj.holder,
10284				offsetX = obj.offsetX || 0,
10285				offsetY = obj.offsetY || 0,
10286				//Uncode change ##START##
10287				toolbarHeight = $('.ilightbox-inner-toolbar', holder).length ? parseInt( $('.ilightbox-inner-toolbar', holder).outerHeight() ) : 0,
10288				//Uncode change ##END##
10289				thumbsOffsetW = obj.thumbsOffsetW,
10290				thumbsOffsetH = obj.thumbsOffsetH;
10291
10292			if (obj.type == 'current') {
10293				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);
10294				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);
10295			} else {
10296				if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width;
10297				if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height;
10298			}
10299
10300
10301			//Uncode change ##START##
10302			heightAvail = parseInt(heightAvail - toolbarHeight);
10303			// heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight());
10304			//Uncode change ##END##
10305
10306			var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'),
10307				height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight');
10308
10309			var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? {
10310					width: width,
10311					height: height
10312				} : iL.getNewDimenstions(widthAvail, heightAvail, width, height)),
10313				newDims = $.extend({}, dims, {});
10314
10315			if (obj.type == 'prev' || obj.type == 'next')
10316				width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)),
10317				height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale));
10318			else
10319				width = dims.width,
10320				height = dims.height;
10321
10322			var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2),
10323				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);
10324
10325			switch (obj.type) {
10326				case 'current':
10327					var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)),
10328						left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2));
10329					break;
10330
10331				case 'next':
10332					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)),
10333						left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2));
10334					break;
10335
10336				case 'prev':
10337					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)),
10338						left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2));
10339					break;
10340			}
10341
10342			holder.data('offset', {
10343				top: top,
10344				left: left,
10345				newDims: newDims,
10346				diff: {
10347					W: widthDiff,
10348					H: heightDiff
10349				},
10350				thumbsOffset: {
10351					W: thumbsOffsetW,
10352					H: thumbsOffsetH
10353				},
10354				object: obj
10355			});
10356
10357			var opacityMobile;
10358			if ( isMobile ) {
10359				opacityMobile = {
10360					opacity: 1,
10361					top: top,
10362					left: left
10363				};
10364			} else {
10365				opacityMobile = {
10366					top: top,
10367					left: left
10368				};
10369			}
10370
10371			if (obj.animate > 0 && opts.effects.reposition) {
10372				holder.css(transform, gpuAcceleration).stop().animate(
10373					opacityMobile,
10374					opts.effects.repositionSpeed, 'easeOutCirc', function() {
10375					holder.css(transform, '');
10376				});
10377				$('div.ilightbox-container', holder).stop().animate({
10378					width: width,
10379					height: height
10380				}, opts.effects.repositionSpeed, 'easeOutCirc');
10381				$('div.ilightbox-inner-toolbar', holder).stop().animate({
10382					width: width
10383				}, opts.effects.repositionSpeed, 'easeOutCirc', function() {
10384					$(this).css('overflow', 'visible');
10385				});
10386			} else {
10387				holder.css(opacityMobile);
10388				$('div.ilightbox-container', holder).css({
10389					width: width,
10390					height: height
10391				});
10392				$('div.ilightbox-inner-toolbar', holder).css({
10393					width: width
10394				});
10395			}
10396		},
10397
10398
10399		resume: function(priority) {
10400			var iL = this,
10401				vars = iL.vars,
10402				opts = iL.options;
10403
10404			if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) {
10405				return;
10406			}
10407
10408			vars.isPaused = 0;
10409
10410			if (vars.cycleID) {
10411				vars.cycleID = clearTimeout(vars.cycleID);
10412			}
10413
10414			vars.cycleID = setTimeout(function() {
10415				if (vars.current == vars.total - 1) iL.goTo(0);
10416				else iL.moveTo('next');
10417			}, opts.slideshow.pauseTime);
10418		},
10419
10420		pause: function(priority) {
10421			var iL = this,
10422				vars = iL.vars,
10423				opts = iL.options;
10424
10425			if (priority < vars.isPaused) {
10426				return;
10427			}
10428
10429			vars.isPaused = priority || 100;
10430
10431			if (vars.cycleID) {
10432				vars.cycleID = clearTimeout(vars.cycleID);
10433			}
10434		},
10435
10436		resetCycle: function() {
10437			var iL = this,
10438				vars = iL.vars,
10439				opts = iL.options;
10440
10441			if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) {
10442				iL.resume();
10443			}
10444		},
10445
10446		getNewDimenstions: function(width, height, width_old, height_old, thumb) {
10447			var iL = this;
10448
10449			if (!width) factor = height / height_old;
10450			else if (!height) factor = width / width_old;
10451			else factor = min(width / width_old, height / height_old);
10452
10453			if (!thumb) {
10454				if (factor > iL.options.maxScale) factor = iL.options.maxScale;
10455				else if (factor < iL.options.minScale) factor = iL.options.minScale;
10456			}
10457
10458			var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width,
10459				final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height;
10460
10461			return {
10462				width: final_width,
10463				height: final_height,
10464				ratio: factor
10465			};
10466		},
10467
10468		setOption: function(options) {
10469			var iL = this;
10470
10471			iL.options = $.extend(true, iL.options, options || {});
10472			iL.refresh();
10473		},
10474
10475		availPlugins: function() {
10476			var iL = this,
10477				testEl = document.createElement("video");
10478
10479			iL.plugins = {
10480				flash: !isMobile,
10481				quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false,
10482				html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')),
10483				html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')),
10484				html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')),
10485				html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, ''))
10486			};
10487		},
10488
10489		addContent: function(element, obj) {
10490			var iL = this,
10491				el;
10492
10493			switch (obj.type) {
10494				case 'video':
10495					var HTML5 = false,
10496						videoType = obj.videoType,
10497						html5video = obj.options.html5video;
10498
10499					if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264)
10500						obj.ext = 'mp4',
10501						obj.URL = html5video.h264 || obj.URL;
10502					else if (html5video.webm && iL.plugins.html5WebM)
10503						obj.ext = 'webm',
10504						obj.URL = html5video.webm || obj.URL;
10505					else if (html5video.ogg && iL.plugins.html5Vorbis)
10506						obj.ext = 'ogv',
10507						obj.URL = html5video.ogg || obj.URL;
10508
10509					if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4";
10510					else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm";
10511					else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg";
10512					else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime";
10513
10514					if (HTML5) {
10515						el = $('<video />
10515', {
10516							"width": "100%",
10517							"height": "100%",
10518							"preload": html5video.preload,
10519							"autoplay": html5video.autoplay,
10520							"loop": html5video.loop,
10521							"poster": html5video.poster,
10522							"controls": html5video.controls,
10523							"controlslist": "nodownload"
10524						}).append($('<source />', {
10525							"src": obj.URL,
10526							"type": videoType
10527						}));
10528					} else {
10529						if (!iL.plugins.quicktime) el = $('<span />', {
10530							"class": "ilightbox-alert",
10531							html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime')
10532						});
10533						else {
10534
10535							el = $('<object />', {
10536								"type": "video/quicktime",
10537								"pluginspage": pluginspages.quicktime
10538							}).attr({
10539								"data": obj.URL,
10540								"width": "100%",
10541								"height": "100%"
10542							}).append($('<param />', {
10543								"name": "src",
10544								"value": obj.URL
10545							})).append($('<param />', {
10546								"name": "autoplay",
10547								"value": "false"
10548							})).append($('<param />', {
10549								"name": "loop",
10550								"value": "false"
10551							})).append($('<param />', {
10552								"name": "scale",
10553								"value": "tofit"
10554							}));
10555
10556							if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false');
10557						}
10558					}
10559
10560					break;
10561
10562				case 'flash':
10563					if (!iL.plugins.flash) el = $('<span />', {
10564						"class": "ilightbox-alert",
10565						html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player')
10566					});
10567					else {
10568						var flashvars = "",
10569							i = 0;
10570
10571						if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) {
10572							if (i != 0) flashvars += "&";
10573							flashvars += k + "=" + encodeURIComponent(v);
10574							i++;
10575						});
10576						else flashvars = null;
10577
10578						el = $('<embed />').attr({
10579							"type": "application/x-shockwave-flash",
10580							"src": obj.URL,
10581							"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
10582							"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
10583							"quality": "high",
10584							"bgcolor": "#000000",
10585							"play": "true",
10586							"loop": "true",
10587							"menu": "true",
10588							"wmode": "transparent",
10589							"scale": "showall",
10590							"allowScriptAccess": "always",
10591							"allowFullScreen": "true",
10592							"flashvars": flashvars,
10593							"fullscreen": "yes"
10594						});
10595					}
10596
10597					break;
10598
10599				case 'iframe':
10600					el = $('<iframe />').attr({
10601						"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
10602						"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
10603						src: obj.URL,
10604						frameborder: 0,
10605						'hspace': 0,
10606						'vspace': 0,
10607						'scrolling': supportTouch ? 'auto' : 'scroll',
10608						'webkitAllowFullScreen': '',
10609						'mozallowfullscreen': '',
10610						'allowFullScreen': ''
10611					});
10612
10613					break;
10614
10615				case 'inline':
10616					el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true));
10617
10618					break;
10619
10620				case 'html':
10621					var object = obj.URL,
10622						el;
10623
10624					if (object[0].nodeName) {
10625						el = $('<div class="ilightbox-wrapper"></div>').html(object);
10626					} else {
10627						var dom = $(obj.URL),
10628							html = (dom.selector) ? $('<div>' + dom + '</div>') : dom;
10629						el = $('<div class="ilightbox-wrapper"></div>').html(html);
10630					}
10631
10632					break;
10633			}
10634
10635			$('div.ilightbox-container', element).empty().html(el);
10636
10637			// For fixing Chrome about just playing the video for first time
10638			if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() {
10639				var src = el[0].currentSrc + '?' + floor(random() * 30000);
10640				el[0].currentSrc = src;
10641				el[0].src = src;
10642			});
10643
10644			return el;
10645		},
10646
10647		ogpRecognition: function(obj, callback) {
10648			var iL = this,
10649				url = obj.URL;
10650
10651			iL.showLoader();
10652			doAjax(url, function(data) {
10653				iL.hideLoader();
10654				if (data) {
10655					var object = new Object();
10656
10657					object.length = false,
10658					object.url = data.url;
10659
10660					if (data.status == 200) {
10661						var result = data.results,
10662							type = result.type,
10663							source = result.source;
10664
10665						object.source = source.src,
10666						object.width = source.width && parseInt(source.width) || 0,
10667						object.height = source.height && parseInt(source.height) || 0,
10668						object.type = type,
10669						object.thumbnail = source.thumbnail || result.images && result.images[0],
10670						object.html5video = result.html5video || {},
10671						object.length = true;
10672
10673						if (source.type == 'application/x-shockwave-flash') object.type = "flash";
10674						else if (source.type.indexOf("video/") != -1) object.type = "video";
10675						else if (source.type.indexOf("/html") != -1) object.type = "iframe";
10676						else if (source.type.indexOf("image/") != -1) object.type = "image";
10677
10678					} else if (typeof data.response != 'undefined')
10679						throw data.response;
10680
10681					callback.call(this, object.length ? object : false);
10682				}
10683			});
10684		},
10685
10686		hashChangeHandler: function(url) {
10687			var iL = this,
10688				vars = iL.vars,
10689				opts = iL.options,
10690				URL = url || window.location.href,
10691				hash = parseURI(URL).hash,
10692				split = hash.split('/'),
10693				index = split[1];
10694
10695			if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return;
10696
10697			if (index) {
10698				var target = split[1] || 0;
10699				if (iL.items[target]) {
10700					var overlay = $('.ilightbox-overlay');
10701					if (overlay.length && overlay.attr('linkid') == opts.linkId) {
10702						iL.goTo(target);
10703					} else {
10704						iL.itemsObject[target].trigger(ishybrid ? "itap click" : supportTouch ? 'itap' : 'click');
10705						//iL.goTo(target);
10706					}
10707				} else {
10708					var overlay = $('.ilightbox-overlay');
10709					if (overlay.length) iL.closeAction();
10710				}
10711			} else {
10712				var overlay = $('.ilightbox-overlay');
10713				if (overlay.length) iL.closeAction();
10714			}
10715		}
10716	};
10717
10718	/**
10719	 * Parse style to pixels.
10720	 *
10721	 * @param {Object}   $element   jQuery object with element.
10722	 * @param {Property} property   CSS property to get the pixels from.
10723	 *
10724	 * @return {Int}
10725	 */
10726	function getPixel($element, property) {
10727		return parseInt($element.css(property), 10) || 0;
10728	}
10729
10730	/**
10731	 * Make sure that number is within the limits.
10732	 *
10733	 * @param {Number} number
10734	 * @param {Number} min
10735	 * @param {Number} max
10736	 *
10737	 * @return {Number}
10738	 */
10739	function within(number, min, max) {
10740		return number < min ? min : number > max ? max : number;
10741	}
10742
10743	/**
10744	 * Get viewport/window size (width and height).
10745	 *
10746	 * @return {Object}
10747	 */
10748	function getViewport() {
10749		var e = window,
10750			a = 'inner';
10751		if (!('innerWidth' in window)) {
10752			a = 'client';
10753			e = document.documentElement || document.body;
10754		}
10755		return {
10756			width: e[a + 'Width'],
10757			height: e[a + 'Height']
10758		}
10759	}
10760
10761	/**
10762	 * Remove hash tag from the URL
10763	 *
10764	 * @return {Void}
10765	 */
10766	function removeHash() {
10767		var scroll = getScrollXY();
10768
10769		//UNCODE change
10770		//window.location.hash = "";
10771		history.pushState("", document.title, window.location.pathname + window.location.search);
10772
10773		// Restore the scroll offset, should be flicker free
10774		window.scrollTo(scroll.x, scroll.y);
10775	}
10776
10777	/**
10778	 * Do the ajax requests with callback.
10779	 *
10780	 * @param {String}   url
10781	 * @param {Function} callback
10782	 *
10783	 * @return {Void}
10784	 */
10785	function doAjax(url, callback) {
10786		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');
10787		$.ajax({
10788			url: url,
10789			dataType: 'jsonp'
10790		});
10791
10792		iLCallback = function(data) {
10793			callback.call(this, data);
10794		};
10795	}
10796
10797	/**
10798	 * Find image from DOM elements
10799	 *
10800	 * @param {Element} element
10801	 *
10802	 * @return {Void}
10803	 */
10804	function findImageInElement(element) {
10805		var elements = $('*', element),
10806			imagesArr = new Array();
10807
10808		elements.each(function() {
10809			var url = "",
10810				element = this;
10811
10812			if ($(element).css("background-image") != "none") {
10813				url = $(element).css("background-image");
10814			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
10815				url = $(element).attr("src");
10816			}
10817
10818			if (url.indexOf("gradient") == -1) {
10819				url = url.replace(/url\(\"/g, "");
10820				url = url.replace(/url\(/g, "");
10821				url = url.replace(/\"\)/g, "");
10822				url = url.replace(/\)/g, "");
10823
10824				var urls = url.split(",");
10825
10826				for (var i = 0; i < urls.length; i++) {
10827					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
10828						var extra = "";
10829						if (browser.msie && browser.version < 9) {
10830							extra = "?" + floor(random() * 3000);
10831						}
10832						imagesArr.push(urls[i] + extra);
10833					}
10834				}
10835			}
10836		});
10837
10838		return imagesArr;
10839	}
10840
10841	/**
10842	 * Get file extension.
10843	 *
10844	 * @param {String} URL
10845	 *
10846	 * @return {String}
10847	 */
10848	function getExtension(URL) {
10849		if (URL !== null) {
10850			//UNCODE: fix issue to detect media type with query strings
10851			var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL;
10852			ext = ext.split('.').pop().toLowerCase();
10853
10854			return ext;
10855		}
10856	}
10857
10858	/**
10859	 * Get type via extension.
10860	 *
10861	 * @param {String} URL
10862	 *
10863	 * @return {String}
10864	 */
10865	function getTypeByExtension(URL) {
10866		var type,
10867			ext = getExtension(URL);
10868
10869		//Uncode addition ##START##
10870		if (URL == undefined) {
10871			return false;
10872		}
10873		//Uncode addition ##END##
10874
10875		if (extensions.image.indexOf(ext) !== -1) type = 'image';
10876		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
10877		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
10878		else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition
10879		else type = 'iframe';
10880
10881		return type;
10882	}
10883
10884	/**
10885	 * Return value from percent of a number.
10886	 *
10887	 * @param {Number} percent
10888	 * @param {Number} total
10889	 *
10890	 * @return {Number}
10891	 */
10892	function percentToValue(percent, total) {
10893		return parseInt((total / 100) * percent);
10894	}
10895
10896	/**
10897	 * A JavaScript equivalent of PHP’s parse_url.
10898	 *
10899	 * @param {String} url           The URL to parse.
10900	 *
10901	 * @return {Mixed}
10902	 */
10903	function parseURI(url) {
10904		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
10905		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
10906		return (m ? {
10907			href: m[0] || '',
10908			protocol: m[1] || '',
10909			authority: m[2] || '',
10910			host: m[3] || '',
10911			hostname: m[4] || '',
10912			port: m[5] || '',
10913			pathname: m[6] || '',
10914			search: m[7] || '',
10915			hash: m[8] || ''
10916		} : null);
10917	}
10918
10919	/**
10920	 * Gets the absolute URI.
10921	 *
10922	 * @param {String} href     The relative URL.
10923	 * @param {String} base     The base URL.
10924	 *
10925	 * @return {String}         The absolute URL.
10926	 */
10927	function absolutizeURI(base, href) { // RFC 3986
10928		var iL = this;
10929
10930		function removeDotSegments(input) {
10931			var output = [];
10932			input.replace(/^(\.\.?(\/|$))+/, '')
10933				.replace(/\/(\.(\/|$))+/g, '/')
10934				.replace(/\/\.\.$/, '/../')
10935				.replace(/\/?[^\/]*/g, function(p) {
10936					if (p === '/..') {
10937						output.pop();
10938					} else {
10939						output.push(p);
10940					}
10941				});
10942			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
10943		}
10944
10945		href = parseURI(href || '');
10946		base = parseURI(base || '');
10947
10948		return !href || !base ? null : (href.protocol || base.protocol) +
10949			(href.protocol || href.authority ? href.authority : base.authority) +
10950			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)) +
10951			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
10952			href.hash;
10953	}
10954
10955	/**
10956	 * A JavaScript equivalent of PHP’s version_compare.
10957	 *
10958	 * @param {String} v1
10959	 * @param {String} v2
10960	 * @param {String} operator
10961	 *
10962	 * @return {Boolean}
10963	 */
10964	function version_compare(v1, v2, operator) {
10965		this.php_js = this.php_js || {};
10966		this.php_js.ENV = this.php_js.ENV || {};
10967		var i = 0,
10968			x = 0,
10969			compare = 0,
10970			vm = {
10971				'dev': -6,
10972				'alpha': -5,
10973				'a': -5,
10974				'beta': -4,
10975				'b': -4,
10976				'RC': -3,
10977				'rc': -3,
10978				'#': -2,
10979				'p': 1,
10980				'pl': 1
10981			},
10982			prepVersion = function(v) {
10983				v = ('' + v).replace(/[_\-+]/g, '.');
10984				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
10985				return (!v.length ? [-8] : v.split('.'));
10986			},
10987			numVersion = function(v) {
10988				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
10989			};
10990		v1 = prepVersion(v1);
10991		v2 = prepVersion(v2);
10992		x = max(v1.length, v2.length);
10993		for (i = 0; i < x; i++) {
10994			if (v1[i] == v2[i]) {
10995				continue;
10996			}
10997			v1[i] = numVersion(v1[i]);
10998			v2[i] = numVersion(v2[i]);
10999			if (v1[i] < v2[i]) {
11000				compare = -1;
11001				break;
11002			} else if (v1[i] > v2[i]) {
11003				compare = 1;
11004				break;
11005			}
11006		}
11007		if (!operator) {
11008			return compare;
11009		}
11010
11011		switch (operator) {
11012			case '>':
11013			case 'gt':
11014				return (compare > 0);
11015			case '>=':
11016			case 'ge':
11017				return (compare >= 0);
11018			case '<=':
11019			case 'le':
11020				return (compare <= 0);
11021			case '==':
11022			case '=':
11023			case 'eq':
11024				return (compare === 0);
11025			case '<>':
11026			case '!=':
11027			case 'ne':
11028				return (compare !== 0);
11029			case '':
11030			case '<':
11031			case 'lt':
11032				return (compare < 0);
11033			default:
11034				return null;
11035		}
11036	}
11037
11038
11039	// Begin the iLightBox plugin
11040	$.fn.iLightBox = function() {
11041
11042		var args = arguments,
11043			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
11044			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
11045
11046		if (!opt) opt = {};
11047
11048		// Default options. Play carefully.
11049		var options = $.extend(true, {
11050			attr: 'href',
11051			path: 'vertical',
11052			skin: 'dark',
11053			linkId: false,
11054			infinite: false,
11055			startFrom: 0,
11056			randomStart: false,
11057			keepAspectRatio: true,
11058			maxScale: 1,
11059			minScale: .2,
11060			innerToolbar: false,
11061			smartRecognition: false,
11062			mobileOptimizer: true,
11063			fullAlone: true,
11064			fullViewPort: null,
11065			fullStretchTypes: 'flash, video',
11066			overlay: {
11067				blur: true,
11068				opacity: .85
11069			},
11070			controls: {
11071				arrows: false,
11072				slideshow: false,
11073				toolbar: true,
11074				fullscreen: true,
11075				thumbnail: true,
11076				keyboard: true,
11077				mousewheel: true,
11078				swipe: true
11079			},
11080			keyboard: {
11081				left: true, // previous
11082				right: true, // next
11083				up: true, // previous
11084				down: true, // next
11085				esc: true, // close
11086				shift_enter: true // fullscreen
11087			},
11088			show: {
11089				effect: true,
11090				speed: 300,
11091				title: true
11092			},
11093			hide: {
11094				effect: true,
11095				speed: 300
11096			},
11097			caption: {
11098				start: true,
11099				show: 'mouseenter',
11100				hide: 'mouseleave'
11101			},
11102			social: {
11103				start: true,
11104				show: 'mouseenter',
11105				hide: 'mouseleave',
11106				buttons: false
11107			},
11108			styles: {
11109				pageOffsetX: 0,
11110				pageOffsetY: 0,
11111				nextOffsetX: 45,
11112				nextOffsetY: 0,
11113				nextOpacity: 1,
11114				nextScale: 1,
11115				prevOffsetX: 45,
11116				prevOffsetY: 0,
11117				prevOpacity: 1,
11118				prevScale: 1
11119			},
11120			thumbnails: {
11121				maxWidth: 120,
11122				maxHeight: 80,
11123				normalOpacity: 1,
11124				activeOpacity: .6
11125			},
11126			effects: {
11127				reposition: true,
11128				repositionSpeed: 200,
11129				switchSpeed: 500,
11130				loadedFadeSpeed: 180,
11131				fadeSpeed: 200
11132			},
11133			slideshow: {
11134				pauseTime: 5000,
11135				pauseOnHover: false,
11136				startPaused: true
11137			},
11138			text: {
11139				close: "Press Esc to close",
11140				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
11141				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
11142				slideShow: "Slideshow",
11143				next: "Next",
11144				previous: "Previous"
11145			},
11146			errors: {
11147				loadImage: "An error occurred when trying to load photo.",
11148				loadContents: "An error occurred when trying to load contents.",
11149				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
11150			},
11151			ajaxSetup: {
11152				url: '',
11153				beforeSend: function(jqXHR, settings) {},
11154				cache: false,
11155				complete: function(jqXHR, textStatus) {},
11156				crossDomain: false,
11157				error: function(jqXHR, textStatus, errorThrown) {},
11158				success: function(data, textStatus, jqXHR) {},
11159				global: true,
11160				ifModified: false,
11161				username: null,
11162				password: null,
11163				type: 'GET'
11164			},
11165			callback: {}
11166		}, opt);
11167
11168		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
11169
11170		items = $.isArray(items) ? items : new Array();
11171
11172		if (typeof args[0] == 'string') items[0] = args[0];
11173
11174		if (version_compare($.fn.jquery, '1.8', '>=')) {
11175			var iLB = new iLightBox($(this), options, items, instant);
11176			return {
11177				close: function() {
11178					iLB.closeAction();
11179				},
11180				fullscreen: function() {
11181					iLB.fullScreenAction();
11182				},
11183				moveNext: function() {
11184					iLB.moveTo('next');
11185				},
11186				movePrev: function() {
11187					iLB.moveTo('prev');
11188				},
11189				goTo: function(index) {
11190					iLB.goTo(index);
11191				},
11192				refresh: function() {
11193					iLB.refresh();
11194				},
11195				reposition: function() {
11196					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
11197				},
11198				setOption: function(options) {
11199					iLB.setOption(options);
11200				},
11201				destroy: function() {
11202					iLB.closeAction();
11203					iLB.dispatchItemsEvents();
11204				}
11205			};
11206		} else {
11207			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
11208		}
11209
11210	};
11211
11212
11213	$.iLightBox = function() {
11214		return $.fn.iLightBox(arguments[0], arguments[1]);
11215	};
11216
11217	function getScrollXY() {
11218		var scrOfX = 0,
11219			scrOfY = 0;
11220		if (typeof(window.pageYOffset) == 'number') {
11221			//Netscape compliant
11222			scrOfY = window.pageYOffset;
11223			scrOfX = window.pageXOffset;
11224		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
11225			//DOM compliant
11226			scrOfY = document.body.scrollTop;
11227			scrOfX = document.body.scrollLeft;
11228		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
11229			//IE6 standards compliant mode
11230			scrOfY = document.documentElement.scrollTop;
11231			scrOfX = document.documentElement.scrollLeft;
11232		}
11233		return {
11234			x: scrOfX,
11235			y: scrOfY
11236		};
11237	}
11238
11239	(function() {
11240		// add new event shortcuts
11241		$.each(("touchstart touchmove touchend " +
11242			"tap taphold " +
11243			"swipe swipeleft swiperight " +
11244			"scrollstart scrollstop").split(" "), function(i, name) {
11245
11246			$.fn[name] = function(fn) {
11247				return fn ? this.bind(name, fn) : this.trigger(name);
11248			};
11249
11250			// jQuery < 1.8
11251			// if ($.attrFn) {
11252			// 	$.attrFn[name] = true;
11253			// }
11254		});
11255
11256		var tapSettings = {
11257			startEvent: 'touchstart.iTap',
11258			endEvent: 'touchend.iTap'
11259		};
11260
11261		// tap Event:
11262		$.event.special.itap = {
11263			setup: function() {
11264
11265				var self = this,
11266					$self = $(this),
11267					start, stop;
11268
11269				$self.bind(tapSettings.startEvent, function(event) {
11270					start = getScrollXY();
11271
11272					$self.one(tapSettings.endEvent, function(event) {
11273						stop = getScrollXY();
11274
11275						var orgEvent = event || window.event;
11276						event = $.event.fix(orgEvent);
11277						event.type = "itap";
11278
11279						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
11280
11281						start = stop = undefined;
11282					});
11283				});
11284			},
11285
11286			teardown: function() {
11287				$(this).unbind(tapSettings.startEvent);
11288			}
11289		};
11290	}());
11291
11292
11293	//Fullscreen API
11294	(function() {
11295		fullScreenApi = {
11296				supportsFullScreen: false,
11297				isFullScreen: function() {
11298					return false;
11299				},
11300				requestFullScreen: function() {},
11301				cancelFullScreen: function() {},
11302				fullScreenEventName: '',
11303				prefix: ''
11304			},
11305			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
11306
11307		// check for native support
11308		if (typeof document.cancelFullScreen != 'undefined') {
11309			fullScreenApi.supportsFullScreen = true;
11310		} else {
11311			// check for fullscreen support by vendor prefix
11312			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
11313				fullScreenApi.prefix = browserPrefixes[i];
11314
11315				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
11316					fullScreenApi.supportsFullScreen = true;
11317
11318					break;
11319				}
11320			}
11321		}
11322
11323		// update methods to do something useful
11324		if (fullScreenApi.supportsFullScreen) {
11325			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
11326
11327			fullScreenApi.isFullScreen = function() {
11328				switch (this.prefix) {
11329					case '':
11330						return document.fullScreen;
11331					case 'webkit':
11332						return document.webkitIsFullScreen;
11333					default:
11334						return document[this.prefix + 'FullScreen'];
11335				}
11336			}
11337			fullScreenApi.requestFullScreen = function(el) {
11338				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
11339			}
11340			fullScreenApi.cancelFullScreen = function(el) {
11341				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
11342			}
11343		}
11344	}());
11345
11346	// Browser detect
11347	(function() {
11348		function uaMatch(ua) {
11349			ua = ua.toLowerCase();
11350
11351			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
11352				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
11353				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
11354				/(msie) ([\w.]+)/.exec(ua) ||
11355				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
11356
11357			return {
11358				browser: match[1] || "",
11359				version: match[2] || "0"
11360			};
11361		}
11362
11363		var matched = uaMatch(navigator.userAgent);
11364		browser = {};
11365
11366		if (matched.browser) {
11367			browser[matched.browser] = true;
11368			browser.version = matched.version;
11369		}
11370
11371		// Chrome is Webkit, but Webkit is also Safari.
11372		if (browser.chrome) {
11373			browser.webkit = true;
11374		} else if (browser.webkit) {
11375			browser.safari = true;
11376		}
11377	}());
11378
11379	// Feature detects
11380	(function() {
11381		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
11382		var el = document.createElement('div');
11383
11384		function testProp(prop) {
11385			for (var p = 0, pl = prefixes.length; p < pl; p++) {
11386				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
11387				if (el.style[prefixedProp] !== undefined) {
11388					return prefixedProp;
11389				}
11390			}
11391		}
11392
11393		// Global support indicators
11394		transform = testProp('transform') || '';
11395		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
11396	}());
11397
11398
11399	/*
11400		PluginDetect v0.7.9
11401		www.pinlady.net/PluginDetect/license/
11402		[ getVersion onWindowLoaded BetterIE ]
11403		[ Flash QuickTime Shockwave ]
11404	*/
11405	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;
11405d++){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);
11405d.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)}
11405c.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;
11405if(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();
11406
11407	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)};
11408
11409
11410	/*
11411		jQuery hashchange event v1.3
11412		https://github.com/cowboy/jquery-hashchange
11413		Copyright (c) 2010 "Cowboy" Ben Alman
11414		Dual licensed under the MIT and GPL licenses.
11415	*/
11416	(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=
11417	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||
11418	"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;
11418a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
11419
11420	if (!Array.prototype.filter) {
11421		Array.prototype.filter = function(fun /*, thisp */ ) {
11422			"use strict";
11423
11424			if (this == null)
11425				throw new TypeError();
11426
11427			var t = Object(this);
11428			var len = t.length >>> 0;
11429			if (typeof fun != "function")
11430				throw new TypeError();
11431
11432			var res = [];
11433			var thisp = arguments[1];
11434			for (var i = 0; i < len; i++) {
11435				if (i in t) {
11436					var val = t[i]; // in case fun mutates this
11437					if (fun.call(thisp, val, i, t))
11438						res.push(val);
11439				}
11440			}
11441
11442			return res;
11443		};
11444	}
11445
11446	if (!Array.prototype.indexOf) {
11447		Array.prototype.indexOf = function(searchElement, fromIndex) {
11448			var k;
11449
11450			if (this == null) {
11451				throw new TypeError('"this" is null or not defined');
11452			}
11453
11454			var O = Object(this);
11455
11456			var len = O.length >>> 0;
11457
11458			if (len === 0) {
11459				return -1;
11460			}
11461
11462			var n = +fromIndex || 0;
11463
11464			if (abs(n) === Infinity) {
11465				n = 0;
11466			}
11467
11468			if (n >= len) {
11469				return -1;
11470			}
11471
11472			k = max(n >= 0 ? n : len - abs(n), 0);
11473
11474			while (k < len) {
11475				var kValue;
11476				if (k in O && O[k] === searchElement) {
11477					return k;
11478				}
11479				k++;
11480			}
11481			return -1;
11482		};
11483	}
11484
11485	if (!Array.prototype.lastIndexOf) {
11486		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
11487			"use strict";
11488
11489			if (this == null)
11490				throw new TypeError();
11491
11492			var t = Object(this);
11493			var len = t.length >>> 0;
11494			if (len === 0)
11495				return -1;
11496
11497			var n = len;
11498			if (arguments.length > 1) {
11499				n = Number(arguments[1]);
11500				if (n != n)
11501					n = 0;
11502				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
11503					n = (n > 0 || -1) * floor(abs(n));
11504			}
11505
11506			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
11507
11508			for (; k >= 0; k--) {
11509				if (k in t && t[k] === searchElement)
11510					return k;
11511			}
11512			return -1;
11513		};
11514	}
11515})(jQuery, this);
11516
11517/**
11518 * Owl carousel
vendor: 12,108 bytes, lines 11519-12025
11519 * @version 2.0.0-beta.3
11520 * @author Bartosz Wojciechowski
11521 * @license The MIT License (MIT)
11522 * @todo Lazy Load Icon
11523 * @todo prevent animationend bubling
11524 * @todo itemsScaleUp
11525 * @todo Test Zepto
11526 * @todo stagePadding calculate wrong active classes
11527 */
11528;(function($, window, document, undefined) {
11529
11530	/**
11531	 * Creates a carousel.
11532	 * @class The Owl Carousel.
11533	 * @public
11534	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
11535	 * @param {Object} [options] - The options
11536	 */
11537	function Owl(element, options) {
11538
11539		/**
11540		 * Current settings for the carousel.
11541		 * @public
11542		 */
11543		this.settings = null;
11544
11545		/**
11546		 * Current options set by the caller including defaults.
11547		 * @public
11548		 */
11549		this.options = $.extend({}, Owl.Defaults, options);
11550
11551		/**
11552		 * Plugin element.
11553		 * @public
11554		 */
11555		this.$element = $(element);
11556
11557		/**
11558		 * Proxied event handlers.
11559		 * @protected
11560		 */
11561		this._handlers = {};
11562
11563		/**
11564		 * References to the running plugins of this carousel.
11565		 * @protected
11566		 */
11567		this._plugins = {};
11568
11569		/**
11570		 * Currently suppressed events to prevent them from beeing retriggered.
11571		 * @protected
11572		 */
11573		this._supress = {};
11574
11575		/**
11576		 * Absolute current position.
11577		 * @protected
11578		 */
11579		this._current = null;
11580
11581		/**
11582		 * Animation speed in milliseconds.
11583		 * @protected
11584		 */
11585		this._speed = null;
11586
11587		/**
11588		 * Coordinates of all items in pixel.
11589		 * @todo The name of this member is missleading.
11590		 * @protected
11591		 */
11592		this._coordinates = [];
11593
11594		/**
11595		 * Current breakpoint.
11596		 * @todo Real media queries would be nice.
11597		 * @protected
11598		 */
11599		this._breakpoint = null;
11600
11601		/**
11602		 * Current width of the plugin element.
11603		 */
11604		this._width = null;
11605
11606		/**
11607		 * All real items.
11608		 * @protected
11609		 */
11610		this._items = [];
11611
11612		/**
11613		 * All cloned items.
11614		 * @protected
11615		 */
11616		this._clones = [];
11617
11618		/**
11619		 * Merge values of all items.
11620		 * @todo Maybe this could be part of a plugin.
11621		 * @protected
11622		 */
11623		this._mergers = [];
11624
11625		/**
11626		 * Widths of all items.
11627		 */
11628		this._widths = [];
11629
11630		/**
11631		 * Invalidated parts within the update process.
11632		 * @protected
11633		 */
11634		this._invalidated = {};
11635
11636		/**
11637		 * Ordered list of workers for the update process.
11638		 * @protected
11639		 */
11640		this._pipe = [];
11641
11642		/**
11643		 * Current state information for the drag operation.
11644		 * @todo #261
11645		 * @protected
11646		 */
11647		this._drag = {
11648			time: null,
11649			target: null,
11650			pointer: null,
11651			stage: {
11652				start: null,
11653				current: null
11654			},
11655			direction: null
11656		};
11657
11658		/**
11659		 * Current state information and their tags.
11660		 * @type {Object}
11661		 * @protected
11662		 */
11663		this._states = {
11664			current: {},
11665			tags: {
11666				'initializing': [ 'busy' ],
11667				'animating': [ 'busy' ],
11668				'dragging': [ 'interacting' ]
11669			}
11670		};
11671
11672		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
11673			this._handlers[handler] = $.proxy(this[handler], this);
11674		}, this));
11675
11676		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
11677			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
11678				= new plugin(this);
11679		}, this));
11680
11681		$.each(Owl.Workers, $.proxy(function(priority, worker) {
11682			this._pipe.push({
11683				'filter': worker.filter,
11684				'run': $.proxy(worker.run, this)
11685			});
11686		}, this));
11687
11688		this.setup();
11689		this.initialize();
11690	}
11691
11692	/**
11693	 * Default options for the carousel.
11694	 * @public
11695	 */
11696	Owl.Defaults = {
11697		items: 3,
11698		loop: false,
11699		center: false,
11700		rewind: false,
11701
11702		mouseDrag: true,
11703		touchDrag: true,
11704		pullDrag: true,
11705		freeDrag: false,
11706
11707		margin: 0,
11708		stagePadding: 0,
11709
11710		merge: false,
11711		mergeFit: true,
11712		autoWidth: false,
11713
11714		startPosition: 0,
11715		rtl: false,
11716
11717		smartSpeed: 250,
11718		fluidSpeed: false,
11719		dragEndSpeed: false,
11720
11721		responsive: {},
11722		responsiveRefreshRate: 200,
11723		responsiveBaseElement: window,
11724
11725		fallbackEasing: 'swing',
11726
11727		info: false,
11728
11729		nestedItemSelector: false,
11730		itemElement: 'div',
11731		stageElement: 'div',
11732
11733		refreshClass: 'owl-refresh',
11734		loadedClass: 'owl-loaded',
11735		loadingClass: 'owl-loading',
11736		rtlClass: 'owl-rtl',
11737		responsiveClass: 'owl-responsive',
11738		dragClass: 'owl-drag',
11739		itemClass: 'owl-item',
11740		stageClass: 'owl-stage',
11741		stageOuterClass: 'owl-stage-outer',
11742		grabClass: 'owl-grab'
11743	};
11744
11745	/**
11746	 * Enumeration for width.
11747	 * @public
11748	 * @readonly
11749	 * @enum {String}
11750	 */
11751	Owl.Width = {
11752		Default: 'default',
11753		Inner: 'inner',
11754		Outer: 'outer'
11755	};
11756
11757	/**
11758	 * Enumeration for types.
11759	 * @public
11760	 * @readonly
11761	 * @enum {String}
11762	 */
11763	Owl.Type = {
11764		Event: 'event',
11765		State: 'state'
11766	};
11767
11768	/**
11769	 * Contains all registered plugins.
11770	 * @public
11771	 */
11772	Owl.Plugins = {};
11773
11774	/**
11775	 * List of workers involved in the update process.
11776	 */
11777	Owl.Workers = [ {
11778		filter: [ 'width', 'settings' ],
11779		run: function() {
11780			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
11781			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
11782		}
11783	}, {
11784		filter: [ 'width', 'items', 'settings' ],
11785		run: function(cache) {
11786			cache.current = this._items && this._items[this.relative(this._current)];
11787		}
11788	}, {
11789		filter: [ 'items', 'settings' ],
11790		run: function() {
11791			this.$stage.children('.cloned').remove();
11792		}
11793	}, {
11794		filter: [ 'width', 'items', 'settings' ],
11795		run: function(cache) {
11796			var margin = this.settings.margin || '',
11797				grid = !this.settings.autoWidth,
11798				rtl = this.settings.rtl,
11799				css = {
11800					'width': 'auto',
11801					'margin-left': rtl ? margin : '',
11802					'margin-right': rtl ? '' : margin
11803				};
11804
11805			!grid && this.$stage.children().css(css);
11806
11807			cache.css = css;
11808		}
11809	}, {
11810		filter: [ 'width', 'items', 'settings' ],
11811		run: function(cache) {
11812			//UNCODE edit to fix Chrome stage padding issue
11813			var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin),
11814				merge = null,
11815				iterator = this._items.length,
11816				grid = !this.settings.autoWidth,
11817				widths = [];
11818
11819			cache.items = {
11820				merge: false,
11821				width: width
11822			};
11823
11824			while (iterator--) {
11825				merge = this._mergers[iterator];
11826				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
11827
11828				cache.items.merge = merge > 1 || cache.items.merge;
11829
11830				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
11831			}
11832
11833			this._widths = widths;
11834		}
11835	}, {
11836		filter: [ 'items', 'settings' ],
11837		run: function() {
11838			var clones = [],
11839				items = this._items,
11840				settings = this.settings,
11841				view = Math.max(settings.items * 2, 4),
11842				size = Math.ceil(items.length / 2) * 2,
11843				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
11844				append = '',
11845				prepend = '';
11846
11847			repeat /= 2;
11848
11849			while (repeat--) {
11850				clones.push(this.normalize(clones.length / 2, true));
11851				append = append + items[clones[clones.length - 1]][0].outerHTML;
11852				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
11853				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
11854			}
11855
11856			this._clones = clones;
11857
11858			// var appendVideo = $(append).find('.uncode-video-container');
11859			// if (appendVideo.length) {
11860			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
11861			// }
11862			// var prependVideo = $(prepend).find('.uncode-video-container');
11863			// if (prependVideo.length) {
11864			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
11865			// }
11866			$(append).addClass('cloned').appendTo(this.$stage);
11867			$(prepend).addClass('cloned').prependTo(this.$stage);
11868		}
11869	}, {
11870		filter: [ 'width', 'items', 'settings' ],
11871		run: function() {
11872			var rtl = this.settings.rtl ? 1 : -1,
11873				size = this._clones.length + this._items.length,
11874				iterator = -1,
11875				previous = 0,
11876				current = 0,
11877				coordinates = [];
11878
11879			while (++iterator < size) {
11880				previous = coordinates[iterator - 1] || 0;
11881				current = this._widths[this.relative(iterator)] + this.settings.margin;
11882				coordinates.push(previous + current * rtl);
11883			}
11884
11885			this._coordinates = coordinates;
11886		}
11887	}, {
11888		filter: [ 'width', 'items', 'settings' ],
11889		run: function() {
11890			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
11891				padding = stagePadding,
11892				coordinates = this._coordinates,
11893				css = {
11894					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
11895					'padding-left': padding || '',
11896					'padding-right': padding || ''
11897				};
11898
11899			this.$stage.css(css);
11900		}
11901	}, {
11902		filter: [ 'width', 'items', 'settings' ],
11903		run: function(cache) {
11904			var iterator = this._coordinates.length,
11905				grid = !this.settings.autoWidth,
11906				items = this.$stage.children();
11907
11908			if (grid && cache.items.merge) {
11909				while (iterator--) {
11910					cache.css.width = this._widths[this.relative(iterator)];
11911					items.eq(iterator).css(cache.css);
11912				}
11913			} else if (grid) {
11914				cache.css.width = cache.items.width;
11915				items.css(cache.css);
11916			}
11917		}
11918	}, {
11919		filter: [ 'items' ],
11920		run: function() {
11921			this._coordinates.length < 1 && this.$stage.removeAttr('style');
11922		}
11923	}, {
11924		filter: [ 'width', 'items', 'settings' ],
11925		run: function(cache) {
11926			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
11927			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
11928			this.reset(cache.current);
11929		}
11930	}, {
11931		filter: [ 'position' ],
11932		run: function() {
11933			this.animate(this.coordinates(this._current));
11934		}
11935	}, {
11936		filter: [ 'width', 'position', 'items', 'settings' ],
11937		run: function() {
11938			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
11939				rtl = this.settings.rtl ? 1 : -1,
11940				padding = this.settings.stagePadding * 2,
11941				begin = this.coordinates(this.current()) + padding,
11942				end = begin + this.width() * rtl,
11943				inner, outer, matches = [], i, n;
11944
11945			for (i = 0, n = this._coordinates.length; i < n; i++) {
11946				inner = this._coordinates[i - 1] || 0;
11947				outer = Math.abs(this._coordinates[i]) + padding * rtl;
11948
11949				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
11950					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
11951					matches.push(i);
11952				}
11953			}
11954
11955			this.$stage.children('.active').removeClass('active');
11956			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
11957
11958			if (this.settings.center) {
11959				this.$stage.children('.center').removeClass('center');
11960				this.$stage.children().eq(this.current()).addClass('center');
11961			}
11962		}
11963	} ];
11964
11965	/**
11966	 * Initializes the carousel.
11967	 * @protected
11968	 */
11969	Owl.prototype.initialize = function() {
11970		this.enter('initializing');
11971		this.trigger('initialize');
11972
11973		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
11974
11975		if (this.settings.autoWidth && !this.is('pre-loading')) {
11976			var imgs, nestedSelector, width;
11977			imgs = this.$element.find('img');
11978			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
11979			width = this.$element.children(nestedSelector).width();
11980
11981			if (imgs.length && width <= 0) {
11982				this.preloadAutoWidthImages(imgs);
11983			}
11984		}
11985
11986		this.$element.addClass(this.options.loadingClass);
11987
11988		// create stage
11989		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
11990			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
11991
11992		// append stage
11993		this.$element.append(this.$stage.parent());
11994
11995		// append content
11996		this.replace(this.$element.children().not(this.$stage.parent()));
11997
11998		// check visibility
11999		if (this.$element.is(':visible')) {
12000			// update view
12001			this.refresh();
12002		} else {
12003			// invalidate width
12004			this.invalidate('width');
12005		}
12006
12007		this.$element
12008			.removeClass(this.options.loadingClass)
12009			.addClass(this.options.loadedClass);
12010
12011		// register event handlers
12012		this.registerEventHandlers();
12013
12014		this.leave('initializing');
12015		this.trigger('initialized');
12016	};
12017
12018	/**
12019	 * Setups the current settings.
12020	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
12021	 * @todo Support for media queries by using `matchMedia` would be nice.
12022	 * @public
12023	 */
12024	Owl.prototype.setup = function() {
12025		var viewport = this.viewport(),
12026			overwrites = this.options.responsive,
12027			match = -1,
12028			settings = null;
12029
12030		if (!overwrites) {
12031			settings = $.extend({}, this.options);
12032		} else {
12033			$.each(overwrites, function(breakpoint) {
12034				if (breakpoint <= viewport && breakpoint > match) {
12035					match = Number(breakpoint);
12036				}
12037			});
12038
12039			settings = $.extend({}, this.options, overwrites[match]);
12040			delete settings.responsive;
12041
12042			// responsive class
12043			if (settings.responsiveClass) {
12044				this.$element.attr('class',
12045					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
12046				);
12047			}
12048		}
12049
12050		if (this.settings === null || this._breakpoint !== match) {
12051			this.trigger('change', { property: { name: 'settings', value: settings } });
12052			this._breakpoint = match;
12053			this.settings = settings;
12054			this.invalidate('settings');
12055			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
12056		}
12057	};
12058
12059	/**
12060	 * Updates option logic if necessery.
12061	 * @protected
12062	 */
12063	Owl.prototype.optionsLogic = function() {
12064		if (this.settings.autoWidth) {
12065			this.settings.stagePadding = false;
12066			this.settings.merge = false;
12067		}
12068	};
12069
12070	/**
12071	 * Prepares an item before add.
12072	 * @todo Rename event parameter `content` to `item`.
12073	 * @protected
12074	 * @returns {jQuery|HTMLElement} - The item container.
12075	 */
12076	Owl.prototype.prepare = function(item, index) {
12077		var event = this.trigger('prepare', { content: item });
12078		if (!event.data) {
12079			event.data = $('<' + this.settings.itemElement + '/>')
12080				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
12081		}
12082
12083		this.trigger('prepared', { content: event.data });
12084
12085		return event.data;
12086	};
12087
12088	/**
12089	 * Updates the view.
12090	 * @public
12091	 */
12092	Owl.prototype.update = function() {
12093		var i = 0,
12094			n = this._pipe.length,
12095			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
12096			cache = {};
12097
12098		while (i < n) {
12099			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
12100				this._pipe[i].run(cache);
12101			}
12102			i++;
12103		}
12104
12105		this._invalidated = {};
12106
12107		!this.is('valid') && this.enter('valid');
12108	};
12109
12110	/**
12111	 * Gets the width of the view.
12112	 * @public
12113	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
12114	 * @returns {Number} - The width of the view in pixel.
12115	 */
12116	Owl.prototype.width = function(dimension) {
12117		dimension = dimension || Owl.Width.Default;
12118		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
12119		switch (dimension) {
12120			case Owl.Width.Inner:
12121			case Owl.Width.Outer:
12122				return this._width;
12123			default:
12124				return this._width - stagePadding * 2 + this.settings.margin;
12125		}
12126	};
12127
12128	/**
12129	 * Refreshes the carousel primarily for adaptive purposes.
12130	 * @public
12131	 */
12132	Owl.prototype.refresh = function() {
12133		this.enter('refreshing');
12134		this.trigger('refresh');
12135
12136		this.setup();
12137
12138		this.optionsLogic();
12139
12140		this.$element.addClass(this.options.refreshClass);
12141
12142		this.update();
12143
12144		this.$element.removeClass(this.options.refreshClass);
12145
12146		this.leave('refreshing');
12147		this.trigger('refreshed');
12148	};
12149
12150	/**
12151	 * Checks window `resize` event.
12152	 * @protected
12153	 */
12154	Owl.prototype.onThrottledResize = function() {
12155		window.clearTimeout(this.resizeTimer);
12156		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
12157	};
12158
12159	/**
12160	 * Checks window `resize` event.
12161	 * @protected
12162	 */
12163	Owl.prototype.onResize = function() {
12164		if (!this._items.length) {
12165			return false;
12166		}
12167
12168		if (this._width === this.$element.width()) {
12169			return false;
12170		}
12171
12172		if (!this.$element.is(':visible')) {
12173			return false;
12174		}
12175
12176		this.enter('resizing');
12177
12178		if (this.trigger('resize').isDefaultPrevented()) {
12179			this.leave('resizing');
12180			return false;
12181		}
12182
12183		this.invalidate('width');
12184
12185		this.refresh();
12186
12187		this.leave('resizing');
12188		this.trigger('resized');
12189	};
12190
12191	/**
12192	 * Registers event handlers.
12193	 * @todo Check `msPointerEnabled`
12194	 * @todo #261
12195	 * @protected
12196	 */
12197	Owl.prototype.registerEventHandlers = function() {
12198		if ($.support.transition) {
12199			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
12200		}
12201
12202		if (this.settings.responsive !== false) {
12203			this.on(window, 'resize', this._handlers.onThrottledResize);
12204		}
12205
12206		if (this.settings.mouseDrag) {
12207			this.$element.addClass(this.options.dragClass);
12208			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
12209			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
12210		}
12211
12212		if (this.settings.touchDrag){
12213			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
12214			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
12215		}
12216	};
12217
12218	/**
12219	 * Handles `touchstart` and `mousedown` events.
12220	 * @todo Horizontal swipe threshold as option
12221	 * @todo #261
12222	 * @protected
12223	 * @param {Event} event - The event arguments.
12224	 */
12225	Owl.prototype.onDragStart = function(event) {
12226		var stage = null;
12227
12228		if (event.which === 3) {
12229			return;
12230		}
12231
vendor: 9,106 bytes, lines 12232-12547
12232		if ($.support.transform) {
12233			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
12234			stage = {
12235				x: stage[stage.length === 16 ? 12 : 4],
12236				y: stage[stage.length === 16 ? 13 : 5]
12237			};
12238		} else {
12239			stage = this.$stage.position();
12240			stage = {
12241				x: this.settings.rtl ?
12242					stage.left + this.$stage.width() - this.width() + this.settings.margin :
12243					stage.left,
12244				y: stage.top
12245			};
12246		}
12247
12248		if (this.is('animating')) {
12249			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
12250			this.invalidate('position');
12251		}
12252
12253		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
12254
12255		this.speed(0);
12256
12257		this._drag.time = new Date().getTime();
12258		this._drag.target = $(event.target);
12259		this._drag.stage.start = stage;
12260		this._drag.stage.current = stage;
12261		this._drag.pointer = this.pointer(event);
12262
12263		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
12264
12265		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
12266			var delta = this.difference(this._drag.pointer, this.pointer(event));
12267
12268			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
12269
12270			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
12271				return;
12272			}
12273
12274			event.preventDefault();
12275
12276			this.enter('dragging');
12277			this.trigger('drag');
12278		}, this));
12279	};
12280
12281	/**
12282	 * Handles the `touchmove` and `mousemove` events.
12283	 * @todo #261
12284	 * @protected
12285	 * @param {Event} event - The event arguments.
12286	 */
12287	Owl.prototype.onDragMove = function(event) {
12288		var minimum = null,
12289			maximum = null,
12290			pull = null,
12291			delta = this.difference(this._drag.pointer, this.pointer(event)),
12292			stage = this.difference(this._drag.stage.start, delta);
12293
12294		if (!this.is('dragging')) {
12295			return;
12296		}
12297
12298		event.preventDefault();
12299
12300		if (this.settings.loop) {
12301			minimum = this.coordinates(this.minimum());
12302			maximum = this.coordinates(this.maximum() + 1) - minimum;
12303			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
12304		} else {
12305			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
12306			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
12307			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
12308			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
12309		}
12310
12311		this._drag.stage.current = stage;
12312
12313		this.animate(stage.x);
12314	};
12315
12316	/**
12317	 * Handles the `touchend` and `mouseup` events.
12318	 * @todo #261
12319	 * @todo Threshold for click event
12320	 * @protected
12321	 * @param {Event} event - The event arguments.
12322	 */
12323	Owl.prototype.onDragEnd = function(event) {
12324		var delta = this.difference(this._drag.pointer, this.pointer(event)),
12325			stage = this._drag.stage.current,
12326			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
12327
12328		$(document).off('.owl.core');
12329
12330		this.$element.removeClass(this.options.grabClass);
12331
12332		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
12333			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
12334			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
12335			this.invalidate('position');
12336			this.update();
12337
12338			this._drag.direction = direction;
12339
12340			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
12341				this._drag.target.one('click.owl.core', function() { return false; });
12342			}
12343		}
12344
12345		if (!this.is('dragging')) {
12346			return;
12347		}
12348
12349		this.leave('dragging');
12350		this.trigger('dragged');
12351	};
12352
12353	/**
12354	 * Gets absolute position of the closest item for a coordinate.
12355	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
12356	 * @protected
12357	 * @param {Number} coordinate - The coordinate in pixel.
12358	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
12359	 * @return {Number} - The absolute position of the closest item.
12360	 */
12361	Owl.prototype.closest = function(coordinate, direction) {
12362		var position = -1,
12363			pull = 30,
12364			width = this.width(),
12365			coordinates = this.coordinates();
12366
12367		if (!this.settings.freeDrag) {
12368			// check closest item
12369			$.each(coordinates, $.proxy(function(index, value) {
12370				if (coordinate > value - pull && coordinate < value + pull) {
12371					position = index;
12372				} else if (this.op(coordinate, '<', value)
12373					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
12374					position = direction === 'left' ? index + 1 : index;
12375				}
12376				return position === -1;
12377			}, this));
12378		}
12379
12380		if (!this.settings.loop) {
12381			// non loop boundries
12382			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
12383				position = coordinate = this.minimum();
12384			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
12385				position = coordinate = this.maximum();
12386			}
12387		}
12388
12389		return position;
12390	};
12391
12392	/**
12393	 * Animates the stage.
12394	 * @todo #270
12395	 * @public
12396	 * @param {Number} coordinate - The coordinate in pixels.
12397	 */
12398	Owl.prototype.animate = function(coordinate) {
12399		var animate = this.speed() > 0;
12400
12401		this.is('animating') && this.onTransitionEnd();
12402
12403		if (animate) {
12404			this.enter('animating');
12405			this.trigger('translate');
12406		}
12407
12408		if ($.support.transform3d && $.support.transition) {
12409			this.$stage.css({
12410				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
12411				transition: (this.speed() / 1000) + 's'
12412			});
12413		} else if (animate) {
12414			this.$stage.animate({
12415				left: coordinate + 'px'
12416			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
12417		} else {
12418			this.$stage.css({
12419				left: coordinate + 'px'
12420			});
12421		}
12422	};
12423
12424	/**
12425	 * Checks whether the carousel is in a specific state or not.
12426	 * @param {String} state - The state to check.
12427	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
12428	 */
12429	Owl.prototype.is = function(state) {
12430		return this._states.current[state] && this._states.current[state] > 0;
12431	};
12432
12433	/**
12434	 * Sets the absolute position of the current item.
12435	 * @public
12436	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
12437	 * @returns {Number} - The absolute position of the current item.
12438	 */
12439	Owl.prototype.current = function(position) {
12440		if (position === undefined) {
12441			return this._current;
12442		}
12443
12444		if (this._items.length === 0) {
12445			return undefined;
12446		}
12447
12448		position = this.normalize(position);
12449
12450		if (this._current !== position) {
12451			var event = this.trigger('change', { property: { name: 'position', value: position } });
12452
12453			if (event.data !== undefined) {
12454				position = this.normalize(event.data);
12455			}
12456
12457			this._current = position;
12458
12459			this.invalidate('position');
12460
12461			this.trigger('changed', { property: { name: 'position', value: this._current } });
12462		}
12463
12464		return this._current;
12465	};
12466
12467	/**
12468	 * Invalidates the given part of the update routine.
12469	 * @param {String} [part] - The part to invalidate.
12470	 * @returns {Array.<String>} - The invalidated parts.
12471	 */
12472	Owl.prototype.invalidate = function(part) {
12473		if ($.type(part) === 'string') {
12474			this._invalidated[part] = true;
12475			this.is('valid') && this.leave('valid');
12476		}
12477		return $.map(this._invalidated, function(v, i) { return i });
12478	};
12479
12480	/**
12481	 * Resets the absolute position of the current item.
12482	 * @public
12483	 * @param {Number} position - The absolute position of the new item.
12484	 */
12485	Owl.prototype.reset = function(position) {
12486		position = this.normalize(position);
12487
12488		if (position === undefined) {
12489			return;
12490		}
12491
12492		this._speed = 0;
12493		this._current = position;
12494
12495		this.suppress([ 'translate', 'translated' ]);
12496
12497		this.animate(this.coordinates(position));
12498
12499		this.release([ 'translate', 'translated' ]);
12500	};
12501
12502	/**
12503	 * Normalizes an absolute or a relative position of an item.
12504	 * @public
12505	 * @param {Number} position - The absolute or relative position to normalize.
12506	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
12507	 * @returns {Number} - The normalized position.
12508	 */
12509	Owl.prototype.normalize = function(position, relative) {
12510		var n = this._items.length,
12511			m = relative ? 0 : this._clones.length;
12512
12513		if (!$.isNumeric(position) || n < 1) {
12514			position = undefined;
12515		} else if (position < 0 || position >= n + m) {
12516			position = ((position - m / 2) % n + n) % n + m / 2;
12517		}
12518
12519		return position;
12520	};
12521
12522	/**
12523	 * Converts an absolute position of an item into a relative one.
12524	 * @public
12525	 * @param {Number} position - The absolute position to convert.
12526	 * @returns {Number} - The converted position.
12527	 */
12528	Owl.prototype.relative = function(position) {
12529		position -= this._clones.length / 2;
12530		return this.normalize(position, true);
12531	};
12532
12533	/**
12534	 * Gets the maximum position for the current item.
12535	 * @public
12536	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
12537	 * @returns {Number}
12538	 */
12539	Owl.prototype.maximum = function(relative) {
12540		var settings = this.settings,
12541			maximum = this._coordinates.length,
12542			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
12543			i = -1, j;
12544
12545		if (settings.loop) {
12546			maximum = this._clones.length / 2 + this._items.length - 1;
12547		} else if (settings.autoWidth || settings.merge) {
12548			// binary search
12549			while (maximum - i > 1) {
12550				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
12551					? i = j : maximum = j;
12552			}
12553		} else if (settings.center) {
12554			maximum = this._items.length - 1;
12555		} else {
12556			maximum = this._items.length - settings.items;
12557		}
12558
12559		if (relative) {
12560			maximum -= this._clones.length / 2;
12561		}
12562
12563		return Math.max(maximum, 0);
12564	};
12565
12566	/**
12567	 * Gets the minimum position for the current item.
12568	 * @public
12569	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
12570	 * @returns {Number}
12571	 */
12572	Owl.prototype.minimum = function(relative) {
12573		return relative ? 0 : this._clones.length / 2;
12574	};
12575
12576	/**
12577	 * Gets an item at the specified relative position.
12578	 * @public
12579	 * @param {Number} [position] - The relative position of the item.
12580	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
12581	 */
12582	Owl.prototype.items = function(position) {
12583		if (position === undefined) {
12584			return this._items.slice();
12585		}
12586
12587		position = this.normalize(position, true);
12588		return this._items[position];
12589	};
12590
12591	/**
12592	 * Gets an item at the specified relative position.
12593	 * @public
12594	 * @param {Number} [position] - The relative position of the item.
12595	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
12596	 */
12597	Owl.prototype.mergers = function(position) {
12598		if (position === undefined) {
12599			return this._mergers.slice();
12600		}
12601
12602		position = this.normalize(position, true);
12603		return this._mergers[position];
12604	};
12605
12606	/**
12607	 * Gets the absolute positions of clones for an item.
12608	 * @public
12609	 * @param {Number} [position] - The relative position of the item.
12610	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
12611	 */
12612	Owl.prototype.clones = function(position) {
12613		var odd = this._clones.length / 2,
12614			even = odd + this._items.length,
12615			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
12616
12617		if (position === undefined) {
12618			return $.map(this._clones, function(v, i) { return map(i) });
12619		}
12620
12621		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
12622	};
12623
12624	/**
12625	 * Sets the current animation speed.
12626	 * @public
12627	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
12628	 * @returns {Number} - The current animation speed in milliseconds.
12629	 */
12630	Owl.prototype.speed = function(speed) {
12631		if (speed !== undefined) {
12632			this._speed = speed;
12633		}
12634
12635		return this._speed;
12636	};
12637
12638	/**
12639	 * Gets the coordinate of an item.
12640	 * @todo The name of this method is missleanding.
12641	 * @public
12642	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
12643	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
12644	 */
12645	Owl.prototype.coordinates = function(position) {
12646		var coordinate = null;
12647
12648		if (position === undefined) {
12649			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
12650				return this.coordinates(index);
12651			}, this));
12652		}
12653
12654		if (this.settings.center) {
12655			coordinate = this._coordinates[position];
12656			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
12657		} else {
12658			coordinate = this._coordinates[position - 1] || 0;
12659		}
12660
12661		return coordinate;
12662	};
12663
12664	/**
12665	 * Calculates the speed for a translation.
12666	 * @protected
12667	 * @param {Number} from - The absolute position of the start item.
12668	 * @param {Number} to - The absolute position of the target item.
12669	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
12670	 * @returns {Number} - The time in milliseconds for the translation.
12671	 */
12672	Owl.prototype.duration = function(from, to, factor) {
12673		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
12674	};
12675
12676	/**
12677	 * Slides to the specified item.
12678	 * @public
12679	 * @param {Number} position - The position of the item.
12680	 * @param {Number} [speed] - The time in milliseconds for the transition.
12681	 */
12682	Owl.prototype.to = function(position, speed) {
12683		var current = this.current(),
12684			revert = null,
12685			distance = position - this.relative(current),
12686			direction = (distance > 0) - (distance < 0),
12687			items = this._items.length,
12688			minimum = this.minimum(),
12689			maximum = this.maximum();
12690
12691		if (this.settings.loop) {
12692			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
12693				distance += direction * -1 * items;
12694			}
12695
12696			position = current + distance;
12697			revert = ((position - minimum) % items + items) % items + minimum;
12698
12699			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
12700				current = revert - distance;
12701				position = revert;
12702				this.reset(current);
12703			}
12704		} else if (this.settings.rewind) {
12705			maximum += 1;
12706			position = (position % maximum + maximum) % maximum;
12707		} else {
12708			position = Math.max(minimum, Math.min(maximum, position));
12709		}
12710
12711		this.speed(this.duration(current, position, speed));
12712		this.current(position);
12713
12714		if (this.$element.is(':visible')) {
12715			this.update();
12716		}
12717	};
12718
12719	/**
12720	 * Slides to the next item.
12721	 * @public
12722	 * @param {Number}
vendor: 12,284 bytes, lines 12722-13142
12722 [speed] - The time in milliseconds for the transition.
12723	 */
12724	Owl.prototype.next = function(speed) {
12725		speed = speed || false;
12726		this.to(this.relative(this.current()) + 1, speed);
12727	};
12728
12729	/**
12730	 * Slides to the previous item.
12731	 * @public
12732	 * @param {Number} [speed] - The time in milliseconds for the transition.
12733	 */
12734	Owl.prototype.prev = function(speed) {
12735		speed = speed || false;
12736		this.to(this.relative(this.current()) - 1, speed);
12737	};
12738
12739	/**
12740	 * Handles the end of an animation.
12741	 * @protected
12742	 * @param {Event} event - The event arguments.
12743	 */
12744	Owl.prototype.onTransitionEnd = function(event) {
12745
12746		// if css2 animation then event object is undefined
12747		if (event !== undefined) {
12748			event.stopPropagation();
12749
12750			// Catch only owl-stage transitionEnd event
12751			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
12752				return false;
12753			}
12754		}
12755
12756		this.leave('animating');
12757		this.trigger('translated');
12758	};
12759
12760	/**
12761	 * Gets viewport width.
12762	 * @protected
12763	 * @return {Number} - The width in pixel.
12764	 */
12765	Owl.prototype.viewport = function() {
12766		var width;
12767		if (this.options.responsiveBaseElement !== window) {
12768			width = $(this.options.responsiveBaseElement).width();
12769		} else if (window.innerWidth) {
12770			width = window.innerWidth;
12771		} else if (document.documentElement && document.documentElement.clientWidth) {
12772			width = document.documentElement.clientWidth;
12773		} else {
12774			throw 'Can not detect viewport width.';
12775		}
12776
12777		return width;
12778	};
12779
12780	/**
12781	 * Replaces the current content.
12782	 * @public
12783	 * @param {HTMLElement|jQuery|String} content - The new content.
12784	 */
12785	Owl.prototype.replace = function(content) {
12786		this.$stage.empty();
12787		this._items = [];
12788
12789		if (content) {
12790			content = (content instanceof jQuery) ? content : $(content);
12791		}
12792
12793		if (this.settings.nestedItemSelector) {
12794			content = content.find('.' + this.settings.nestedItemSelector);
12795		}
12796
12797		content.filter(function() {
12798			return this.nodeType === 1;
12799		}).each($.proxy(function(index, item) {
12800			item = this.prepare(item, index);
12801			this.$stage.append(item);
12802			this._items.push(item);
12803			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
12804		}, this));
12805
12806		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
12807
12808		this.invalidate('items');
12809	};
12810
12811	/**
12812	 * Adds an item.
12813	 * @todo Use `item` instead of `content` for the event arguments.
12814	 * @public
12815	 * @param {HTMLElement|jQuery|String} content - The item content to add.
12816	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
12817	 */
12818	Owl.prototype.add = function(content, position) {
12819		var current = this.relative(this._current);
12820
12821		position = position === undefined ? this._items.length : this.normalize(position, true);
12822		content = content instanceof jQuery ? content : $(content);
12823
12824		this.trigger('add', { content: content, position: position });
12825
12826		content = this.prepare(content, this._items[current].index());
12827
12828		if (this._items.length === 0 || position === this._items.length) {
12829			this._items.length === 0 && this.$stage.append(content);
12830			this._items.length !== 0 && this._items[position - 1].after(content);
12831			this._items.push(content);
12832			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
12833		} else {
12834			this._items[position].before(content);
12835			this._items.splice(position, 0, content);
12836			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
12837		}
12838
12839		this._items[current] && this.reset(this._items[current].index());
12840
12841		this.invalidate('items');
12842
12843		this.trigger('added', { content: content, position: position });
12844	};
12845
12846	/**
12847	 * Removes an item by its position.
12848	 * @todo Use `item` instead of `content` for the event arguments.
12849	 * @public
12850	 * @param {Number} position - The relative position of the item to remove.
12851	 */
12852	Owl.prototype.remove = function(position) {
12853		position = this.normalize(position, true);
12854
12855		if (position === undefined) {
12856			return;
12857		}
12858
12859		this.trigger('remove', { content: this._items[position], position: position });
12860
12861		this._items[position].remove();
12862		this._items.splice(position, 1);
12863		this._mergers.splice(position, 1);
12864
12865		this.invalidate('items');
12866
12867		this.trigger('removed', { content: null, position: position });
12868	};
12869
12870	/**
12871	 * Preloads images with auto width.
12872	 * @todo Replace by a more generic approach
12873	 * @protected
12874	 */
12875	Owl.prototype.preloadAutoWidthImages = function(images) {
12876		images.each($.proxy(function(i, element) {
12877			this.enter('pre-loading');
12878			element = $(element);
12879			$(new Image()).one('load', $.proxy(function(e) {
12880				element.attr('src', e.target.src);
12881				element.css('opacity', 1);
12882				this.leave('pre-loading');
12883				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
12884			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
12885		}, this));
12886	};
12887
12888	/**
12889	 * Destroys the carousel.
12890	 * @public
12891	 */
12892	Owl.prototype.destroy = function() {
12893
12894		this.$element.off('.owl.core');
12895		this.$stage.off('.owl.core');
12896		$(document).off('.owl.core');
12897
12898		if (this.settings.responsive !== false) {
12899			window.clearTimeout(this.resizeTimer);
12900			this.off(window, 'resize', this._handlers.onThrottledResize);
12901		}
12902
12903		for (var i in this._plugins) {
12904			this._plugins[i].destroy();
12905		}
12906
12907		this.$stage.children('.cloned').remove();
12908
12909		this.$stage.unwrap();
12910		this.$stage.children().contents().unwrap();
12911		this.$stage.children().unwrap();
12912
12913		this.$element
12914			.removeClass(this.options.refreshClass)
12915			.removeClass(this.options.loadingClass)
12916			.removeClass(this.options.loadedClass)
12917			.removeClass(this.options.rtlClass)
12918			.removeClass(this.options.dragClass)
12919			.removeClass(this.options.grabClass)
12920			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
12921			.removeData('owl.carousel');
12922	};
12923
12924	/**
12925	 * Operators to calculate right-to-left and left-to-right.
12926	 * @protected
12927	 * @param {Number} [a] - The left side operand.
12928	 * @param {String} [o] - The operator.
12929	 * @param {Number} [b] - The right side operand.
12930	 */
12931	Owl.prototype.op = function(a, o, b) {
12932		var rtl = this.settings.rtl;
12933		switch (o) {
12934			case '<':
12935				return rtl ? a > b : a < b;
12936			case '>':
12937				return rtl ? a < b : a > b;
12938			case '>=':
12939				return rtl ? a <= b : a >= b;
12940			case '<=':
12941				return rtl ? a >= b : a <= b;
12942			default:
12943				break;
12944		}
12945	};
12946
12947	/**
12948	 * Attaches to an internal event.
12949	 * @protected
12950	 * @param {HTMLElement} element - The event source.
12951	 * @param {String} event - The event name.
12952	 * @param {Function} listener - The event handler to attach.
12953	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
12954	 */
12955	Owl.prototype.on = function(element, event, listener, capture) {
12956		if (element.addEventListener) {
12957			element.addEventListener(event, listener, capture);
12958		} else if (element.attachEvent) {
12959			element.attachEvent('on' + event, listener);
12960		}
12961	};
12962
12963	/**
12964	 * Detaches from an internal event.
12965	 * @protected
12966	 * @param {HTMLElement} element - The event source.
12967	 * @param {String} event - The event name.
12968	 * @param {Function} listener - The attached event handler to detach.
12969	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
12970	 */
12971	Owl.prototype.off = function(element, event, listener, capture) {
12972		if (element.removeEventListener) {
12973			element.removeEventListener(event, listener, capture);
12974		} else if (element.detachEvent) {
12975			element.detachEvent('on' + event, listener);
12976		}
12977	};
12978
12979	/**
12980	 * Triggers a public event.
12981	 * @todo Remove `status`, `relatedTarget` should be used instead.
12982	 * @protected
12983	 * @param {String} name - The event name.
12984	 * @param {*} [data=null] - The event data.
12985	 * @param {String} [namespace=carousel] - The event namespace.
12986	 * @param {String} [state] - The state which is associated with the event.
12987	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
12988	 * @returns {Event} - The event arguments.
12989	 */
12990	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
12991		var status = {
12992			item: { count: this._items.length, index: this.current() }
12993		}, handler = $.camelCase(
12994			$.grep([ 'on', name, namespace ], function(v) { return v })
12995				.join('-').toLowerCase()
12996		), event = $.Event(
12997			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
12998			$.extend({ relatedTarget: this }, status, data)
12999		);
13000
13001		if (!this._supress[name]) {
13002			$.each(this._plugins, function(name, plugin) {
13003				if (plugin.onTrigger) {
13004					plugin.onTrigger(event);
13005				}
13006			});
13007
13008			this.register({ type: Owl.Type.Event, name: name });
13009			this.$element.trigger(event);
13010
13011			if (this.settings && typeof this.settings[handler] === 'function') {
13012				this.settings[handler].call(this, event);
13013			}
13014		}
13015
13016		return event;
13017	};
13018
13019	/**
13020	 * Enters a state.
13021	 * @param name - The state name.
13022	 */
13023	Owl.prototype.enter = function(name) {
13024		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
13025			if (this._states.current[name] === undefined) {
13026				this._states.current[name] = 0;
13027			}
13028
13029			this._states.current[name]++;
13030		}, this));
13031	};
13032
13033	/**
13034	 * Leaves a state.
13035	 * @param name - The state name.
13036	 */
13037	Owl.prototype.leave = function(name) {
13038		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
13039			this._states.current[name]--;
13040		}, this));
13041	};
13042
13043	/**
13044	 * Registers an event or state.
13045	 * @public
13046	 * @param {Object} object - The event or state to register.
13047	 */
13048	Owl.prototype.register = function(object) {
13049		if (object.type === Owl.Type.Event) {
13050			if (!$.event.special[object.name]) {
13051				$.event.special[object.name] = {};
13052			}
13053
13054			if (!$.event.special[object.name].owl) {
13055				var _default = $.event.special[object.name]._default;
13056				$.event.special[object.name]._default = function(e) {
13057					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
13058						return _default.apply(this, arguments);
13059					}
13060					return e.namespace && e.namespace.indexOf('owl') > -1;
13061				};
13062				$.event.special[object.name].owl = true;
13063			}
13064		} else if (object.type === Owl.Type.State) {
13065			if (!this._states.tags[object.name]) {
13066				this._states.tags[object.name] = object.tags;
13067			} else {
13068				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
13069			}
13070
13071			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
13072				return $.inArray(tag, this._states.tags[object.name]) === i;
13073			}, this));
13074		}
13075	};
13076
13077	/**
13078	 * Suppresses events.
13079	 * @protected
13080	 * @param {Array.<String>} events - The events to suppress.
13081	 */
13082	Owl.prototype.suppress = function(events) {
13083		$.each(events, $.proxy(function(index, event) {
13084			this._supress[event] = true;
13085		}, this));
13086	};
13087
13088	/**
13089	 * Releases suppressed events.
13090	 * @protected
13091	 * @param {Array.<String>} events - The events to release.
13092	 */
13093	Owl.prototype.release = function(events) {
13094		$.each(events, $.proxy(function(index, event) {
13095			delete this._supress[event];
13096		}, this));
13097	};
13098
13099	/**
13100	 * Gets unified pointer coordinates from event.
13101	 * @todo #261
13102	 * @protected
13103	 * @param {Event} - The `mousedown` or `touchstart` event.
13104	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
13105	 */
13106	Owl.prototype.pointer = function(event) {
13107		var result = { x: null, y: null };
13108
13109		event = event.originalEvent || event || window.event;
13110
13111		event = event.touches && event.touches.length ?
13112			event.touches[0] : event.changedTouches && event.changedTouches.length ?
13113				event.changedTouches[0] : event;
13114
13115		if (event.pageX) {
13116			result.x = event.pageX;
13117			result.y = event.pageY;
13118		} else {
13119			result.x = event.clientX;
13120			result.y = event.clientY;
13121		}
13122
13123		return result;
13124	};
13125
13126	/**
13127	 * Gets the difference of two vectors.
13128	 * @todo #261
13129	 * @protected
13130	 * @param {Object} - The first vector.
13131	 * @param {Object} - The second vector.
13132	 * @returns {Object} - The difference.
13133	 */
13134	Owl.prototype.difference = function(first, second) {
13135		return {
13136			x: first.x - second.x,
13137			y: first.y - second.y
13138		};
13139	};
13140
13141	/**
13142	 * The jQuery Plugin for the Owl Carousel
vendor: 32,216 bytes, lines 13143-14425
13143	 * @todo Navigation plugin `next` and `prev`
13144	 * @public
13145	 */
13146	$.fn.owlCarousel = function(option) {
13147		var args = Array.prototype.slice.call(arguments, 1);
13148
13149		return this.each(function() {
13150			var $this = $(this),
13151				data = $this.data('owl.carousel');
13152
13153			if (!data) {
13154				data = new Owl(this, typeof option == 'object' && option);
13155				$this.data('owl.carousel', data);
13156
13157				$.each([
13158					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
13159				], function(i, event) {
13160					data.register({ type: Owl.Type.Event, name: event });
13161					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
13162						if (e.namespace && e.relatedTarget !== this) {
13163							this.suppress([ event ]);
13164							data[event].apply(this, [].slice.call(arguments, 1));
13165							this.release([ event ]);
13166						}
13167					}, data));
13168				});
13169			}
13170
13171			if (typeof option == 'string' && option.charAt(0) !== '_') {
13172				data[option].apply(data, args);
13173			}
13174		});
13175	};
13176
13177	/**
13178	 * The constructor for the jQuery Plugin
13179	 * @public
13180	 */
13181	$.fn.owlCarousel.Constructor = Owl;
13182
13183})(window.Zepto || window.jQuery, window, document);
13184
13185/**
13186 * AutoRefresh Plugin
13187 * @version 2.0.0-beta.3
13188 * @author Artus Kolanowski
13189 * @license The MIT License (MIT)
13190 */
13191;(function($, window, document, undefined) {
13192
13193	/**
13194	 * Creates the auto refresh plugin.
13195	 * @class The Auto Refresh Plugin
13196	 * @param {Owl} carousel - The Owl Carousel
13197	 */
13198	var AutoRefresh = function(carousel) {
13199		/**
13200		 * Reference to the core.
13201		 * @protected
13202		 * @type {Owl}
13203		 */
13204		this._core = carousel;
13205
13206		/**
13207		 * Refresh interval.
13208		 * @protected
13209		 * @type {number}
13210		 */
13211		this._interval = null;
13212
13213		/**
13214		 * Whether the element is currently visible or not.
13215		 * @protected
13216		 * @type {Boolean}
13217		 */
13218		this._visible = null;
13219
13220		/**
13221		 * All event handlers.
13222		 * @protected
13223		 * @type {Object}
13224		 */
13225		this._handlers = {
13226			'initialized.owl.carousel': $.proxy(function(e) {
13227				if (e.namespace && this._core.settings.autoRefresh) {
13228					this.watch();
13229				}
13230			}, this)
13231		};
13232
13233		// set default options
13234		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
13235
13236		// register event handlers
13237		this._core.$element.on(this._handlers);
13238	};
13239
13240	/**
13241	 * Default options.
13242	 * @public
13243	 */
13244	AutoRefresh.Defaults = {
13245		autoRefresh: true,
13246		autoRefreshInterval: 500
13247	};
13248
13249	/**
13250	 * Watches the element.
13251	 */
13252	AutoRefresh.prototype.watch = function() {
13253		if (this._interval) {
13254			return;
13255		}
13256
13257		this._visible = this._core.$element.is(':visible');
13258		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
13259	};
13260
13261	/**
13262	 * Refreshes the element.
13263	 */
13264	AutoRefresh.prototype.refresh = function() {
13265		if (this._core.$element.is(':visible') === this._visible) {
13266			return;
13267		}
13268
13269		this._visible = !this._visible;
13270
13271		this._core.$element.toggleClass('owl-hidden', !this._visible);
13272
13273		this._visible && (this._core.invalidate('width') && this._core.refresh());
13274	};
13275
13276	/**
13277	 * Destroys the plugin.
13278	 */
13279	AutoRefresh.prototype.destroy = function() {
13280		var handler, property;
13281
13282		window.clearInterval(this._interval);
13283
13284		for (handler in this._handlers) {
13285			this._core.$element.off(handler, this._handlers[handler]);
13286		}
13287		for (property in Object.getOwnPropertyNames(this)) {
13288			typeof this[property] != 'function' && (this[property] = null);
13289		}
13290	};
13291
13292	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
13293
13294})(window.Zepto || window.jQuery, window, document);
13295
13296/**
13297 * Lazy Plugin
13298 * @version 2.0.0-beta.3
13299 * @author Bartosz Wojciechowski
13300 * @license The MIT License (MIT)
13301 */
13302;(function($, window, document, undefined) {
13303
13304	/**
13305	 * Creates the lazy plugin.
13306	 * @class The Lazy Plugin
13307	 * @param {Owl} carousel - The Owl Carousel
13308	 */
13309	var Lazy = function(carousel) {
13310
13311		/**
13312		 * Reference to the core.
13313		 * @protected
13314		 * @type {Owl}
13315		 */
13316		this._core = carousel;
13317
13318		/**
13319		 * Already loaded items.
13320		 * @protected
13321		 * @type {Array.<jQuery>}
13322		 */
13323		this._loaded = [];
13324
13325		/**
13326		 * Event handlers.
13327		 * @protected
13328		 * @type {Object}
13329		 */
13330		this._handlers = {
13331			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
13332				if (!e.namespace) {
13333					return;
13334				}
13335
13336				if (!this._core.settings || !this._core.settings.lazyLoad) {
13337					return;
13338				}
13339
13340				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
13341					var settings = this._core.settings,
13342						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
13343						i = ((settings.center && n * -1) || 0),
13344						position = ((e.property && e.property.value) || this._core.current()) + i,
13345						clones = this._core.clones().length,
13346						load = $.proxy(function(i, v) { this.load(v) }, this);
13347
13348					while (i++ < n) {
13349						this.load(clones / 2 + this._core.relative(position));
13350						clones && $.each(this._core.clones(this._core.relative(position)), load);
13351						position++;
13352					}
13353				}
13354			}, this)
13355		};
13356
13357		// set the default options
13358		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
13359
13360		// register event handler
13361		this._core.$element.on(this._handlers);
13362	}
13363
13364	/**
13365	 * Default options.
13366	 * @public
13367	 */
13368	Lazy.Defaults = {
13369		lazyLoad: false
13370	}
13371
13372	/**
13373	 * Loads all resources of an item at the specified position.
13374	 * @param {Number} position - The absolute position of the item.
13375	 * @protected
13376	 */
13377	Lazy.prototype.load = function(position) {
13378		var $item = this._core.$stage.children().eq(position),
13379			$elements = $item && $item.find('.owl-lazy');
13380
13381		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
13382			return;
13383		}
13384
13385		$elements.each($.proxy(function(index, element) {
13386			var $element = $(element), image,
13387				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
13388
13389			this._core.trigger('load', { element: $element, url: url }, 'lazy');
13390
13391			if ($element.is('img')) {
13392				$element.one('load.owl.lazy', $.proxy(function() {
13393					$element.css('opacity', 1);
13394					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
13395				}, this)).attr('src', url);
13396			} else {
13397				image = new Image();
13398				image.onload = $.proxy(function() {
13399					$element.css({
13400						'background-image': 'url(' + url + ')',
13401						'opacity': '1'
13402					});
13403					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
13404				}, this);
13405				image.src = url;
13406			}
13407		}, this));
13408
13409		this._loaded.push($item.get(0));
13410	}
13411
13412	/**
13413	 * Destroys the plugin.
13414	 * @public
13415	 */
13416	Lazy.prototype.destroy = function() {
13417		var handler, property;
13418
13419		for (handler in this.handlers) {
13420			this._core.$element.off(handler, this.handlers[handler]);
13421		}
13422		for (property in Object.getOwnPropertyNames(this)) {
13423			typeof this[property] != 'function' && (this[property] = null);
13424		}
13425	};
13426
13427	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
13428
13429})(window.Zepto || window.jQuery, window, document);
13430
13431/**
13432 * AutoHeight Plugin
13433 * @version 2.0.0-beta.3
13434 * @author Bartosz Wojciechowski
13435 * @license The MIT License (MIT)
13436 */
13437;(function($, window, document, undefined) {
13438
13439	/**
13440	 * Creates the auto height plugin.
13441	 * @class The Auto Height Plugin
13442	 * @param {Owl} carousel - The Owl Carousel
13443	 */
13444	var AutoHeight = function(carousel) {
13445		/**
13446		 * Reference to the core.
13447		 * @protected
13448		 * @type {Owl}
13449		 */
13450		this._core = carousel;
13451
13452		/**
13453		 * All event handlers.
13454		 * @protected
13455		 * @type {Object}
13456		 */
13457		this._handlers = {
13458			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
13459				if (e.namespace && this._core.settings.autoHeight) {
13460					this.update();
13461				}
13462			}, this),
13463			'changed.owl.carousel': $.proxy(function(e) {
13464				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
13465					this.update();
13466				}
13467			}, this),
13468			'loaded.owl.lazy': $.proxy(function(e) {
13469				if (e.namespace && this._core.settings.autoHeight
13470					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
13471					this.update();
13472				}
13473			}, this)
13474		};
13475
13476		// set default options
13477		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
13478
13479		// register event handlers
13480		this._core.$element.on(this._handlers);
13481	};
13482
13483	/**
13484	 * Default options.
13485	 * @public
13486	 */
13487	AutoHeight.Defaults = {
13488		autoHeight: false,
13489		autoHeightClass: 'owl-height'
13490	};
13491
13492	/**
13493	 * Updates the view.
13494	 */
13495	AutoHeight.prototype.update = function() {
13496		var start = this._core._current,
13497			end = start + this._core.settings.items,
13498			visible = this._core.$stage.children().toArray().slice(start, end);
13499			heights = [],
13500			maxheight = 0;
13501
13502		$.each(visible, function(index, item) {
13503			heights.push($(item).height());
13504		});
13505
13506		maxheight = Math.max.apply(null, heights);
13507
13508		this._core.$stage.parent()
13509			.height(maxheight)
13510			.addClass(this._core.settings.autoHeightClass);
13511	};
13512
13513	AutoHeight.prototype.destroy = function() {
13514		var handler, property;
13515
13516		for (handler in this._handlers) {
13517			this._core.$element.off(handler, this._handlers[handler]);
13518		}
13519		for (property in Object.getOwnPropertyNames(this)) {
13520			typeof this[property] != 'function' && (this[property] = null);
13521		}
13522	};
13523
13524	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
13525
13526})(window.Zepto || window.jQuery, window, document);
13527
13528/**
13529 * Video Plugin
13530 * @version 2.0.0-beta.3
13531 * @author Bartosz Wojciechowski
13532 * @license The MIT License (MIT)
13533 */
13534;(function($, window, document, undefined) {
13535
13536	/**
13537	 * Creates the video plugin.
13538	 * @class The Video Plugin
13539	 * @param {Owl} carousel - The Owl Carousel
13540	 */
13541	var Video = function(carousel) {
13542		/**
13543		 * Reference to the core.
13544		 * @protected
13545		 * @type {Owl}
13546		 */
13547		this._core = carousel;
13548
13549		/**
13550		 * Cache all video URLs.
13551		 * @protected
13552		 * @type {Object}
13553		 */
13554		this._videos = {};
13555
13556		/**
13557		 * Current playing item.
13558		 * @protected
13559		 * @type {jQuery}
13560		 */
13561		this._playing = null;
13562
13563		/**
13564		 * All event handlers.
13565		 * @todo The cloned content removale is too late
13566		 * @protected
13567		 * @type {Object}
13568		 */
13569		this._handlers = {
13570			'initialized.owl.carousel': $.proxy(function(e) {
13571				if (e.namespace) {
13572					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
13573				}
13574			}, this),
13575			'resize.owl.carousel': $.proxy(function(e) {
13576				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
13577					e.preventDefault();
13578				}
13579			}, this),
13580			'refreshed.owl.carousel': $.proxy(function(e) {
13581				if (e.namespace && this._core.is('resizing')) {
13582					this._core.$stage.find('.cloned .owl-video-frame').remove();
13583				}
13584			}, this),
13585			'changed.owl.carousel': $.proxy(function(e) {
13586				if (e.namespace && e.property.name === 'position' && this._playing) {
13587					this.stop();
13588				}
13589			}, this),
13590			'prepared.owl.carousel': $.proxy(function(e) {
13591				if (!e.namespace) {
13592					return;
13593				}
13594
13595				var $element = $(e.content).find('.owl-video');
13596
13597				if ($element.length) {
13598					$element.css('display', 'none');
13599					this.fetch($element, $(e.content));
13600				}
13601			}, this)
13602		};
13603
13604		// set default options
13605		this._core.options = $.extend({}, Video.Defaults, this._core.options);
13606
13607		// register event handlers
13608		this._core.$element.on(this._handlers);
13609
13610		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
13611			this.play(e);
13612		}, this));
13613	};
13614
13615	/**
13616	 * Default options.
13617	 * @public
13618	 */
13619	Video.Defaults = {
13620		video: false,
13621		videoHeight: false,
13622		videoWidth: false
13623	};
13624
13625	/**
13626	 * Gets the video ID and the type (YouTube/Vimeo only).
13627	 * @protected
13628	 * @param {jQuery} target - The target containing the video data.
13629	 * @param {jQuery} item - The item containing the video.
13630	 */
13631	Video.prototype.fetch = function(target, item) {
13632		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
13633			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
13634			width = target.attr('data-width') || this._core.settings.videoWidth,
13635			height = target.attr('data-height') || this._core.settings.videoHeight,
13636			url = target.attr('href');
13637
13638		if (url) {
13639			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+)?/);
13640
13641			if (id[3].indexOf('youtu') > -1) {
13642				type = 'youtube';
13643			} else if (id[3].indexOf('vimeo') > -1) {
13644				type = 'vimeo';
13645			} else {
13646				throw new Error('Video URL not supported.');
13647			}
13648			id = id[6];
13649		} else {
13650			throw new Error('Missing video URL.');
13651		}
13652
13653		this._videos[url] = {
13654			type: type,
13655			id: id,
13656			width: width,
13657			height: height
13658		};
13659
13660		item.attr('data-video', url);
13661
13662		this.thumbnail(target, this._videos[url]);
13663	};
13664
13665	/**
13666	 * Creates video thumbnail.
13667	 * @protected
13668	 * @param {jQuery} target - The target containing the video data.
13669	 * @param {Object} info - The video info object.
13670	 * @see `fetch`
13671	 */
13672	Video.prototype.thumbnail = function(target, video) {
13673		var tnLink,
13674			icon,
13675			path,
13676			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
13677			customTn = target.find('img'),
13678			srcType = 'src',
13679			lazyClass = '',
13680			settings = this._core.settings,
13681			create = function(path) {
13682				icon = '<div class="owl-video-play-icon"></div>';
13683
13684				if (settings.lazyLoad) {
13685					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
13686				} else {
13687					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
13688				}
13689				target.after(tnLink);
13690				target.after(icon);
13691			};
13692
13693		// wrap video content into owl-video-wrapper div
13694		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
13695
13696		if (this._core.settings.lazyLoad) {
13697			srcType = 'data-src';
13698			lazyClass = 'owl-lazy';
13699		}
13700
13701		// custom thumbnail
13702		if (customTn.length) {
13703			create(customTn.attr(srcType));
13704			customTn.remove();
13705			return false;
13706		}
13707
13708		if (video.type === 'youtube') {
13709			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
13710			create(path);
13711		} else if (video.type === 'vimeo') {
13712			$.ajax({
13713				type: 'GET',
13714				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
13715				jsonp: 'callback',
13716				dataType: 'jsonp',
13717				success: function(data) {
13718					path = data[0].thumbnail_large;
13719					create(path);
13720				}
13721			});
13722		}
13723	};
13724
13725	/**
13726	 * Stops the current video.
13727	 * @public
13728	 */
13729	Video.prototype.stop = function() {
13730		this._core.trigger('stop', null, 'video');
13731		this._playing.find('.owl-video-frame').remove();
13732		this._playing.removeClass('owl-video-playing');
13733		this._playing = null;
13734		this._core.leave('playing');
13735		this._core.trigger('stopped', null, 'video');
13736	};
13737
13738	/**
13739	 * Starts the current video.
13740	 * @public
13741	 * @param {Event} event - The event arguments.
13742	 */
13743	Video.prototype.play = function(event) {
13744		var target = $(event.target),
13745			item = target.closest('.' + this._core.settings.itemClass),
13746			video = this._videos[item.attr('data-video')],
13747			width = video.width || '100%',
13748			height = video.height || this._core.$stage.height(),
13749			html;
13750
13751		if (this._playing) {
13752			return;
13753		}
13754
13755		this._core.enter('playing');
13756		this._core.trigger('play', null, 'video');
13757
13758		item = this._core.items(this._core.relative(item.index()));
13759
13760		this._core.reset(item.index());
13761
13762		if (video.type === 'youtube') {
13763			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
13764				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
13765		} else if (video.type === 'vimeo') {
13766			html = '<iframe src="//player.vimeo.com/video/' + video.id +
13767				'?autoplay=1" width="' + width + '" height="' + height +
13768				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
13769		}
13770
13771		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
13772
13773		this._playing = item.addClass('owl-video-playing');
13774	};
13775
13776	/**
13777	 * Checks whether an video is currently in full screen mode or not.
13778	 * @todo Bad style because looks like a readonly method but changes members.
13779	 * @protected
13780	 * @returns {Boolean}
13781	 */
13782	Video.prototype.isInFullScreen = function() {
13783		var element = document.fullscreenElement || document.mozFullScreenElement ||
13784				document.webkitFullscreenElement;
13785
13786		return element && $(element).parent().hasClass('owl-video-frame');
13787	};
13788
13789	/**
13790	 * Destroys the plugin.
13791	 */
13792	Video.prototype.destroy = function() {
13793		var handler, property;
13794
13795		this._core.$element.off('click.owl.video');
13796
13797		for (handler in this._handlers) {
13798			this._core.$element.off(handler, this._handlers[handler]);
13799		}
13800		for (property in Object.getOwnPropertyNames(this)) {
13801			typeof this[property] != 'function' && (this[property] = null);
13802		}
13803	};
13804
13805	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
13806
13807})(window.Zepto || window.jQuery, window, document);
13808
13809/**
13810 * Animate Plugin
13811 * @version 2.0.0-beta.3
13812 * @author Bartosz Wojciechowski
13813 * @license The MIT License (MIT)
13814 */
13815;(function($, window, document, undefined) {
13816
13817	/**
13818	 * Creates the animate plugin.
13819	 * @class The Navigation Plugin
13820	 * @param {Owl} scope - The Owl Carousel
13821	 */
13822	var Animate = function(scope) {
13823		this.core = scope;
13824		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
13825		this.swapping = true;
13826		this.previous = undefined;
13827		this.next = undefined;
13828
13829		this.handlers = {
13830			'change.owl.carousel': $.proxy(function(e) {
13831				if (e.namespace && e.property.name == 'position') {
13832					this.previous = this.core.current();
13833					this.next = e.property.value;
13834				}
13835			}, this),
13836			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
13837				if (e.namespace) {
13838					this.swapping = e.type == 'translated';
13839				}
13840			}, this),
13841			'translate.owl.carousel': $.proxy(function(e) {
13842				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
13843					this.swap();
13844				}
13845			}, this)
13846		};
13847
13848		this.core.$element.on(this.handlers);
13849	};
13850
13851	/**
13852	 * Default options.
13853	 * @public
13854	 */
13855	Animate.Defaults = {
13856		animateOut: false,
13857		animateIn: false
13858	};
13859
13860	/**
13861	 * Toggles the animation classes whenever an translations starts.
13862	 * @protected
13863	 * @returns {Boolean|undefined}
13864	 */
13865	Animate.prototype.swap = function() {
13866
13867		if (this.core.settings.items !== 1) {
13868			return;
13869		}
13870
13871		if (!$.support.animation || !$.support.transition) {
13872			return;
13873		}
13874
13875		this.core.speed(0);
13876
13877		var left,
13878			clear = $.proxy(this.clear, this),
13879			previous = this.core.$stage.children().eq(this.previous),
13880			next = this.core.$stage.children().eq(this.next),
13881			incoming = this.core.settings.animateIn,
13882			outgoing = this.core.settings.animateOut;
13883
13884		if (this.core.current() === this.previous) {
13885			return;
13886		}
13887
13888		if (outgoing) {
13889			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
13890			previous.css( { 'left': left + 'px' } )
13891				.addClass('animated owl-animated-out')
13892				.addClass(outgoing)
13893				.on($.support.animation.end, clear);
13894		}
13895
13896		if (incoming) {
13897			next.addClass('animated owl-animated-in')
13898				.addClass(incoming)
13899				.on($.support.animation.end, clear);
13900		}
13901	};
13902
13903	Animate.prototype.clear = function(e) {
13904		if ($(e.target).hasClass('animated')) {
13905			$(e.target).css( { 'left': '' } )
13906				.removeClass('animated owl-animated-out owl-animated-in')
13907				.removeClass(this.core.settings.animateIn)
13908				.removeClass(this.core.settings.animateOut);
13909			this.core.onTransitionEnd();
13910		}
13911	};
13912
13913	/**
13914	 * Destroys the plugin.
13915	 * @public
13916	 */
13917	Animate.prototype.destroy = function() {
13918		var handler, property;
13919
13920		for (handler in this.handlers) {
13921			this.core.$element.off(handler, this.handlers[handler]);
13922		}
13923		for (property in Object.getOwnPropertyNames(this)) {
13924			typeof this[property] != 'function' && (this[property] = null);
13925		}
13926	};
13927
13928	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
13929
13930})(window.Zepto || window.jQuery, window, document);
13931
13932/**
13933 * Autoplay Plugin
13934 * @version 2.0.0-beta.3
13935 * @author Bartosz Wojciechowski
13936 * @author Artus Kolanowski
13937 * @license The MIT License (MIT)
13938 */
13939;(function($, window, document, undefined) {
13940
13941	/**
13942	 * Creates the autoplay plugin.
13943	 * @class The Autoplay Plugin
13944	 * @param {Owl} scope - The Owl Carousel
13945	 */
13946	var Autoplay = function(carousel) {
13947		/**
13948		 * Reference to the core.
13949		 * @protected
13950		 * @type {Owl}
13951		 */
13952		this._core = carousel;
13953
13954		/**
13955		 * The autoplay interval.
13956		 * @type {Number}
13957		 */
13958		this._interval = null;
13959
13960		/**
13961		 * Indicates whenever the autoplay is paused.
13962		 * @type {Boolean}
13963		 */
13964		this._paused = false;
13965
13966		/**
13967		 * All event handlers.
13968		 * @protected
13969		 * @type {Object}
13970		 */
13971		this._handlers = {
13972			'changed.owl.carousel': $.proxy(function(e) {
13973				if (e.namespace && e.property.name === 'settings') {
13974					if (this._core.settings.autoplay) {
13975						this.play();
13976					} else {
13977						this.stop();
13978					}
13979				}
13980			}, this),
13981			'initialized.owl.carousel': $.proxy(function(e) {
13982				if (e.namespace && this._core.settings.autoplay) {
13983					this.play();
13984				}
13985			}, this),
13986			'play.owl.autoplay': $.proxy(function(e, t, s) {
13987				if (e.namespace) {
13988					this.play(t, s);
13989				}
13990			}, this),
13991			'stop.owl.autoplay': $.proxy(function(e) {
13992				if (e.namespace) {
13993					this.stop();
13994				}
13995			}, this),
13996			'mouseover.owl.autoplay': $.proxy(function() {
13997				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
13998					this.pause();
13999				}
14000			}, this),
14001			'mouseleave.owl.autoplay': $.proxy(function() {
14002				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
14003					this.play();
14004				}
14005			}, this)
14006		};
14007
14008		// register event handlers
14009		this._core.$element.on(this._handlers);
14010
14011		// set default options
14012		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
14013	};
14014
14015	/**
14016	 * Default options.
14017	 * @public
14018	 */
14019	Autoplay.Defaults = {
14020		autoplay: false,
14021		autoplayTimeout: 5000,
14022		autoplayHoverPause: false,
14023		autoplaySpeed: false
14024	};
14025
14026	/**
14027	 * Starts the autoplay.
14028	 * @public
14029	 * @param {Number} [timeout] - The interval before the next animation starts.
14030	 * @param {Number} [speed] - The animation speed for the animations.
14031	 */
14032	Autoplay.prototype.play = function(timeout, speed) {
14033		this._paused = false;
14034
14035		if (this._core.is('rotating')) {
14036			return;
14037		}
14038
14039		this._core.enter('rotating');
14040
14041		this._interval = window.setInterval($.proxy(function() {
14042			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
14043				return;
14044			}
14045			this._core.next(speed || this._core.settings.autoplaySpeed);
14046		}, this), timeout || this._core.settings.autoplayTimeout);
14047	};
14048
14049	/**
14050	 * Stops the autoplay.
14051	 * @public
14052	 */
14053	Autoplay.prototype.stop = function() {
14054		if (!this._core.is('rotating')) {
14055			return;
14056		}
14057
14058		window.clearInterval(this._interval);
14059		this._core.leave('rotating');
14060	};
14061
14062	/**
14063	 * Stops the autoplay.
14064	 * @public
14065	 */
14066	Autoplay.prototype.pause = function() {
14067		if (!this._core.is('rotating')) {
14068			return;
14069		}
14070
14071		this._paused = true;
14072	};
14073
14074	/**
14075	 * Destroys the plugin.
14076	 */
14077	Autoplay.prototype.destroy = function() {
14078		var handler, property;
14079
14080		this.stop();
14081
14082		for (handler in this._handlers) {
14083			this._core.$element.off(handler, this._handlers[handler]);
14084		}
14085		for (property in Object.getOwnPropertyNames(this)) {
14086			typeof this[property] != 'function' && (this[property] = null);
14087		}
14088	};
14089
14090	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
14091
14092})(window.Zepto || window.jQuery, window, document);
14093
14094/**
14095 * Navigation Plugin
14096 * @version 2.0.0-beta.3
14097 * @author Artus Kolanowski
14098 * @license The MIT License (MIT)
14099 */
14100;(function($, window, document, undefined) {
14101	'use strict';
14102
14103	/**
14104	 * Creates the navigation plugin.
14105	 * @class The Navigation Plugin
14106	 * @param {Owl} carousel - The Owl Carousel.
14107	 */
14108	var Navigation = function(carousel) {
14109		/**
14110		 * Reference to the core.
14111		 * @protected
14112		 * @type {Owl}
14113		 */
14114		this._core = carousel;
14115
14116		/**
14117		 * Indicates whether the plugin is initialized or not.
14118		 * @protected
14119		 * @type {Boolean}
14120		 */
14121		this._initialized = false;
14122
14123		/**
14124		 * The current paging indexes.
14125		 * @protected
14126		 * @type {Array}
14127		 */
14128		this._pages = [];
14129
14130		/**
14131		 * All DOM elements of the user interface.
14132		 * @protected
14133		 * @type {Object}
14134		 */
14135		this._controls = {};
14136
14137		/**
14138		 * Markup for an indicator.
14139		 * @protected
14140		 * @type {Array.<String>}
14141		 */
14142		this._templates = [];
14143
14144		/**
14145		 * The carousel element.
14146		 * @type {jQuery}
14147		 */
14148		this.$element = this._core.$element;
14149
14150		/**
14151		 * Overridden methods of the carousel.
14152		 * @protected
14153		 * @type {Object}
14154		 */
14155		this._overrides = {
14156			next: this._core.next,
14157			prev: this._core.prev,
14158			to: this._core.to
14159		};
14160
14161		/**
14162		 * All event handlers.
14163		 * @protected
14164		 * @type {Object}
14165		 */
14166		this._handlers = {
14167			'prepared.owl.carousel': $.proxy(function(e) {
14168				if (e.namespace && this._core.settings.dotsData) {
14169					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
14170						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
14171				}
14172			}, this),
14173			'added.owl.carousel': $.proxy(function(e) {
14174				if (e.namespace && this._core.settings.dotsData) {
14175					this._templates.splice(e.position, 0, this._templates.pop());
14176				}
14177			}, this),
14178			'remove.owl.carousel': $.proxy(function(e) {
14179				if (e.namespace && this._core.settings.dotsData) {
14180					this._templates.splice(e.position, 1);
14181				}
14182			}, this),
14183			'changed.owl.carousel': $.proxy(function(e) {
14184				if (e.namespace && e.property.name == 'position') {
14185					this.draw();
14186				}
14187			}, this),
14188			'initialized.owl.carousel': $.proxy(function(e) {
14189				if (e.namespace && !this._initialized) {
14190					this._core.trigger('initialize', null, 'navigation');
14191					this.initialize();
14192					this.update();
14193					this.draw();
14194					this._initialized = true;
14195					this._core.trigger('initialized', null, 'navigation');
14196				}
14197			}, this),
14198			'refreshed.owl.carousel': $.proxy(function(e) {
14199				if (e.namespace && this._initialized) {
14200					this._core.trigger('refresh', null, 'navigation');
14201					this.update();
14202					this.draw();
14203					this._core.trigger('refreshed', null, 'navigation');
14204				}
14205			}, this)
14206		};
14207
14208		// set default options
14209		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
14210
14211		// register event handlers
14212		this.$element.on(this._handlers);
14213	};
14214
14215	/**
14216	 * Default options.
14217	 * @public
14218	 * @todo Rename `slideBy` to `navBy`
14219	 */
14220	Navigation.Defaults = {
14221		nav: false,
14222		navText: [ 'prev', 'next' ],
14223		navSpeed: false,
14224		navElement: 'div',
14225		navContainer: false,
14226		navContainerClass: 'owl-nav',
14227		navClass: [ 'owl-prev', 'owl-next' ],
14228		slideBy: 1,
14229		dotClass: 'owl-dot',
14230		dotsClass: 'owl-dots',
14231		dots: true,
14232		dotsEach: false,
14233		dotsData: false,
14234		dotsSpeed: false,
14235		dotsContainer: false
14236	};
14237
14238	/**
14239	 * Initializes the layout of the plugin and extends the carousel.
14240	 * @protected
14241	 */
14242	Navigation.prototype.initialize = function() {
14243		var override,
14244			settings = this._core.settings;
14245
14246		// create DOM structure for relative navigation
14247		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
14248			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
14249
14250		this._controls.$previous = $('<' + settings.navElement + '>')
14251			.addClass(settings.navClass[0])
14252			.html(settings.navText[0])
14253			.prependTo(this._controls.$relative)
14254			.on('click', $.proxy(function(e) {
14255				this.prev(settings.navSpeed);
14256			}, this));
14257		this._controls.$next = $('<' + settings.navElement + '>')
14258			.addClass(settings.navClass[1])
14259			.html(settings.navText[1])
14260			.appendTo(this._controls.$relative)
14261			.on('click', $.proxy(function(e) {
14262				this.next(settings.navSpeed);
14263			}, this));
14264
14265		// create DOM structure for absolute navigation
14266		if (!settings.dotsData) {
14267			this._templates = [ $('<div>')
14268				.addClass(settings.dotClass)
14269				.append($('<span>'))
14270				.prop('outerHTML') ];
14271		}
14272
14273		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
14274			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
14275
14276		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
14277			var index = $(e.target).parent().is(this._controls.$absolute)
14278				? $(e.target).index() : $(e.target).parent().index();
14279
14280			e.preventDefault();
14281
14282			this.to(index, settings.dotsSpeed);
14283		}, this));
14284
14285		// override public methods of the carousel
14286		for (override in this._overrides) {
14287			this._core[override] = $.proxy(this[override], this);
14288		}
14289	};
14290
14291	/**
14292	 * Destroys the plugin.
14293	 * @protected
14294	 */
14295	Navigation.prototype.destroy = function() {
14296		var handler, control, property, override;
14297
14298		for (handler in this._handlers) {
14299			this.$element.off(handler, this._handlers[handler]);
14300		}
14301		for (control in this._controls) {
14302			this._controls[control].remove();
14303		}
14304		for (override in this.overides) {
14305			this._core[override] = this._overrides[override];
14306		}
14307		for (property in Object.getOwnPropertyNames(this)) {
14308			typeof this[property] != 'function' && (this[property] = null);
14309		}
14310	};
14311
14312	/**
14313	 * Updates the internal state.
14314	 * @protected
14315	 */
14316	Navigation.prototype.update = function() {
14317		var i, j, k,
14318			lower = this._core.clones().length / 2,
14319			upper = lower + this._core.items().length,
14320			maximum = this._core.maximum(true),
14321			settings = this._core.settings,
14322			size = settings.center || settings.autoWidth || settings.dotsData
14323				? 1 : settings.dotsEach || settings.items;
14324
14325		if (settings.slideBy !== 'page') {
14326			settings.slideBy = Math.min(settings.slideBy, settings.items);
14327		}
14328
14329		if (settings.dots || settings.slideBy == 'page') {
14330			this._pages = [];
14331
14332			for (i = lower, j = 0, k = 0; i < upper; i++) {
14333				if (j >= size || j === 0) {
14334					this._pages.push({
14335						start: Math.min(maximum, i - lower),
14336						end: i - lower + size - 1
14337					});
14338					if (Math.min(maximum, i - lower) === maximum) {
14339						break;
14340					}
14341					j = 0, ++k;
14342				}
14343				j += this._core.mergers(this._core.relative(i));
14344			}
14345		}
14346	};
14347
14348	/**
14349	 * Draws the user interface.
14350	 * @todo The option `dotsData` wont work.
14351	 * @protected
14352	 */
14353	Navigation.prototype.draw = function() {
14354		var difference,
14355			settings = this._core.settings,
14356			disabled = this._core.items().length <= settings.items,
14357			index = this._core.relative(this._core.current()),
14358			loop = settings.loop || settings.rewind;
14359
14360		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
14361
14362		if (settings.nav) {
14363			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
14364			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
14365		}
14366
14367		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
14368
14369		if (settings.dots) {
14370			difference = this._pages.length - this._controls.$absolute.children().length;
14371
14372			if (settings.dotsData && difference !== 0) {
14373				this._controls.$absolute.html(this._templates.join(''));
14374			} else if (difference > 0) {
14375				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
14376			} else if (difference < 0) {
14377				this._controls.$absolute.children().slice(difference).remove();
14378			}
14379
14380			this._controls.$absolute.find('.active').removeClass('active');
14381			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
14382		}
14383	};
14384
14385	/**
14386	 * Extends event data.
14387	 * @protected
14388	 * @param {Event} event - The event object which gets thrown.
14389	 */
14390	Navigation.prototype.onTrigger = function(event) {
14391		var settings = this._core.settings;
14392
14393		event.page = {
14394			index: $.inArray(this.current(), this._pages),
14395			count: this._pages.length,
14396			size: settings && (settings.center || settings.autoWidth || settings.dotsData
14397				? 1 : settings.dotsEach || settings.items)
14398		};
14399	};
14400
14401	/**
14402	 * Gets the current page position of the carousel.
14403	 * @protected
14404	 * @returns {Number}
14405	 */
14406	Navigation.prototype.current = function() {
14407		var current = this._core.relative(this._core.current());
14408		return $.grep(this._pages, $.proxy(function(page, index) {
14409			return page.start <= current && page.end >= current;
14410		}, this)).pop();
14411	};
14412
14413	/**
14414	 * Gets the current succesor/predecessor position.
14415	 * @protected
14416	 * @returns {Number}
14417	 */
14418	Navigation.prototype.getPosition = function(successor) {
14419		var position, length,
14420			settings = this._core.settings;
14421
14422		if (settings.slideBy == 'page') {
14423			position = $.inArray(this.current(), this._pages);
14424			length = this._pages.length;
14425			successor ? ++position : --position;
vendor: 5,678 bytes, lines 14426-14650
14426			position = this._pages[((position % length) + length) % length].start;
14427		} else {
14428			position = this._core.relative(this._core.current());
14429			length = this._core.items().length;
14430			successor ? position += settings.slideBy : position -= settings.slideBy;
14431		}
14432
14433		return position;
14434	};
14435
14436	/**
14437	 * Slides to the next item or page.
14438	 * @public
14439	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
14440	 */
14441	Navigation.prototype.next = function(speed) {
14442		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
14443	};
14444
14445	/**
14446	 * Slides to the previous item or page.
14447	 * @public
14448	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
14449	 */
14450	Navigation.prototype.prev = function(speed) {
14451		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
14452	};
14453
14454	/**
14455	 * Slides to the specified item or page.
14456	 * @public
14457	 * @param {Number} position - The position of the item or page.
14458	 * @param {Number} [speed] - The time in milliseconds for the transition.
14459	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
14460	 */
14461	Navigation.prototype.to = function(position, speed, standard) {
14462		var length;
14463
14464		if (!standard) {
14465			length = this._pages.length;
14466			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
14467		} else {
14468			$.proxy(this._overrides.to, this._core)(position, speed);
14469		}
14470	};
14471
14472	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
14473
14474})(window.Zepto || window.jQuery, window, document);
14475
14476/**
14477 * Hash Plugin
14478 * @version 2.0.0-beta.3
14479 * @author Artus Kolanowski
14480 * @license The MIT License (MIT)
14481 */
14482;(function($, window, document, undefined) {
14483	'use strict';
14484
14485	/**
14486	 * Creates the hash plugin.
14487	 * @class The Hash Plugin
14488	 * @param {Owl} carousel - The Owl Carousel
14489	 */
14490	var Hash = function(carousel) {
14491		/**
14492		 * Reference to the core.
14493		 * @protected
14494		 * @type {Owl}
14495		 */
14496		this._core = carousel;
14497
14498		/**
14499		 * Hash index for the items.
14500		 * @protected
14501		 * @type {Object}
14502		 */
14503		this._hashes = {};
14504
14505		/**
14506		 * The carousel element.
14507		 * @type {jQuery}
14508		 */
14509		this.$element = this._core.$element;
14510
14511		/**
14512		 * All event handlers.
14513		 * @protected
14514		 * @type {Object}
14515		 */
14516		this._handlers = {
14517			/*'initialized.owl.carousel': $.proxy(function(e) {
14518				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
14519					$(window).trigger('hashchange.owl.navigation');
14520				}
14521			}, this),*/
14522			'prepared.owl.carousel': $.proxy(function(e) {
14523				if (e.namespace) {
14524					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
14525
14526					if (!hash) {
14527						return;
14528					}
14529
14530					this._hashes[hash] = e.content;
14531				}
14532			}, this),
14533			'changed.owl.carousel': $.proxy(function(e) {
14534				if (e.namespace && e.property.name === 'position') {
14535					var current = this._core.items(this._core.relative(this._core.current())),
14536						hash = $.map(this._hashes, function(item, hash) {
14537							return item === current ? hash : null;
14538						}).join();
14539
14540					if (!hash || window.location.hash.slice(1) === hash) {
14541						return;
14542					}
14543
14544					window.location.hash = hash;
14545				}
14546			}, this)
14547		};
14548
14549		// set default options
14550		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
14551
14552		// register the event handlers
14553		this.$element.on(this._handlers);
14554
14555		// register event listener for hash navigation
14556		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
14557			var hash = window.location.hash.substring(1),
14558				items = this._core.$stage.children(),
14559				position = this._hashes[hash] && items.index(this._hashes[hash]);
14560
14561			if (position === undefined || position === this._core.current()) {
14562				return;
14563			}
14564
14565			this._core.to(this._core.relative(position), false, true);
14566		}, this));*/
14567	};
14568
14569	/**
14570	 * Default options.
14571	 * @public
14572	 */
14573	Hash.Defaults = {
14574		URLhashListener: false
14575	};
14576
14577	/**
14578	 * Destroys the plugin.
14579	 * @public
14580	 */
14581	Hash.prototype.destroy = function() {
14582		var handler, property;
14583
14584		$(window).off('hashchange.owl.navigation');
14585
14586		for (handler in this._handlers) {
14587			this._core.$element.off(handler, this._handlers[handler]);
14588		}
14589		for (property in Object.getOwnPropertyNames(this)) {
14590			typeof this[property] != 'function' && (this[property] = null);
14591		}
14592	};
14593
14594	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
14595
14596})(window.Zepto || window.jQuery, window, document);
14597
14598/**
14599 * Support Plugin
14600 *
14601 * @version 2.0.0-beta.3
14602 * @author Vivid Planet Software GmbH
14603 * @author Artus Kolanowski
14604 * @license The MIT License (MIT)
14605 */
14606;(function($, window, document, undefined) {
14607
14608	var style = $('<support>').get(0).style,
14609		prefixes = 'Webkit Moz O ms'.split(' '),
14610		events = {
14611			transition: {
14612				end: {
14613					WebkitTransition: 'webkitTransitionEnd',
14614					MozTransition: 'transitionend',
14615					OTransition: 'oTransitionEnd',
14616					transition: 'transitionend'
14617				}
14618			},
14619			animation: {
14620				end: {
14621					WebkitAnimation: 'webkitAnimationEnd',
14622					MozAnimation: 'animationend',
14623					OAnimation: 'oAnimationEnd',
14624					animation: 'animationend'
14625				}
14626			}
14627		},
14628		tests = {
14629			csstransforms: function() {
14630				return !!test('transform');
14631			},
14632			csstransforms3d: function() {
14633				return !!test('perspective');
14634			},
14635			csstransitions: function() {
14636				return !!test('transition');
14637			},
14638			cssanimations: function() {
14639				return !!test('animation');
14640			}
14641		};
14642
14643	function test(property, prefixed) {
14644		var result = false,
14645			upper = property.charAt(0).toUpperCase() + property.slice(1);
14646
14647		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
14648			if (style[property] !== undefined) {
14649				result = prefixed ? property : true;
14650				return false;
14651			}
14652		});
14653
14654		return result;
14655	}
14656
14657	function prefixed(property) {
14658		return test(property, true);
14659	}
14660
14661	if (tests.csstransitions()) {
14662		/* jshint -W053 */
14663		$.support.transition = new String(prefixed('transition'))
14664		$.support.transition.end = events.transition.end[ $.support.transition ];
14665	}
14666
14667	if (tests.cssanimations()) {
14668		/* jshint -W053 */
14669		$.support.animation = new String(prefixed('animation'))
14670		$.support.animation.end = events.animation.end[ $.support.animation ];
14671	}
14672
14673	if (tests.csstransforms()) {
14674		/* jshint -W053 */
14675		$.support.transform = new String(prefixed('transform'));
14676		$.support.transform3d = tests.csstransforms3d();
14677	}
14678
14679})(window.Zepto || window.jQuery, window, document);
14680
14681(function(window, document, undefined) {
14682
14683	/**
14684	 * Find the absolute position of an element
14685	 */
14686	var absPos = function(element) {
14687		var offsetLeft, offsetTop;
14688		offsetLeft = offsetTop = 0;
14689		if (element.offsetParent) {
14690			do {
14691				offsetLeft += element.offsetLeft;
14692				offsetTop += element.offsetTop;
14693			} while (element = element.offsetParent);
14694		}
14695		return [offsetLeft, offsetTop];
14696	};
14697
14698	/**
14699	 * @constructor Progress Circle class
14700	 * @param params.canvas Canvas on which the circles will be drawn.
14701	 * @param params.minRadius Inner radius of the innermost circle, in px.
14702	 * @param params.arcWidth Width of each circle(to be more accurate, ring).
14703	 * @param params.gapWidth Space between each circle.
14704	 * @param params.centerX X coordinate of the center of circles.
14705	 * @param params.centerY Y coordinate of the center of circles.
14706	 * @param params.infoLineBaseAngle Base angle of the info line.
14707	 * @param params.infoLineAngleInterval Angles between the info lines.
14708	 */
14709	var ProgressCircle = function(params) {
14710		this.canvas = params.canvas;
14711		this.minRadius = params.minRadius || 15;
14712		this.arcWidth = params.arcWidth || 5;
14713		this.gapWidth = params.gapWidth || 3;
14714		this.centerX = params.centerX || this.canvas.width / 2;
14715		this.centerY = params.centerY || this.canvas.height / 2;
14716		this.infoLineLength = params.infoLineLength || 60;
14717		this.horizLineLength = params.horizLineLength || 10;
14718		this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
14719		this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
14720
14721		this.context = this.canvas.getContext('2d');
14722
14723		this.width = this.canvas.width;
14724		this.height = this.canvas.height;
14725
14726		this.circles = [];
14727		this.runningCount = 0;
14728	};
14729
14730	ProgressCircle.prototype = {
14731		constructor: ProgressCircle,
14732
14733		/**
14734		 * @method Adds an progress monitor entry.
14735		 * @param params.fillColor Color to fill in the circle.
14736		 * @param params.outlineColor Color to outline the circle.
14737		 * @param params.progressListener Callback function to fetch the progress.
14738		 * @param params.infoListener Callback function to fetch the info.
14739		 * @returns this
14740		 */
14741		addEntry: function(params) {
14742			this.circles.push(new Circle({
14743				canvas: this.canvas,
14744				context: this.context,
14745				centerX: this.centerX,
14746				centerY: this.centerY,
14747				innerRadius: this.minRadius + this.circles.length *
14748					(this.gapWidth + this.arcWidth),
14749				arcWidth: this.arcWidth,
14750				infoLineLength: this.infoLineLength,
14751				horizLineLength: this.horizLineLength,
14752
14753				id: this.circles.length,
14754				fillColor: params.fillColor,
14755				outlineColor: params.outlineColor,
14756				progressListener: params.progressListener,
14757				infoListener: params.infoListener,
14758				infoLineAngle: this.infoLineBaseAngle +
14759					this.circles.length * this.infoLineAngleInterval,
14760			}));
14761
14762			return this;
14763		},
14764
14765		/**
14766		 * @method Starts the monitor and updates with the given interval.
14767		 * @param interval Interval between updates, in millisecond.
14768		 * @returns this
14769		 */
14770		start: function(interval) {
14771			var self = this;
14772			this.timer = setInterval(function() {
14773				self._update();
14774			}, interval || 33);
14775
14776			return this;
14777		},
14778
14779		/**
14780		 * @method Stop the animation.
14781		 */
14782		stop: function() {
14783			clearTimeout(this.timer);
14784		},
14785
14786		/**
14787		 * @private
14788		 * @method Call update on each circle and redraw them.
14789		 * @returns this
14790		 */
14791		_update: function() {
14792			this._clear();
14793			this.circles.forEach(function(circle, idx, array) {
14794				circle.update();
14795			});
14796
14797			return this;
14798		},
14799
14800		/**
14801		 * @private
14802		 * @method Clear the canvas.
14803		 * @returns this
14804		 */
14805		_clear: function() {
14806			this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
14807
14808			return this;
14809		},
14810
14811	};
14812
14813	/**
14814	 * @private
14815	 * @class Individual progress circle.
14816	 * @param params.canvas Canvas on which the circle will be drawn.
14817	 * @param params.context Context of the canvas.
14818	 * @param params.innerRadius Inner radius of the circle, in px.
14819	 * @param params.arcWidth Width of each arc(circle).
14820	 * @param params.gapWidth Distance between each arc.
14821	 * @param params.centerX X coordinate of the center of circles.
14822	 * @param params.centerY Y coordinate of the center of circles.
14823	 * @param params.fillColor Color to fill in the circle.
14824	 * @param params.outlineColor Color to outline the circle.
14825	 * @param params.progressListener Callback function to fetch the progress.
14826	 * @param params.infoListener Callback function to fetch the info.
14827	 * @param params.infoLineAngle Angle of info line.
14828	 */
14829	var Circle = function(params) {
14830		this.id = params.id;
14831		this.canvas = params.canvas;
14832		this.context = params.context;
14833		this.centerX = params.centerX;
14834		this.centerY = params.centerY;
14835		this.arcWidth = params.arcWidth;
14836		this.innerRadius = params.innerRadius || 0;
14837		this.fillColor = params.fillColor || '#fff';
14838		this.outlineColor = params.outlineColor || this.fillColor;
14839		this.progressListener = params.progressListener;
14840		this.infoLineLength = params.infoLineLength || 250;
14841		this.horizLineLength = params.horizLineLength || 50;
14842		this.infoListener = params.infoListener;
14843		this.infoLineAngle = params.infoLineAngle;
14844
14845		this.outerRadius = this.innerRadius + this.arcWidth;
14846
14847		// If the info listener is not registered, then don't calculate
14848		// the related coordinates
14849		if (!this.infoListener) return;
14850
14851		// calculate the info-line turning points
14852		var angle = this.infoLineAngle,
14853			arcDistance = (this.innerRadius + this.outerRadius) / 2,
14854
14855			sinA = Math.sin(angle),
14856			cosA = Math.cos(angle);
14857
14858		this.infoLineStartX = this.centerX + sinA * arcDistance;
14859		this.infoLineStartY = this.centerY - cosA * arcDistance;
14860
14861		this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
14862		this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
14863
14864		this.infoLineEndX = this.infoLineMidX +
14865			 (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
14866		this.infoLineEndY = this.infoLineMidY;
14867
14868		var infoText = document.createElement('div'),
14869			style = infoText.style;
14870
14871		style.color = this.fillColor;
14872		style.position = 'absolute';
14873		style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
14874		// style.top will be calculated in the `drawInfo` method. Since
14875		// user may want to change the size of the font, so the top offset
14876		// must be updated in each loop.
14877		infoText.className = 'ProgressCircleInfo'; // For css styling
14878		infoText.id = 'progress_circle_info_' + this.id;
14879		document.body.appendChild(infoText);
14880		this.infoText = infoText;
14881	};
14882
14883	Circle.prototype = {
14884		constructor: Circle,
14885
14886		update: function() {
14887			this.progress = this.progressListener();
14888			this._draw();
14889
14890			if (this.infoListener) {
14891				this.info = this.infoListener();
14892				this._drawInfo();
14893			}
14894		},
14895
14896		/**
14897		 * @private
14898		 * @method Draw the circle on the canvas.
14899		 * @returns this
14900		 */
14901		_draw: function() {
14902			var ctx = this.context,
14903
14904				ANGLE_OFFSET = -Math.PI / 2,
14905
14906				startAngle = 0 + ANGLE_OFFSET,
14907				endAngle= startAngle + this.progress * Math.PI * 2,
14908
14909				x = this.centerX,
14910				y = this.centerY,
14911
14912				innerRadius = this.innerRadius - this.arcWidth - 1,
14913				outerRadius = this.outerRadius - this.arcWidth - 1;
14914
14915			if ( innerRadius < 0 )
14916				return;
14917
14918			ctx.fillStyle = this.fillColor;
14919			ctx.strokeStyle = this.outlineColor;
14920
14921			ctx.beginPath();
14922			ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
14923			ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
14924			ctx.closePath();
14925			ctx.stroke();
14926			ctx.fill();
14927
14928			return this;
14929		},
14930
14931		/**
14932		 * @private
14933		 * @method Draw the info lines and info text.
14934		 * @returns this
14935		 */
14936		_drawInfo: function() {
14937
14938			var pointList, lineHeight;
14939
14940			pointList = [
14941				[this.infoLineStartX, this.infoLineStartY],
14942				[this.infoLineMidX, this.infoLineMidY],
14943				[this.infoLineEndX, this.infoLineEndY],
14944			];
14945			this._drawSegments(pointList, false);
14946
14947			this.infoText.innerHTML = this.info;
14948
14949			lineHeight = this.infoText.offsetHeight;
14950			this.infoText.style.top = this.infoLineEndY +
14951				absPos(this.canvas)[1] - lineHeight / 2 + 'px';
14952
14953			return this;
14954		},
14955
14956		/**
14957		 * @private
14958		 * @method Helper function to draw the segments
14959		 * @param pointList An array of points in the form of [x, y].
14960		 * @param close Whether to connect the first and last point.
14961		 */
14962		_drawSegments: function(pointList, close) {
14963			var ctx = this.context;
14964
14965			ctx.beginPath();
14966			ctx.moveTo(pointList[0][0], pointList[0][1]);
14967			for (var i = 1; i < pointList.length; ++i) {
14968				ctx.lineTo(pointList[i][0], pointList[i][1]);
14969			}
14970
14971			if (close) {
14972				ctx.closePath();
14973			}
14974			ctx.stroke();
14975		},
14976	};
14977
14978	window.ProgressCircle = ProgressCircle;
14979
14980})(window, document);
14981
14982
14983
14984
14985/* =========================================================
14986 * jquery.vc_chart.js v1.0
14987 * =========================================================
14988 * Copyright 2013 Wpbakery
14989 *
14990 * Jquery chart plugin for the Visual Composer.
14991 * ========================================================= */
14992(function($){
14993	/**
14994	 * Pie chart animated.
14995	 * @param element - DOM element
14996	 * @param options - settings object.
14997	 * @constructor
14998	 */
14999	var VcChart = function(element, options) {
15000		this.el = element;
15001		this.$el = $(this.el);
15002		var $this = this;
15003		$this.options = $.extend({
15004			color: 'wpb_button',
15005			units: '',
15006			width: '',
15007			label_selector: '.vc_pie_chart_value',
15008			back_selector: '.vc_pie_chart_back',
15009			responsive: true
15010		}, options);
15011		$this.init();
15012	};
15013	VcChart.prototype = {
15014		constructor: VcChart,
15015		_progress_v: 0,
15016		animated: false,
15017		colors: {
15018			'wpb_button': 'rgba(247, 247, 247, 1)',
15019			'btn-primary': 'rgba(0, 136, 204, 1)',
15020			'btn-info': 'rgba(88, 185, 218, 1)',
15021			'btn-success': 'rgba(106, 177, 101, 1)',
15022			'btn-warning': 'rgba(255, 153, 0, 1)',
15023			'btn-danger': 'rgba(255, 103, 91, 1)',
15024			'btn-inverse': 'rgba(85, 85, 85, 1)'
15025		},
15026		init: function() {
15027			this.setupColor();
15028			this.value = this.$el.data('pie-value')/100;
15029			this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
15030			this.$wrapper = $('.vc_pie_wrapper', this.$el);
15031			this.$label = $(this.options.label_selector, this.$el);
15032			this.$back = $(this.options.back_selector, this.$el);
15033			this.$canvas = this.$el.find('canvas');
15034			this.arcWidth = this.$el.data('pie-width') * 2;
15035			this.draw();
15036			this.setWayPoint();
15037			if(this.options.responsive === true) this.setResponsive();
15038			if (UNCODE.isMobile) this._progress_v = this.value;
15039		},
15040		setupColor: function() {
15041			// if(typeof this.colors[this.options.color] !== 'undefined') {
15042			//     this.color = this.colors[this.options.color];
15043			// } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
15044			//     this.color = this.options.color;
15045			// } else {
15046			//     this.color = 'rgba(247, 247, 247, 0.2)';
15047			// }
15048			if(typeof this.options.color !== 'undefined') {
15049				this.color = this.options.color;
15050			} else this.color = 'rgba(247, 247, 247, 0.2)';
15051
15052		},
15053		setResponsive: function() {
15054			var that = this;
15055			if (!UNCODE.isMobile) {
15056				$(window).resize(function(){
15057					if(that.animated === true) that.circle.stop();
15058					that.draw(true);
15059				});
15060			}
15061		},
15062		draw: function(redraw) {
15063			var w = this.$el.addClass('vc_ready').width() * 2,
15064				border_w = this.arcWidth,
15065				radius;
15066			if(!w) w = this.$el.parents(':visible').first().width()-2;
15067			//w = Math.round(w/100*80);
15068			//if (w < 250) w = 250;
15069			radius = w/2;
15070			this.$wrapper.css({"width" : (w / 2) + "px"});
15071			this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
15072			this.$back.css({"width" : (w / 2), "height" : (w / 2)});
15073			this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
15074			this.$el.addClass('vc_ready');
15075			this.circle = new ProgressCircle({
15076				canvas: this.$canvas.get(0),
15077				minRadius: radius,
15078				arcWidth: border_w
15079			});
15080			if(redraw === true && this.animated === true) {
15081				this._progress_v = this.value;
15082				this.circle.addEntry({
15083					fillColor: this.color,
15084					progressListener: $.proxy(this.setProgress, this)
15085				}).start();
15086			}
15087		},
15088		setProgress: function() {
15089			if (this._progress_v >= this.value) {
15090				this.circle.stop();
15091				this.animated = true;
15092				this.$label.html(this.label_value + this.options.units);
15093				return this._progress_v;
15094			}
15095			this._progress_v += 0.01;
15096			if (!isNaN(this.label_value)) {
15097				var label_value = this._progress_v/this.value*this.label_value;
15098				var val = Math.round(label_value) + this.options.units;
15099				this.$label.html(val);
15100			} else this.$label.html(this.label_value + this.options.units);
15101			return this._progress_v;
15102		},
15103		animate: function() {
15104			if(this.animated !== true) {
15105				this.circle.addEntry({
15106					fillColor: this.color,
15107					progressListener: $.proxy(this.setProgress, this)
15108				}).start(10);
15109			}
15110		},
15111		setWayPoint: function() {
15112			if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
15113				this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
15114			} else {
15115				this.animate();
15116			}
15117		}
15118	};
15119	/**
15120	 * jQuery plugin
15121	 * @param option - object with settings
15122	 * @return {*}
15123	 */
15124	$.fn.vcChat = function(option, value) {
15125		return this.each(function () {
15126			var $this = $(this),
15127				data = $this.data('vc_chart'),
15128				options = typeof option === 'object' ? option : {
15129					color: $this.data('pie-color'),
15130					units: $this.data('pie-units')
15131				};
15132			if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
15133			if (typeof option == 'string') data[option](value);
15134		});
15135	};
15136	/**
15137	 * Allows users to rewrite function inside theme.
15138	 */
15139	if ( typeof window['vc_pieChart'] !== 'function' ) {
15140		window.vc_pieChart = function() {
15141			$('.vc_pie_chart:visible:not(.vc_ready)').vcChat();
15142		}
15143	}
15144	$(document).ready(function(){
15145		!window.vc_iframe && vc_pieChart();
15146
15147		/**
15148		* Tab and collapse integration.
15149		*/
15150		$('.nav-tabs a').on('shown.bs.tab', function(e){
15151			var $cont = $(e.target).closest('.tab-container'),
15152				$active = $('.tab-pane.active', $cont);
15153			$('.vc_pie_chart:not(.vc_ready)', $active).vcChat();
15154		});
15155
15156		$('.panel-collapse').on('shown.bs.collapse', function (e) {
15157			$('.vc_pie_chart:not(.vc_ready)', e.target).vcChat();
15158		})
15159	});
15160
15161})(window.jQuery);
15162
15163/* Progress bar
15164 ---------------------------------------------------------- */
15165function uncode_progress_bar() {    
15166	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
15167		if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) {
15168			return;
15169		}
15170		if (!UNCODE.isMobile) {
15171			new Waypoint({
15172				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
15173				element: val,
15174				handler: function() {
15175					var element = jQuery(this.element);
15176					element.find('.vc_single_bar').each(function(index) {          
15177						var $this = jQuery(this),
15178							            bar = $this.find('.vc_bar'),
15179							            val = bar.data('percentage-value');          
15180						setTimeout(function() {            
15181							bar.css({
15182								"width": val + '%'
15183							});          
15184						}, index * 200);        
15185					});
15186				},
15187				offset: '80%'
15188			});
15189		} else {
15190			var element = jQuery(val);
15191			element.find('.vc_single_bar').each(function(index) {          
15192				var $this = jQuery(this),
15193					            bar = $this.find('.vc_bar'),
15194					            val = bar.data('percentage-value');          
15195				setTimeout(function() {            
15196					bar.css({
15197						"width": val + '%'
15198					});          
15199				}, index * 200);        
15200			});
15201		}
15202	});
15203};
15204uncode_progress_bar();
15205
15206/*!
15207 * jquery.counterup.js 1.0
15208 *
15209 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
15210 * Released under the GPL v2 License
15211 *
15212 * Date: Nov 26, 2013
15213 */
15214(function($) {
15215	"use strict";
15216	$.fn.counterUp = function(options) {
15217		// Defaults
15218		var settings = $.extend({
15219			'time': 400,
15220			'delay': 10
15221		}, options);
15222		return this.each(function() {
15223			// Store the object
15224			var $this = $(this);
15225			var $settings = settings;
15226			var counterUpper = function() {
15227				var nums = [];
15228				var divisions = $settings.time / $settings.delay;
15229				var numReal = $this.attr('data-val'),
15230				num = numReal;
15231				var isComma = /[0-9]+,[0-9]+/.test(num);
15232				num = num.replace(/,/g, '');
15233				var isInt = /^[0-9]+$/.test(num);
15234				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
15235				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
15236				// Generate list of incremental numbers to display
15237				for (var i = divisions; i >= 1; i--) {
15238					// Preserve as int if input was int
15239					var newNum = parseInt(num / divisions * i);
15240					// Preserve float if input was float
15241					if (isFloat) {
15242						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
15243					}
15244					// Preserve commas if input had commas
15245					if (isComma) {
15246						while (/(\d+)(\d{3})/.test(newNum.toString())) {
15247							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
15248						}
15249					}
15250					nums.unshift(newNum);
15251				}
15252				nums.push(numReal);
15253				$this.data('counterup-nums', nums);
15254				$this.text('0');
15255				// Updates the number until we're done
15256				var f = function() {
15257					if ($this.data('counterup-nums') != null) {
15258						$this.text($this.data('counterup-nums').shift());
15259						if ($this.data('counterup-nums').length) {
15260							setTimeout($this.data('counterup-func'), $settings.delay);
15261						} else {
15262							delete $this.data('counterup-nums');
15263							$this.data('counterup-nums', null);
15264							$this.data('counterup-func', null);
15265						}
15266					}
15267				};
15268				$this.data('counterup-func', f);
15269				// Start the count up
15270				setTimeout($this.data('counterup-func'), $settings.delay);
15271			};
15272			// Perform counts when the element gets into view
15273			new Waypoint({
15274				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
15275				element: this,
15276				handler: function() {
15277					counterUpper();
15278					if (!UNCODE.isUnmodalOpen) {
15279						this.destroy();
15280					}
15281				},
15282				offset: '100%'
15283			});
15284		});
15285	};
15286})(jQuery);
15287
15288/*!
15289 * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/)
15290 * Copyright (c) 2016 Edson Hilios
15291 *
15292 * Permission is hereby granted, free of charge, to any person obtaining a copy of
15293 * this software and associated documentation files (the "Software"), to deal in
15294 * the Software without restriction, including without limitation the rights to
15295 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
15296 * the Software, and to permit persons to whom the Software is furnished to do so,
15297 * subject to the following conditions:
15298 *
15299 * The above copyright notice and this permission notice shall be included in all
15300 * copies or substantial portions of the Software.
15301 *
15302 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15303 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15304 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15305 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
15306 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15307 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15308 */
15309(function(factory) {
15310	"use strict";
15311	if (typeof define === "function" && define.amd) {
15312		define([ "jquery" ], factory);
15313	} else {
15314		factory(jQuery);
15315	}
15316})(function($) {
15317	"use strict";
15318	var instances = [], matchers = [], defaultOptions = {
15319		precision: 100,
15320		elapse: false,
15321		defer: false
15322	};
15323	matchers.push(/^[0-9]*$/.source);
15324	matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
15325	matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
15326	matchers = new RegExp(matchers.join("|"));
15327	function parseDateString(dateString) {
15328		if (dateString instanceof Date) {
15329			return dateString;
15330		}
15331		if (String(dateString).match(matchers)) {
15332			if (String(dateString).match(/^[0-9]*$/)) {
15333				dateString = Number(dateString);
15334			}
15335			if (String(dateString).match(/\-/)) {
15336				dateString = String(dateString).replace(/\-/g, "/");
15337			}
15338			return new Date(dateString);
15339		} else {
15340			throw new Error("Couldn't cast `" + dateString + "` to a date object.");
15341		}
15342	}
15343	var DIRECTIVE_KEY_MAP = {
15344		Y: "years",
15345		m: "months",
15346		n: "daysToMonth",
15347		d: "daysToWeek",
15348		w: "weeks",
15349		W: "weeksToMonth",
15350		H: "hours",
15351		M: "minutes",
15352		S: "seconds",
15353		D: "totalDays",
15354		I: "totalHours",
15355		N: "totalMinutes",
15356		T: "totalSeconds"
15357	};
15358	function escapedRegExp(str) {
15359		var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
15360		return new RegExp(sanitize);
15361	}
15362	function strftime(offsetObject) {
15363		return function(format) {
15364			var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi);
15365			if (directives) {
15366				for (var i = 0, len = directives.length; i < len; ++i) {
15367					var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null;
15368					directive = directive[2];
15369					if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
15370						value = DIRECTIVE_KEY_MAP[directive];
15371						value = Number(offsetObject[value]);
15372					}
15373					if (value !== null) {
15374						if (modifier === "!") {
15375							value = pluralize(plural, value);
15376						}
15377						if (modifier === "") {
15378							if (value < 10) {
15379			
vendor: 4,091 bytes, lines 15379-15516
15379					value = "0" + value.toString();
15380							}
15381						}
15382						format = format.replace(regexp, value.toString());
15383					}
15384				}
15385			}
15386			format = format.replace(/%%/, "%");
15387			return format;
15388		};
15389	}
15390	function pluralize(format, count) {
15391		var plural = "s", singular = "";
15392		if (format) {
15393			format = format.replace(/(:|;|\s)/gi, "").split(/\,/);
15394			if (format.length === 1) {
15395				plural = format[0];
15396			} else {
15397				singular = format[0];
15398				plural = format[1];
15399			}
15400		}
15401		if (Math.abs(count) > 1) {
15402			return plural;
15403		} else {
15404			return singular;
15405		}
15406	}
15407	var Countdown = function(el, finalDate, options) {
15408		this.el = el;
15409		this.$el = $(el);
15410		this.interval = null;
15411		this.offset = {};
15412		this.options = $.extend({}, defaultOptions);
15413		this.instanceNumber = instances.length;
15414		instances.push(this);
15415		this.$el.data("countdown-instance", this.instanceNumber);
15416		if (options) {
15417			if (typeof options === "function") {
15418				this.$el.on("update.countdown", options);
15419				this.$el.on("stoped.countdown", options);
15420				this.$el.on("finish.countdown", options);
15421			} else {
15422				this.options = $.extend({}, defaultOptions, options);
15423			}
15424		}
15425		this.setFinalDate(finalDate);
15426		if (this.options.defer === false) {
15427			this.start();
15428		}
15429	};
15430	$.extend(Countdown.prototype, {
15431		start: function() {
15432			if (this.interval !== null) {
15433				clearInterval(this.interval);
15434			}
15435			var self = this;
15436			this.update();
15437			this.interval = setInterval(function() {
15438				self.update.call(self);
15439			}, this.options.precision);
15440		},
15441		stop: function() {
15442			clearInterval(this.interval);
15443			this.interval = null;
15444			this.dispatchEvent("stoped");
15445		},
15446		toggle: function() {
15447			if (this.interval) {
15448				this.stop();
15449			} else {
15450				this.start();
15451			}
15452		},
15453		pause: function() {
15454			this.stop();
15455		},
15456		resume: function() {
15457			this.start();
15458		},
15459		remove: function() {
15460			this.stop.call(this);
15461			instances[this.instanceNumber] = null;
15462			delete this.$el.data().countdownInstance;
15463		},
15464		setFinalDate: function(value) {
15465			this.finalDate = parseDateString(value);
15466		},
15467		update: function() {
15468			if (this.$el.closest("html").length === 0) {
15469				this.remove();
15470				return;
15471			}
15472			var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft;
15473			newTotalSecsLeft = this.finalDate.getTime() - now.getTime();
15474			newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3);
15475			newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft);
15476			if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) {
15477				return;
15478			} else {
15479				this.totalSecsLeft = newTotalSecsLeft;
15480			}
15481			this.elapsed = now >= this.finalDate;
15482			this.offset = {
15483				seconds: this.totalSecsLeft % 60,
15484				minutes: Math.floor(this.totalSecsLeft / 60) % 60,
15485				hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24,
15486				days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
15487				daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
15488				daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368),
15489				weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
15490				weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4,
15491				months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368),
15492				years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()),
15493				totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24),
15494				totalHours: Math.floor(this.totalSecsLeft / 60 / 60),
15495				totalMinutes: Math.floor(this.totalSecsLeft / 60),
15496				totalSeconds: this.totalSecsLeft
15497			};
15498			if (!this.options.elapse && this.totalSecsLeft === 0) {
15499				this.stop();
15500				this.dispatchEvent("finish");
15501			} else {
15502				this.dispatchEvent("update");
15503			}
15504		},
15505		dispatchEvent: function(eventName) {
15506			var event = $.Event(eventName + ".countdown");
15507			event.finalDate = this.finalDate;
15508			event.elapsed = this.elapsed;
15509			event.offset = $.extend({}, this.offset);
15510			event.strftime = strftime(this.offset);
15511			this.$el.trigger(event);
15512		}
15513	});
15514	$.fn.countdown = function() {
15515		var argumentsArray = Array.prototype.slice.call(arguments, 0);
15516		return this.each(function() {
15517			var instanceNumber = $(this).data("countdown-instance");
15518			if (instanceNumber !== undefined) {
15519				var instance = instances[instanceNumber], method = argumentsArray[0];
15520				if (Countdown.prototype.hasOwnProperty(method)) {
15521					instance[method].apply(instance, argumentsArray.slice(1));
15522				} else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
15523					instance.setFinalDate.call(instance, method);
15524					instance.start();
15525				} else {
15526					$.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method));
15527				}
15528			} else {
15529				new Countdown(this, argumentsArray[0], argumentsArray[1]);
15530			}
15531		});
15532	};
15533});
15534
15535/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05
15536* https://github.com/alexanderdickson/waitForImages
15537* Copyright (c) 2015 Alex Dickson; Licensed MIT */
15538;(function (factory) {
15539    if (typeof define === 'function' && define.amd) {
15540        // AMD. Register as an anonymous module.
15541        define(['jquery'], factory);
15542    } else if (typeof exports === 'object') {
15543        // CommonJS / nodejs module
15544        module.exports = factory(require('jquery'));
15545    } else {
15546        // Browser globals
15547        factory(jQuery);
15548    }
15549}(function ($) {
15550    // Namespace all events.
15551    var eventNamespace = 'waitForImages';
15552
15553    // CSS properties which contain references to images.
15554    $.waitForImages = {
15555        hasImageProperties: [
15556            'backgroundImage',
15557            'listStyleImage',
15558            'borderImage',
15559            'borderCornerImage',
15560            'cursor'
15561        ],
15562        hasImageAttributes: ['srcset']
15563    };
15564
15565    // Custom selector to find `img` elements that have a valid `src`
15566    // attribute and have not already loaded.
15567    $.expr[':'].uncached = function (obj) {
15568        // Ensure we are dealing with an `img` element with a valid
15569        // `src` attribute.
15570        if (!$(obj).is('img[src][src!=""]')) {
15571            return false;
15572        }
15573
15574        return !obj.complete;
15575    };
15576
15577    $.fn.waitForImages = function () {
15578
15579        var allImgsLength = 0;
15580        var allImgsLoaded = 0;
15581        var deferred = $.Deferred();
15582
15583        var finishedCallback;
15584        var eachCallback;
15585        var waitForAll;
15586
15587        // Handle options object (if passed).
15588        if ($.isPlainObject(arguments[0])) {
15589
15590            waitForAll = arguments[0].waitForAll;
15591            eachCallback = arguments[0].each;
15592            finishedCallback = arguments[0].finished;
15593
15594        } else {
15595
15596            // Handle if using deferred object and only one param was passed in.
15597            if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
15598                waitForAll = arguments[0];
15599            } else {
15600                finishedCallback = arguments[0];
15601                eachCallback = arguments[1];
15602                waitForAll = arguments[2];
15603            }
15604
15605        }
15606
15607        // Handle missing callbacks.
15608        finishedCallback = finishedCallback || $.noop;
15609        eachCallback = eachCallback || $.noop;
15610
15611        // Convert waitForAll to Boolean
15612        waitForAll = !! waitForAll;
15613
15614        // Ensure callbacks are functions.
15615        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
15616            throw new TypeError('An invalid callback was supplied.');
15617        }
15618
15619        this.each(function () {
15620            // Build a list of all imgs, dependent on what images will
15621            // be considered.
15622            var obj = $(this);
15623            var allImgs = [];
15624            // CSS properties which may contain an image.
15625            var hasImgProperties = $.waitForImages.hasImageProperties || [];
15626            // Element attributes which may contain an image.
15627            var hasImageAttributes = $.waitForImages.hasImageAttributes || [];
15628            // To match `url()` references.
15629            // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
15630            var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
15631
15632            if (waitForAll) {
15633
15634                // Get all elements (including the original), as any one of
15635                // them could have a background image.
15636                obj.find('*').addBack().each(function () {
15637                    var element = $(this);
15638
15639                    // If an `img` element, add it. But keep iterating in
15640                    // case it has a background image too.
15641                    if (element.is('img:uncached')) {
15642                        allImgs.push({
15643                            src: element.attr('src'),
15644                            element: element[0]
15645                        });
15646                    }
15647
15648                    $.each(hasImgProperties, function (i, property) {
15649                        var propertyValue = element.css(property);
15650                        var match;
15651
15652                        // If it doesn't contain this property, skip.
15653                        if (!propertyValue) {
15654                            return true;
15655                        }
15656
15657                        // Get all url() of this element.
15658                        while (match = matchUrl.exec(propertyValue)) {
15659                            allImgs.push({
15660                                src: match[2],
15661                                element: element[0]
15662                            });
15663                        }
15664                    });
15665
15666                    $.each(hasImageAttributes, function (i, attribute) {
15667                        var attributeValue = element.attr(attribute);
15668                        var attributeValues;
15669
15670                        // If it doesn't contain this property, skip.
15671                        if (!attributeValue) {
15672                            return true;
15673                        }
15674
15675                        // Check for multiple comma separated images
15676                        attributeValues = attributeValue.split(',');
15677
15678                        $.each(attributeValues, function(i, value) {
15679                            // Trim value and get string before first
15680                            // whitespace (for use with srcset).
15681                            value = $.trim(value).split(' ')[0];
15682                            allImgs.push({
15683                                src: value,
15684                                element: element[0]
15685                            });
15686                        });
15687                    });
15688                });
15689            } else {
15690                // For images only, the task is simpler.
15691                obj.find('img:uncached')
15692                    .each(function () {
15693                    allImgs.push({
15694                        src: this.src,
15695                        element: this
15696                    });
15697                });
15698            }
15699
15700            allImgsLength = allImgs.length;
15701            allImgsLoaded = 0;
15702
15703            // If no images found, don't bother.
15704            if (allImgsLength === 0) {
15705                finishedCallback.call(obj[0]);
15706                deferred.resolveWith(obj[0]);
15707            }
15708
15709            $.each(allImgs, function (i, img) {
15710
15711                var image = new Image();
15712                var events =
15713                  'load.' + eventNamespace + ' error.' + eventNamespace;
15714
15715                // Handle the image loading and error with the same callback.
15716                $(image).one(events, function me (event) {
15717                    // If an error occurred with loading the image, set the
15718                    // third argument accordingly.
15719                    var eachArguments = [
15720                        allImgsLoaded,
15721                        allImgsLength,
15722                        event.type == 'load'
15723                    ];
15724                    allImgsLoaded++;
15725
15726                    eachCallback.apply(img.element, eachArguments);
15727                    deferred.notifyWith(img.element, eachArguments);
15728
15729                    // Unbind the event listeners. I use this in addition to
15730                    // `one` as one of those events won't be called (either
15731                    // 'load' or 'error' will be called).
15732                    $(this).off(events, me);
15733
15734                    if (allImgsLoaded == allImgsLength) {
15735                        finishedCallback.call(obj[0]);
15736                        deferred.resolveWith(obj[0]);
15737                        return false;
15738                    }
15739
15740                });
15741
15742                image.src = img.src;
15743            });
15744        });
15745
15746        return deferred.promise();
15747
15748    };
15749}));
15750
15751/**
15752 * @preserve  textfill
15753 * @name      jquery.textfill.js
15754 * @author    Russ Painter
15755 * @author    Yu-Jie Lin
15756 * @author    Alexandre Dantas
15757 * @version   0.6.0
15758 * @date      2014-08-19
15759 * @copyright (c) 2014 Alexandre Dantas
15760 * @copyright (c) 2012-2013 Yu-Jie Lin
15761 * @copyright (c) 2009 Russ Painter
15762 * @license   MIT License
15763 * @homepage  https://github.com/jquery-textfill/jquery-textfill
15764 * @example   http://jquery-textfill.github.io/jquery-textfill/index.html
15765 */
15766; (function($) {
15767
15768	/**
15769	 * Resizes an inner element's font so that the
15770	 * inner element completely fills the outer element.
15771	 *
15772	 * @param {Object} options User options that take
15773	 *                         higher precedence when
15774	 *                         merging with the default ones.
15775	 *
15776	 * @return All outer elements processed
15777	 */
15778	$.fn.textfill = function(options) {
15779
15780		// ______  _______ _______ _______ _     _        _______ _______
15781		// |     \ |______ |______ |_____| |     | |         |    |______
15782		// |_____/ |______ |       |     | |_____| |_____    |    ______|
15783        //
15784		// Merging user options with the default values
15785
15786		var defaults = {
15787			debug            : false,
15788			maxFontPixels    : 40,
15789			minFontPixels    : 4,
15790			innerTag         : 'span',
15791			widthOnly        : false,
15792			success          : null, // callback when a resizing is done
15793			callback         : null, // callback when a resizing is done (deprecated, use success)
15794			fail             : null, // callback when a resizing is failed
15795			complete         : null, // callback when all is done
15796			explicitWidth    : null,
15797			explicitHeight   : null,
15798			changeLineHeight : false
15799		};
15800
15801		var Opts = $.extend(defaults, options);
15802
15803		// _______ _     _ __   _ _______ _______ _____  _____  __   _ _______
15804		// |______ |     | | \  | |          |      |   |     | | \  | |______
15805		// |       |_____| |  \_| |_____     |    __|__ |_____| |  \_| ______|
15806		//
15807		// Predefining the awesomeness
15808
15809		// Output arguments to the Debug console
15810		// if "Debug Mode" is enabled
15811		function _debug() {
15812			if (!Opts.debug
15813				||  typeof console       == 'undefined'
15814				||  typeof console.debug == 'undefined') {
15815				return;
15816			}
15817			console.debug.apply(console, arguments);
15818		}
15819
15820		// Output arguments to the Warning console
15821		function _warn() {
15822			if (typeof console      == 'undefined' ||
15823				typeof console.warn == 'undefined') {
15824				return;
15825			}
15826			console.warn.apply(console, arguments);
15827		}
15828
15829		// Outputs all information on the current sizing
15830		// of the font.
15831		function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
15832
15833			function _m(v1, v2) {
15834
15835				var marker = ' / ';
15836
15837				if (v1 > v2)
15838					marker = ' > ';
15839
15840				else if (v1 == v2)
15841					marker = ' = ';
15842
15843				return marker;
15844			}
15845
15846			_debug(
15847				'[TextFill] '  + prefix + ' { ' +
15848				'font-size: ' + ourText.css('font-size') + ',' +
15849				'Height: '    + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' +
15850				'Width: '     + ourText.width()  + _m(ourText.width() , maxWidth)  + maxWidth + ',' +
15851				'minFontPixels: ' + minFontPixels + 'px, ' +
15852				'maxFontPixels: ' + maxFontPixels + 'px }'
15853			);
15854		}
15855
15856		/**
15857		 * Calculates which size the font can get resized,
15858		 * according to constrains.
15859		 *
15860		 * @param {String} prefix Gets shown on the console before
15861		 *                        all the arguments, if debug mode is on.
15862		 * @param {Object} ourText The DOM element to resize,
15863		 *                         that contains the text.
15864		 * @param {function} func Function called on `ourText` that's
15865		 *                        used to compare with `max`.
15866		 * @param {number} max Maximum value, that gets compared with
15867		 *                     `func` called on `ourText`.
15868		 * @param {number} minFontPixels Minimum value the font can
15869		 *                               get resized to (in pixels).
15870		 * @param {number} maxFontPixels Maximum value the font can
15871		 *                               get resized to (in pixels).
15872		 *
15873		 * @return Size (in pixels) that the font can be resized.
15874		 */
15875		function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
15876
15877			_debug_sizing(
15878				prefix, ourText,
15879				maxHeight, maxWidth,
15880				minFontPixels, maxFontPixels
15881			);
15882
15883			// The kernel of the whole plugin, take most attention
15884			// on this part.
15885			//
15886			// This is a loop that keeps increasing the `font-size`
15887			// until it fits the parent element.
15888			//
15889			// - Start from the minimal allowed value (`minFontPixels`)
15890			// - Guesses an average font size (in pixels) for the font,
15891			// - Resizes the text and sees if its size is within the
15892			//   boundaries (`minFontPixels` and `maxFontPixels`).
15893			//   - If so, keep guessing until we break.
15894			//   - If not, return the last calculated size.
15895			//
15896			// I understand this is not optimized and we should
15897			// consider implementing something akin to
15898			// Daniel Hoffmann's answer here:
15899			//
15900			//     http://stackoverflow.com/a/17433451/1094964
15901			//
15902
15903			while (minFontPixels < (maxFontPixels - 1)) {
15904
15905				var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2);
15906				ourText.css('font-size', fontSize);
15907
15908				if (func.call(ourText) <= max) {
15909					minFontPixels = fontSize;
15910
15911					if (func.call(ourText) == max)
15912						break;
15913				}
15914				else
15915					maxFontPixels = fontSize;
15916
15917				_debug_sizing(
15918					prefix, ourText,
15919					maxHeight, maxWidth,
15920					minFontPixels, maxFontPixels
15921				);
15922			}
15923
15924			ourText.css('font-size', maxFontPixels);
15925
15926			if (func.call(ourText) <= max) {
15927				minFontPixels = maxFontPixels;
15928
15929				_debug_sizing(
15930					prefix + '* ', ourText,
15931					maxHeight, maxWidth,
15932					minFontPixels, maxFontPixels
15933				);
15934			}
15935			return minFontPixels;
15936		}
15937
15938		// _______ _______ _______  ______ _______
15939		// |______    |    |_____| |_____/    |
15940		// ______|    |    |     | |    \_    |
15941        //
15942		// Let's get it started (yeah)!
15943
15944		_debug('[TextFill] Start Debug');
15945
15946		this.each(function() {
15947
15948			// Contains the child element we will resize.
15949			// $(this) means the parent container
15950			var ourText = $(Opts.innerTag + ':visible:first', this);
15951
15952			// Will resize to this dimensions.
15953			// Use explicit dimensions when specified
15954			var maxHeight = Opts.explicitHeight || $(this).height();
15955			var maxWidth  = Opts.explicitWidth  || $(this).width();
15956
15957			var oldFontSize = ourText.css('font-size');
15958
15959			var lineHeight  = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize);
15960
15961			_debug('[TextFill] Inner text: ' + ourText.text());
15962			_debug('[TextFill] All options: ', Opts);
15963			_debug('[TextFill] Maximum sizes: { ' +
15964				   'Height: ' + maxHeight + 'px, ' +
15965				   'Width: '  + maxWidth  + 'px' + ' }'
15966				  );
15967
15968			var minFontPixels = Opts.minFontPixels;
15969
15970			// Remember, if this `maxFontPixels` is negative,
15971			// the text will resize to as long as the container
15972			// can accomodate
15973			var maxFontPixels = (Opts.maxFontPixels <= 0 ?
15974								 maxHeight :
15975								 Opts.maxFontPixels);
15976
15977
15978			// Let's start it all!
15979
15980			// 1. Calculate which `font-size` would
15981			//    be best for the Height
15982			var fontSizeHeight = undefined;
15983
15984			if (! Opts.widthOnly)
15985				fontSizeHeight = _sizing(
15986					'Height', ourText,
15987					$.fn.height, maxHeight,
15988					maxHeight, maxWidth,
15989					minFontPixels, maxFontPixels
15990				);
15991
15992			// 2. Calculate which `font-size` would
15993			//    be best for the Width
15994			var fontSizeWidth = undefined;
15995
15996			fontSizeWidth = _sizing(
15997				'Width', ourText,
15998				$.fn.width, maxWidth,
15999				maxHeight, maxWidth,
16000				minFontPixels, maxFontPixels
16001			);
16002
16003			// 3. Actually resize the text!
16004
16005			if (Opts.widthOnly) {
16006				ourText.css({
16007					'font-size'  : fontSizeWidth,
16008					'white-space': 'nowrap'
16009				});
16010
16011				if (Opts.changeLineHeight)
16012					ourText.parent().css(
16013						'line-height',
16014						(lineHeight * fontSizeWidth + 'px')
16015					);
16016			}
16017			else {
16018				var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth);
16019
16020				ourText.css('font-size', fontSizeFinal);
16021
16022				if (Opts.changeLineHeight)
16023					ourText.parent().css(
16024						'line-height',
16025						(lineHeight * fontSizeFinal) + 'px'
16026					);
16027			}
16028
16029			_debug(
16030				'[TextFill] Finished { ' +
16031				'Old font-size: ' + oldFontSize              + ', ' +
16032				'New font-size: ' + ourText.css('font-size') + ' }'
16033			);
16034
16035			// Oops, something wrong happened!
16036			// We weren't supposed to exceed the original size
16037			if ((ourText.width()  > maxWidth) ||
16038				(ourText.height() > maxHeight && !Opts.widthOnly)) {
16039
16040				ourText.css('font-size', oldFontSize);
16041
16042				// Failure callback
16043				if (Opts.fail)
16044					Opts.fail(this);
16045
16046				_debug(
16047					'[TextFill] Failure { ' +
16048					'Current Width: '  + ourText.width()  + ', ' +
16049					'Maximum Width: '  + maxWidth         + ', ' +
16050					'Current Height: ' + ourText.height() + ', ' +
16051					'Maximum Height: ' + maxHeight        + ' }'
16052				);
16053			}
16054			else if (Opts.success) {
16055				Opts.success(this);
16056			}
16057			else if (Opts.callback) {
16058				_warn('callback is deprecated, use success, instead');
16059
16060				// Success callback
16061				Opts.callback(this);
16062			}
16063		});
16064
16065		// Complete callback
16066		if (Opts.complete)
16067			Opts.complete(this);
16068
16069		_debug('[TextFill] End Debug');
16070		return this;
16071	};
16072
16073})(window.jQuery);
16074
16075!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;
16076function getStyles(config){
16077  // 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;
16077left: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+"}"
16078};
16079  var ShareUtils;
16080
16081if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
16082  Object.defineProperty(HTMLElement.prototype, "classList", {
16083    get: function() {
16084      var ret, self, update;
16085      update = function(fn) {
16086        return function(value) {
16087          var classes, index;
16088          classes = self.className.split(/\s+/);
16089          index = classes.indexOf(value);
16090          fn(classes, index, value);
16091          self.className = classes.join(" ");
16092        };
16093      };
16094      self = this;
16095      ret = {
16096        add: update(function(classes, index, value) {
16097          ~index || classes.push(value);
16098        }),
16099        remove: update(function(classes, index) {
16100          ~index && classes.splice(index, 1);
16101        }),
16102        toggle: update(function(classes, index, value) {
16103          if (~index) {
16104            classes.splice(index, 1);
16105          } else {
16106            classes.push(value);
16107          }
16108        }),
16109        contains: function(value) {
16110          return !!~self.className.split(/\s+/).indexOf(value);
16111        },
16112        item: function(i) {
16113          return self.className.split(/\s+/)[i] || null;
16114        }
16115      };
16116      Object.defineProperty(ret, "length", {
16117        get: function() {
16118          return self.className.split(/\s+/).length;
16119        }
16120      });
16121      return ret;
16122    }
16123  });
16124}
16125
16126String.prototype.to_rfc3986 = function() {
16127  var tmp;
16128  tmp = encodeURIComponent(this);
16129  return tmp.replace(/[!'()*]/g, function(c) {
16130    return "%" + c.charCodeAt(0).toString(16);
16131  });
16132};
16133
16134ShareUtils = (function() {
16135  function ShareUtils() {}
16136
16137  ShareUtils.prototype.extend = function(to, from, overwrite) {
16138    var hasProp, prop;
16139    for (prop in from) {
16140      hasProp = to[prop] !== undefined;
16141      if (hasProp && typeof from[prop] === "object") {
16142        this.extend(to[prop], from[prop], overwrite);
16143      } else {
16144        if (overwrite || !hasProp) {
16145          to[prop] = from[prop];
16146        }
16147      }
16148    }
16149  };
16150
16151  ShareUtils.prototype.hide = function(el) {
16152    return el.style.display = "none";
16153  };
16154
16155  ShareUtils.prototype.show = function(el) {
16156    return el.style.display = "block";
16157  };
16158
16159  ShareUtils.prototype.has_class = function(el, class_name) {
16160    return el.classList.contains(class_name);
16161  };
16162
16163  ShareUtils.prototype.add_class = function(el, class_name) {
16164    return el.classList.add(class_name);
16165  };
16166
16167  ShareUtils.prototype.remove_class = function(el, class_name) {
16168    return el.classList.remove(class_name);
16169  };
16170
16171  ShareUtils.prototype.is_encoded = function(str) {
16172    str = str.to_rfc3986();
16173    return decodeURIComponent(str) !== str;
16174  };
16175
16176  ShareUtils.prototype.encode = function(str) {
16177    if (typeof str === "undefined" || this.is_encoded(str)) {
16178      return str;
16179    } else {
16180      return str.to_rfc3986();
16181    }
16182  };
16183
16184  ShareUtils.prototype.popup = function(url, params) {
16185    var k, popup, qs, v;
16186    if (params == null) {
16187      params = {};
16188    }
16189    popup = {
16190      width: 500,
16191      height: 350
16192    };
16193    popup.top = (screen.height / 2) - (popup.height / 2);
16194    popup.left = (screen.width / 2) - (popup.width / 2);
16195    qs = ((function() {
16196      var _results;
16197      _results = [];
16198      for (k in params) {
16199        v = params[k];
16200        _results.push("" + k + "=" + (this.encode(v)));
16201      }
16202      return _results;
16203    }).call(this)).join('&');
16204    if (qs) {
16205      qs = "?" + qs;
16206    }
16207    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=" 
16207+ popup.width + ",height=" + popup.height);
16208  };
16209
16210  return ShareUtils;
16211
16212})();
16213var Share,
16214  __hasProp = {}.hasOwnProperty,
16215  __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; };
16216
16217Share = (function(_super) {
16218  __extends(Share, _super);
16219
16220  function Share(element, options) {
16221    this.element = element;
16222    this.el = {
16223      head: document.getElementsByTagName('head')[0],
16224      body: document.getElementsByTagName('body')[0]
16225    };
16226    this.config = {
16227      enabled_networks: 0,
16228      protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
16229      url: window.location.href.replace("&", "%26"),
16230      caption: null,
16231      title: this.default_title(),
16232      image: this.default_image(),
16233      description: this.default_description(),
16234      ui: {
16235        flyout: 'top center',
16236        button_text: 'Share',
16237        button_font: true,
16238        icon_font: true
16239      },
16240      networks: {
16241        google_plus: {
16242          enabled: true,
16243          url: null
16244        },
16245        twitter: {
16246          enabled: true,
16247          url: null,
16248          title: null,
16249          description: null
16250        },
16251        facebook: {
16252          enabled: true,
16253          load_sdk: true,
16254          url: null,
16255          app_id: null,
16256          title: null,
16257          caption: null,
16258          description: null,
16259          image: null
16260        },
16261        pinterest: {
16262          enabled: true,
16263          url: null,
16264          image: null,
16265          description: null
16266        },
16267        reddit: {
16268          enabled: true,
16269          url: null,
16270          title: null
16271        },
16272        linkedin: {
16273          enabled: true,
16274          url: null,
16275          title: null,
16276          description: null
16277        },
16278        xing: {
16279          enabled: true,
16280          url: null,
16281          title: null,
16282          image: null,
16283          description: null
16284        },
16285        whatsapp: {
16286          enabled: true,
16287          description: null,
16288          url: null
16289        },
16290        email: {
16291          enabled: true,
16292          title: null,
16293          description: null,
16294          url: null
16295        }
16296      }
16297    };
16298    this.setup(element, options);
16299    return this;
16300  }
16301
16302  Share.prototype.setup = function(element, opts) {
16303    var index, instance, instances, _i, _len;
16304    instances = document.querySelectorAll(element);
16305    this.extend(this.config, opts, true);
16306    this.set_global_configuration();
16307    this.normalize_network_configuration();
16308    if (this.config.ui.icon_font) {
16309      this.inject_icons();
16310    }
16311    if (this.config.ui.button_font) {
16312      this.inject_fonts();
16313    }
16314    if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
16315      this.inject_facebook_sdk();
16316    }
16317    for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
16318      instance = instances[index];
16319      this.setup_instance(element, index);
16320    }
16321  };
16322
16323  Share.prototype.setup_instance = function(element, index) {
16324    var button, instance, label, network, networks, _i, _len, _results,
16325      _this = this;
16326    instance = document.querySelectorAll(element)[index];
16327    this.hide(instance);
16328    this.add_class(instance, "sharer-" + index);
16329    instance = document.querySelectorAll(element)[index];
16330    this.inject_css(instance);
16331    this.inject_html(instance);
16332    this.show(instance);
16333    label = instance.getElementsByTagName("label")[0];
16334    button = instance.getElementsByClassName("social")[0];
16335    networks = instance.getElementsByTagName('li');
16336    this.add_class(button, "networks-" + this.config.enabled_networks);
16337    label.addEventListener("click", function() {
16338      return _this.event_toggle(button);
16339    });
16340    _this = this;
16341    _results = [];
16342    for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
16343      network = networks[index];
16344      _results.push(network.addEventListener("click", function() {
16345        _this.event_network(instance, this);
16346        return _this.event_close(button);
16347      }));
16348    }
16349    return _results;
16350  };
16351
16352  Share.prototype.event_toggle = function(button) {
16353    if (this.has_class(button, "active")) {
16354      return this.event_close(button);
16355    } else {
16356      return this.event_open(button);
16357    }
16358  };
16359
16360  Share.prototype.event_open = function(button) {
16361    if (this.has_class(button, "load")) {
16362      this.remove_class(button, "load");
16363    }
16364    return this.add_class(button, "active");
16365  };
16366
16367  Share.prototype.event_close = function(button) {
16368    return this.remove_class(button, "active");
16369  };
16370
16371  Share.prototype.event_network = function(instance, network) {
16372    var name;
16373    name = network.getAttribute("data-network");
16374    this.hook("before", name, instance);
16375    this["network_" + name]();
16376    return this.hook("after", name, instance);
16377  };
16378
16379  Share.prototype.open = function() {
16380    return this["public"]("open");
16381  };
16382
16383  Share.prototype.close = function() {
16384    return this["public"]("close");
16385  };
16386
16387  Share.prototype.toggle = function() {
16388    return this["public"]("toggle");
16389  };
16390
16391  Share.prototype["public"] = function(action) {
16392    var button, index, instance, _i, _len, _ref, _results;
16393    _ref = document.querySelectorAll(this.element);
16394    _results = [];
16395    for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
16396      instance = _ref[index];
16397      button = instance.getElementsByClassName("social")[0];
16398      _results.push(this["event_" + action](button));
16399    }
16400    return _results;
16401  };
16402
16403  Share.prototype.network_facebook = function() {
16404    if (this.config.networks.facebook.load_sdk) {
16405      if (!window.FB) {
16406        return console.error("The Facebook JS SDK hasn't loaded yet.");
16407      }
16408      return FB.ui({
16409        method: 'feed',
16410        name: this.config.networks.facebook.title,
16411        link: this.config.networks.facebook.url,
16412        picture: this.config.networks.facebook.image,
16413        caption: this.config.networks.facebook.caption,
16414        description: this.config.networks.facebook.description
16415      });
16416    } else {
16417      return this.popup('https://www.facebook.com/sharer/sharer.php', {
16418        u: this.config.networks.facebook.url
16419      });
16420    }
16421  };
16422
16423  Share.prototype.network_twitter = function() {
16424    return this.popup('https://twitter.com/intent/tweet', {
16425      text: this.config.networks.twitter.title,
16426      url: this.config.networks.twitter.url
16427    });
16428  };
16429
16430  Share.prototype.network_google_plus = function() {
16431    return this.popup('https://plus.google.com/share', {
16432      url: this.config.networks.google_plus.url
16433    });
16434  };
16435
16436  Share.prototype.network_pinterest = function() {
16437    return this.popup('https://www.pinterest.com/pin/create/button', {
16438      url: this.config.networks.pinterest.url,
16439      media: this.config.networks.pinterest.image,
16440      description: this.config.networks.pinterest.description
16441    });
16442  };
16443
16444  Share.prototype.network_linkedin = function() {
16445    return this.popup('https://www.linkedin.com/shareArticle', {
16446      url: this.config.networks.linkedin.url,
16447      title: this.config.networks.linkedin.title,
16448      summary: this.config.networks.linkedin.description
16449    });
16450  }
16451
16452  Share.prototype.network_xing = function() {
16453    return this.popup('https://www.xing.com/spi/shares/new', {
16454      url: this.config.networks.xing.url,
16455      image: this.config.networks.xing.image,
16456      title: this.config.networks.xing.title,
16457      summary: this.config.networks.xing.description
16458    });
16459  }
16460
16461  Share.prototype.network_email = function() {
16462    return this.popup('mailto:', {
16463      subject: this.config.networks.email.title,
16464      body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
16465    });
16466  };
16467
16468  Share.prototype.inject_icons = function() {
16469  //  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
16470  };
16471
16472  Share.prototype.inject_fonts = function() {
16473   // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
16474  };
16475
16476  Share.prototype.inject_stylesheet = function(url) {
16477    var link;
16478    if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
16479      link = document.createElement("link");
16480      link.setAttribute("rel", "stylesheet");
16481      link.setAttribute("href", url);
16482      return this.el.head.appendChild(link);
16483    }
16484  };
16485
16486  Share.prototype.inject_css = function(instance) {
16487    var css, meta, selector, style;
16488    selector = "." + (instance.getAttribute('class').split(" ").join("."));
16489    if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
16490      this.config.selector = selector;
16491      css = getStyles(this.config);
16492      style = document.createElement("style");
16493      style.type = "text/css";
16494      if (style.styleSheet) {
16495        style.styleSheet.cssText = css;
16496      } else {
16497        style.appendChild(document.createTextNode(css));
16498      }
16499      this.el.head.appendChild(style);
16500      delete this.config.selector;
16501      meta = document.createElement("meta");
16502      meta.setAttribute("name", "sharer" + selector);
16503      return this.el.head.appendChild(meta);
16504    }
16505  };
16506
16507  Share.prototype.inject_html = function(instance) {
16508    //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>";
16509    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>";
16510  };
16511
16512  Share.prototype.inject_facebook_sdk = function() {
16513    var fb_root, script;
16514    if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
16515      script = document.createElement("script");
16516      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')";
16517      fb_root = document.createElement("div");
16518      fb_root.id = "fb-root";
16519      this.el.body.appendChild(fb_root);
16520      return this.el.body.appendChild(script);
16521    }
16522  };
16523
16524  Share.prototype.hook = function(type, network, instance) {
16525    var fn, opts;
16526    fn = this.config.networks[network][type];
16527    if (typeof fn === "function") {
16528      opts = fn.call(this.config.networks[network], instance);
16529      if (opts !== void 0) {
16530        opts = this.normalize_filter_config_updates(opts);
16531        this.extend(this.config.networks[network], opts, true);
16532        this.normalize_network_configuration();
16533      }
16534    }
16535  };
16536
16537  Share.prototype.default_title = function() {
16538    var content;
16539    if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
16540      return encodeURIComponent(content.getAttribute('content'));
16541    } else if (content = document.querySelector('title')) {
16542      return encodeURIComponent(content.innerText);
16543    }
16544  };
16545
16546  Share.prototype.default_image = function() {
16547    var content;
16548    if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
16549      return content.getAttribute('content');
16550    }
16551  };
16552
16553  Share.prototype.default_description = function() {
16554    var content;
16555    if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
16556      return encodeURIComponent(content.getAttribute('content'));
16557    } else {
16558      return '';
16559    }
16560  };
16561
16562  Share.prototype.set_global_configuration = function() {
16563    var display, network, option, options, _ref, _results;
16564    _ref = this.config.networks;
16565    _results = [];
16566    for (network in _ref) {
16567      options = _ref[network];
16568      for (option in options) {
16569        if (this.config.networks[network][option] == null) {
16570          this.config.networks[network][option] = this.config[option];
16571        }
16572      }
16573      if (this.config.networks[network].enabled) {
16574        display = 'block';
16575        this.config.enabled_networks += 1;
16576      } else {
16577        display = 'none';
16578      }
16579      _results.push(this.config.networks[network].display = display);
16580    }
16581    return _results;
16582  };
16583
16584  Share.prototype.normalize_network_configuration = function() {
16585    if (!this.config.networks.facebook.app_id) {
16586      this.config.networks.facebook.load_sdk = false;
16587    }
16588    if (!this.is_encoded(this.config.networks.twitter.description)) {
16589      this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
16590    }
16591    if (typeof this.config.networks.facebook.app_id === 'number') {
16592      return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
16593    }
16594  };
16595
16596  Share.prototype.normalize_filter_config_updates = function(opts) {
16597    if (this.config.networks.facebook.app_id !== opts.app_id) {
16598      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.");
16599      delete opts.app_id;
16600    }
16601    if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
16602      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.");
16603      delete opts.app_id;
16604    }
16605    return opts;
16606  };
16607
16608  return Share;
16609
16610})(ShareUtils);
16611 return Share;
16612});
16613
16614// Generated by CoffeeScript 1.9.2
16615
16616// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
16617
16618(function() {
16619  var $, win;
16620
16621  $ = this.jQuery || window.jQuery;
16622
16623  win = $(window);
16624
16625  $.fn.stick_in_parent = function(opts) {
16626    var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
16627    if (opts == null) {
16628      opts = {};
16629    }
16630    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;
16631    if (offset_top == null) {
16632      offset_top = 0;
16633    }
16634    if (parent_selector == null) {
16635      parent_selector = void 0;
16636    }
16637    if (inner_scrolling == null) {
16638      inner_scrolling = true;
16639    }
16640    if (sticky_class == null) {
16641      sticky_class = "is_stuck";
16642    }
16643    doc = $(document);
16644    if (enable_bottoming == null) {
16645      enable_bottoming = true;
16646    }
16647    outer_width = function(el) {
16648      var _el, computed, w;
16649      if (window.getComputedStyle) {
16650        _el = el[0];
16651        computed = window.getComputedStyle(el[0]);
16652        w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
16653        if (computed.getPropertyValue("box-sizing") !== "border-box") {
16654          w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
16655        }
16656        return w;
16657      } else {
16658        return el.outerWidth(true);
16659      }
16660    };
16661    fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
16662      var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
16663      if (elm.data("sticky_kit")) {
16664        return;
16665      }
16666      elm.data("sticky_kit", true);
16667      last_scroll_height = doc.height();
16668      parent = elm.parent();
16669      if (parent_selector != null) {
16670        parent = parent.closest(parent_selector);
16671      }
16672      if (!parent.length) {
16673        throw "failed to find stick parent";
16674      }
16675      fixed = false;
16676      bottomed = false;
16677      spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
16678      if (spacer) {
16679        spacer.css('position', elm.css('position'));
16680      }
16681      recalc = function() {
16682        var border_top, padding_top, restore;
16683        if (detached) {
16684          return;
16685        }
16686        last_scroll_height = doc.height();
16687        border_top = parseInt(parent.css("border-top-width"), 10);
16688        padding_top = parseInt(parent.css("padding-top"), 10);
16689        padding_bottom = parseInt(parent.css("padding-bottom"), 10);
16690        parent_top = parent.offset().top + border_top + padding_top;
16691        parent_height = parent.height();
16692        if (fixed) {
16693          fixed = false;
vendor: 6,068 bytes, lines 16694-16888
16694          bottomed = false;
16695          if (manual_spacer == null) {
16696            elm.insertAfter(spacer);
16697            spacer.detach();
16698          }
16699          elm.css({
16700            position: "",
16701            top: "",
16702            width: "",
16703            bottom: ""
16704          }).removeClass(sticky_class);
16705          restore = true;
16706        }
16707        top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
16708        height = elm.outerHeight(true);
16709        el_float = elm.css("float");
16710        if (spacer) {
16711          spacer.css({
16712            width: outer_width(elm),
16713            height: height,
16714            display: elm.css("display"),
16715            "vertical-align": elm.css("vertical-align"),
16716            "float": el_float
16717          });
16718        }
16719        if (restore) {
16720          return tick();
16721        }
16722      };
16723      recalc();
16724      if (height === parent_height) {
16725        return;
16726      }
16727      last_pos = void 0;
16728      offset = offset_top;
16729      recalc_counter = recalc_every;
16730      tick = function() {
16731        var css, delta, recalced, scroll, will_bottom, win_height;
16732        if (detached) {
16733          return;
16734        }
16735        recalced = false;
16736        if (recalc_counter != null) {
16737          recalc_counter -= 1;
16738          if (recalc_counter <= 0) {
16739            recalc_counter = recalc_every;
16740            recalc();
16741            recalced = true;
16742          }
16743        }
16744        if (!recalced && doc.height() !== last_scroll_height) {
16745          recalc();
16746          recalced = true;
16747        }
16748        scroll = win.scrollTop();
16749        if (last_pos != null) {
16750          delta = scroll - last_pos;
16751        }
16752        last_pos = scroll;
16753        if (fixed) {
16754          if (enable_bottoming) {
16755            will_bottom = scroll + height + offset > parent_height + parent_top;
16756            if (bottomed && !will_bottom) {
16757              bottomed = false;
16758              elm.css({
16759                position: "fixed",
16760                bottom: "",
16761                top: offset
16762              }).trigger("sticky_kit:unbottom");
16763            }
16764          }
16765          if (scroll < top) {
16766            fixed = false;
16767            offset = offset_top;
16768            if (manual_spacer == null) {
16769              if (el_float === "left" || el_float === "right") {
16770                elm.insertAfter(spacer);
16771              }
16772              spacer.detach();
16773            }
16774            css = {
16775              position: "",
16776              width: "",
16777              top: ""
16778            };
16779            elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
16780          }
16781          if (inner_scrolling) {
16782            win_height = win.height();
16783            if (height + offset_top > win_height) {
16784              if (!bottomed) {
16785                offset -= delta;
16786                offset = Math.max(win_height - height, offset);
16787                offset = Math.min(offset_top, offset);
16788                if (fixed) {
16789                  elm.css({
16790                    top: offset + "px"
16791                  });
16792                }
16793              }
16794            }
16795          }
16796        } else {
16797          if (scroll > top) {
16798            fixed = true;
16799            css = {
16800              position: "fixed",
16801              top: offset
16802            };
16803            css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
16804            elm.css(css).addClass(sticky_class);
16805            if (manual_spacer == null) {
16806              elm.after(spacer);
16807              if (el_float === "left" || el_float === "right") {
16808                spacer.append(elm);
16809              }
16810            }
16811            elm.trigger("sticky_kit:stick");
16812          }
16813        }
16814        if (fixed && enable_bottoming) {
16815          if (will_bottom == null) {
16816            will_bottom = scroll + height + offset > parent_height + parent_top;
16817          }
16818          if (!bottomed && will_bottom) {
16819            bottomed = true;
16820            if (parent.css("position") === "static") {
16821              parent.css({
16822                position: "relative"
16823              });
16824            }
16825            return elm.css({
16826              position: "absolute",
16827              bottom: padding_bottom,
16828              top: "auto"
16829            }).trigger("sticky_kit:bottom");
16830          }
16831        }
16832      };
16833      recalc_and_tick = function() {
16834        recalc();
16835        return tick();
16836      };
16837      detach = function() {
16838        detached = true;
16839        win.off("touchmove", tick);
16840        win.off("scroll", tick);
16841        win.off("resize", recalc_and_tick);
16842        $(document.body).off("sticky_kit:recalc", recalc_and_tick);
16843        elm.off("sticky_kit:detach", detach);
16844        elm.removeData("sticky_kit");
16845        elm.css({
16846          position: "",
16847          bottom: "",
16848          top: "",
16849          width: ""
16850        });
16851        parent.position("position", "");
16852        if (fixed) {
16853          if (manual_spacer == null) {
16854            if (el_float === "left" || el_float === "right") {
16855              elm.insertAfter(spacer);
16856            }
16857            spacer.remove();
16858          }
16859          return elm.removeClass(sticky_class);
16860        }
16861      };
16862      win.on("touchmove", tick);
16863      win.on("scroll", tick);
16864      win.on("resize", recalc_and_tick);
16865      $(document.body).on("sticky_kit:recalc", recalc_and_tick);
16866      elm.on("sticky_kit:detach", detach);
16867      return setTimeout(tick, 0);
16868    };
16869    for (i = 0, len = this.length; i < len; i++) {
16870      elm = this[i];
16871      fn($(elm));
16872    }
16873    return this;
16874  };
16875
16876}).call(this);
16877/* ==========================================================================
16878 * bootstrap-tab-history.js
16879 * Author: Michael Narayan <[email protected]>
16880 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
16881 * ==========================================================================
16882 * Licensed under the Apache License, Version 2.0 (the "License"); you may
16883 * not use this file except in compliance with the License. You may obtain a
16884 * copy of the License at
16885 *
16886 * http://www.apache.org/licenses/LICENSE-2.0
16887 *
16888 * Unless required by applicable law or agreed to in writing, softw
16888are
16889 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16890 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16891 * License for the specific language governing permissions and limitations
16892 * under the License.
16893 * ========================================================================== */
16894
16895/* ========================================================================== */
16896/* JSHint directives                                                          */
16897/*                                                                            */
16898/* global BootstrapTabHistory: true                                           */
16899/*                                                                            */
16900/* global document                                                            */
16901/* global jQuery                                                              */
16902/* global history                                                             */
16903/* global window                                                              */
16904/* ========================================================================== */
16905
16906/**
16907 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
16908 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
16909 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
16910 *
16911 * See the README for additional information.
16912 *
16913 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
16914 */
16915
16916BootstrapTabHistory = {
16917  options: {
16918    /**
16919     * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
16920     * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
16921     *
16922     * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
16923     *
16924     * @public
16925     * @type {?number}
16926     */
16927    defaultAnchorYOffset: 0,
16928    /**
16929     * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
16930     *
16931     * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
16932     *
16933     * @public
16934     * @type {string}
16935     */
16936    defaultChanger: 'replace',
16937    /**
16938     * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
16939     * `null` is passed as the third parameter to these calls.
16940     *
16941     * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
16942     *
16943     * @public
16944     * @type {boolean}
16945     */
16946    defaultUpdateURL: false,
16947    /**
16948     * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
16949     * load.
16950     *
16951     * @public
16952     * @type {boolean}
16953     */
16954    showTabsBasedOnAnchor: true
16955  }
16956};
16957
16958(function () {
16959  'use strict';
16960
16961  jQuery(function () {
16962    if(history && history.pushState && history.replaceState) {
16963      var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
16964
16965      if(bootstrapTabHistory) {
16966        showTabsBasedOnState(bootstrapTabHistory);
16967      } else {
16968        showTabsBasedOnAnchor();
16969      }
16970
16971      backfillHistoryState();
16972
16973      jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
16974      jQuery(window).on('popstate', onPopState);
16975    } else {
16976      showTabsBasedOnAnchor();
16977    }
16978  });
16979
16980  /**
16981   * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
16982   *
16983   * @type {boolean}
16984   */
16985  var showingTabsBasedOnState = false;
16986
16987  /**
16988   * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
16989   * `history.back` handling when `data-tab-history-update-url` is true.
16990   */
16991  function backfillHistoryState() {
16992    var newState = null;
16993
16994    jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
16995      var $activeTabElement = jQuery(this);
16996      var selector = getTabSelector($activeTabElement);
16997
16998      if(selector) {
16999        var tabGroup = getTabGroup($activeTabElement);
17000
17001        if(tabGroup) {
17002          newState = createNewHistoryState(newState || history.state, tabGroup, selector);
17003        }
17004      }
17005    });
17006
17007    if(newState) {
17008      history.replaceState(newState, '', null);
17009    }
17010  }
17011
17012  /**
17013   * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
17014   * said bootstrapTabHistory attribute.
17015   *
17016   * @param {?object} existingState
17017   * @param {!string} tabGroup
17018   * @param {!string} selector
17019   * @returns {!object}
17020   */
17021  function createNewHistoryState(existingState, tabGroup, selector) {
17022    // Clone history.state and ensure it has a bootstrapTabHistory entry.
17023    var newState = jQuery.extend(true, {}, existingState, {
17024      bootstrapTabHistory: {}
17025    });
17026
17027    newState.bootstrapTabHistory[tabGroup] = selector;
17028
17029    return newState;
17030  }
17031
17032  /**
17033   * @param {jQuery} $tab
17034   * @returns {?string}
17035   */
17036  function getTabGroup($tab) {
17037    return parseTruthyAttributeValue($tab.data('tab-history'));
17038  }
17039
17040  /**
17041   * @param {jQuery} $tab
17042   * @returns {?string}
17043   */
17044  function getTabSelector($tab) {
17045    return $tab.data('target') || $tab.attr('href');
17046  }
17047
17048  /**
17049   * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
17050   *
17051   * @param {jQuery.Event} shownEvt
17052   */
17053  function onShownTab(shownEvt) {
17054    if(!showingTabsBasedOnState) {
17055      var $activatedTab = jQuery(shownEvt.target);
17056      if ( $activatedTab.hasClass('panel-collapse') )
17057        $activatedTab = $activatedTab.closest('.panel').find('a');
17058      var selector = getTabSelector($activatedTab);
17059
17060      if(selector) {
17061        var tabGroup = getTabGroup($activatedTab);
17062
17063        if(tabGroup) {
17064          var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
17065          var newState = createNewHistoryState(history.state, tabGroup, selector);
17066          var updateURL = (function ($activatedTab) {
17067            if(selector[0] === '#') {
17068              var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
17069
17070              if(elementUpdateURLOption === undefined) {
17071                return BootstrapTabHistory.options.defaultUpdateURL;
17072              } else {
17073                return elementUpdateURLOption;
17074              }
17075            } else {
17076              return false;
17077            }
17078          })($activatedTab);
17079
17080          switch(historyChanger) {
17081            case 'push':
17082              history.pushState(newState, '', updateURL ? selector : null);
17083              break;
17084            case 'replace':
17085              history.replaceState(newState, '', updateURL ? selector : null);
17086              break;
17087            default:
17088              throw new Error('Unknown tab-history-changer: ' + historyChanger);
17089          }
17090        }
17091      }
17092    }
17093  }
17094
17095  /**
17096   * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
17097   */
17098  function onPopState() {
17099    var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
17100
17101    if(bootstrapTabHistory) {
17102      showTabsBasedOnState(bootstrapTabHistory);
17103    }
17104  }
17105
17106  /**
17107   * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
17108   *
17109   * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
17110   *
17111   * @param {*} value
17112   * @returns {*}
17113   */
17114  function parseTruthyAttributeValue(value) {
17115    if(value) {
17116      return value;
17117    } else if(value === '') {
17118      return true;
17119    } else {
17120      return value;
17121    }
17122  }
17123
17124  /**
17125   * Show tabs based upon the anchor component of `window.location`.
17126   */
17127  function showTabsBasedOnAnchor() {
17128    if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
17129      var anchor = window.location && window.location.hash;
17130
17131      if(anchor) {
17132        var $tabElement = showTabForSelector(anchor);
17133
17134        if($tabElement && window.addEventListener && window.removeEventListener) {
17135          var anchorYOffset = (function ($tabElement) {
17136            var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
17137
17138            if(elementSetting === undefined) {
17139              return BootstrapTabHistory.options.defaultAnchorYOffset;
17140            } else {
17141              return elementSetting;
17142            }
17143          })($tabElement);
17144
17145          // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
17146          //   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
17147          //   `history.state` object should have been used (unless the browser did not support the modern History API).
17148          if(anchorYOffset || anchorYOffset === 0) {
17149            var scrollListener = function resetAnchorScroll () {
17150              window.removeEventListener('scroll', scrollListener);
17151              window.scrollTo(0, anchorYOffset);
17152            };
17153
17154            window.addEventListener('scroll', scrollListener);
17155          }
17156        }
17157      }
17158    }
17159  }
17160
17161  /**
17162   * Show a tab which corresponds to the provided selector.
17163   *
17164   * @param {string} selector - A CSS selector.
17165   * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
17166   */
17167  function showTabForSelector(selector) {
17168    var $tabElement = (function (selector) {
17169      var $ret = null;
17170
17171      jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
17172        var $potentialTab = jQuery(this);
17173
17174        if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
17175          $ret = $potentialTab;
17176          return false;
vendor: 4,522 bytes, lines 17177-17326
17177        } else {
17178         return null;
17179        }
17180      });
17181
17182      return $ret;
17183    })(selector);
17184
17185    if($tabElement) {
17186      $tabElement.trigger('click');
17187      //$tabElement.tab('show');
17188    }
17189
17190    return $tabElement;
17191  }
17192
17193  /**
17194   * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
17195   *
17196   * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
17197   */
17198  function showTabsBasedOnState(bootstrapTabHistory) {
17199    showingTabsBasedOnState = true;
17200
17201    try {
17202      for(var k in bootstrapTabHistory) {
17203        if(bootstrapTabHistory.hasOwnProperty(k)) {
17204          showTabForSelector(bootstrapTabHistory[k]);
17205        }
17206      }
17207    } finally {
17208      showingTabsBasedOnState = false;
17209    }
17210  }
17211})();
17212
17213/*!
17214 * Justified Gallery - v3.6.3
17215 * http://miromannino.github.io/Justified-Gallery/
17216 * Copyright (c) 2016 Miro Mannino
17217 * Licensed under the MIT license.
17218 */
17219(function($) {
17220
17221  function hasScrollBar() {
17222    return $("body").height() > $(window).height();
17223  }
17224  /**
17225   * Justified Gallery controller constructor
17226   *
17227   * @param $gallery the gallery to build
17228   * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults)
17229   * @constructor
17230   */
17231  var JustifiedGallery = function ($gallery, settings) {
17232    
17233    this.settings = settings;
17234    this.checkSettings();
17235
17236    this.imgAnalyzerTimeout = null;
17237    this.entries = null;
17238    this.buildingRow = {
17239      entriesBuff : [],
17240      width : 0,
17241      height : 0,
17242      aspectRatio : 0
17243    };
17244    this.lastFetchedEntry = null;
17245    this.lastAnalyzedIndex = -1;
17246    this.yield = {
17247      every : 2, // do a flush every n flushes (must be greater than 1)
17248      flushed : 0 // flushed rows without a yield
17249    };
17250    this.border = settings.border >= 0 ? settings.border : settings.margins;
17251    this.maxRowHeight = this.retrieveMaxRowHeight();
17252    this.suffixRanges = this.retrieveSuffixRanges();
17253    this.offY = this.border;
17254    this.rows = 0;
17255    this.spinner = {
17256      phase : 0,
17257      timeSlot : 150,
17258      $el : $('<div class="spinner"><span></span><span></span><span></span></div>'),
17259      intervalId : null
17260    };
17261    this.checkWidthIntervalId = null;
17262    this.galleryWidth = $gallery.width();
17263    this.$gallery = $gallery;
17264
17265  };
17266
17267  /** @returns {String} the best suffix given the width and the height */
17268  JustifiedGallery.prototype.getSuffix = function (width, height) {
17269    var longestSide, i;
17270    longestSide = (width > height) ? width : height;
17271    for (i = 0; i < this.suffixRanges.length; i++) {
17272      if (longestSide <= this.suffixRanges[i]) {
17273        return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
17274      }
17275    }
17276    return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
17277  };
17278
17279  /**
17280   * Remove the suffix from the string
17281   *
17282   * @returns {string} a new string without the suffix
17283   */
17284  JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
17285    return str.substring(0, str.length - suffix.length);
17286  };
17287
17288  /**
17289   * @returns {boolean} a boolean to say if the suffix is contained in the str or not
17290   */
17291  JustifiedGallery.prototype.endsWith = function (str, suffix) {
17292    return str.indexOf(suffix, str.length - suffix.length) !== -1;
17293  };
17294
17295  /**
17296   * Get the used suffix of a particular url
17297   *
17298   * @param str
17299   * @returns {String} return the used suffix
17300   */
17301  JustifiedGallery.prototype.getUsedSuffix = function (str) {
17302    for (var si in this.settings.sizeRangeSuffixes) {
17303      if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
17304        if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
17305        if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
17306      }
17307    }
17308    return '';
17309  };
17310
17311  /**
17312   * Given an image src, with the width and the height, returns the new image src with the
17313   * best suffix to show the best quality thumbnail.
17314   *
17315   * @returns {String} the suffix to use
17316   */
17317  JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
17318    var newImageSrc;
17319
17320    if (this.settings.thumbnailPath) {
17321      newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
17322    } else {
17323      var matchRes = imageSrc.match(this.settings.extension);
17324      var ext = (matchRes !== null) ? matchRes[0] : '';
17325      newImageSrc = imageSrc.replace(this.settings.extension, '');
17326      newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
17327      newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
17328    }
17329
17330    return newImageSrc;
17331  };
17332
17333  /**
17334   * Shows the images that is in the given entry
17335   *
17336   * @param $entry the entry
17337   * @param callback the callback that is called when the show animation is finished
17338   */
17339  JustifiedGallery.prototype.showImg = function ($entry, callback) {
17340    if (this.settings.cssAnimation) {
17341      $entry.addClass('entry-visible');
17342      if (callback) callback();
17343    } else {
17344      $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
17345      $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
17346    }
17347  };
17348
17349  /**
17350   * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
17351   * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
17352   *
17353   * @param $image the image to analyze
17354   * @returns {String} the extracted src
17355   */
17356  JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
17357    var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src');
17358    $image.data('jg.originalSrc', imageSrc);
17359    return imageSrc;
17360  };
17361
17362  /** @returns {jQuery} the image in the given entry */
17363  JustifiedGallery.prototype.imgFromEntry = function ($entry) {
17364    var $img = $entry.find('> img');
17365    if ($img.length === 0) $img = $entry.find('> a > img');
17366    if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
17367    return $img.length === 0 ? null : $img;
17368  };
17369
17370  /** @returns {jQuery} the caption in the given entry */
17371  JustifiedGallery.prototype.captionFromEntry = function ($entry) {
17372    var $caption = $entry.find('> .caption');
17373    return $caption.length === 0 ? null : $caption;
17374  };
17375
17376  /**
17377   * Display the entry
17378   *
17379   * @param {jQuery} $entry the entry to display
17380   * @param {int} x the x position where the entry must be positioned
17381   * @param y the y position where the entry must be positioned
17382   * @param imgWidth the image width
17383   * @param imgHeight the image height
17384   * @param rowHeight the row height of the row that owns the entry
17385   */
17386  JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
17387    $entry.width(imgWidth);
17388    $entry.height(Math.floor(rowHeight));//hacked by Uncode
17389    $entry.css('top', Math.floor(y));//hacked by Uncode
17390    $entry.css('left', x);
17391
17392    var $image = this.imgFromEntry($entry);
17393    if ($image !== null) {
17394      $image.css('width', imgWidth);
17395      $image.css('height', imgHeight);
17396      $image.css('margin-left', - imgWidth / 2);
17397      $image.css('margin-top', - imgHeight / 2);
17398
17399      // Image reloading for an high quality of thumbnails
17400      var imageSrc = $image.attr('src');
17401      var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
17402
17403      $image.one('error', function () {
17404        $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it.
17405      });
17406
17407      var loadNewImage = function () {
17408        if (imageSrc !== newImageSrc) { //load the new image after the fadeIn
17409          $image.attr('src', newImageSrc);
17410        }
17411      };
17412
17413      if ($entry.data('jg.loaded') === 'skipped') {
17414        this.onImageEvent(imageSrc, $.proxy(function() {
17415          this.showImg($entry, loadNewImage);
17416          $entry.data('jg.loaded', true);
17417        }, this));
17418      } else {
17419        this.showImg($entry, loadNewImage);
17420      }
17421
17422    } else {
17423      this.showImg($entry);
17424    }
17425
17426    this.displayEntryCaption($entry);
17427  };
17428
17429  /**
17430   * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
17431   * or the 'title' attributes.
17432   *
17433   * @param {jQuery} $entry the entry to process
17434   */
17435  JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
17436    var $image = this.imgFromEntry($entry);
17437    if ($image !== null && this.settings.captions) {
17438      var $imgCaption = this.captionFromEntry($entry);
17439
17440      // Create it if it doesn't exists
17441      if ($imgCaption === null) {
17442        var caption = $image.attr('alt');
17443        if (!this.isValidCaption(caption)) caption = $entry.attr('title');
17444        if (this.isValidCaption(caption)) { // Create only we found something
17445          $imgCaption = $('<div class="caption">' + caption + '</div>');
17446          $entry.append($imgCaption);
17447          $entry.data('jg.createdCaption', true);
17448        }
17449      }
17450
17451      // Create events (we check again the $imgCaption because it can be still inexistent)
17452      if ($imgCaption !== null) {
17453        if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
17454        this.addCaptionEventsHandlers($entry);
17455      }
17456    } else {
17457      this.removeCaptionEventsHandlers($entry);
17458    }
17459  };
17460
17461  /**
17462   * Validates the caption
17463   *
17464   * @param caption The caption that should be validated
17465   * @return {boolean} Validation result
17466   */
17467  JustifiedGallery.prototype.isValidCaption = function (caption) {
17468    return (typeof caption !== 'undefined' && caption.length > 0);
17469  };
17470
17471  /**
17472   * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
17473   * It shows the caption using jQuery (or using CSS if it is configured so)
17474   *
17475   * @param {Event} eventObject the event object
17476   */
17477  JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
17478    var $caption = this.captionFromEntry($(eventObject.currentTarget));
17479    if (this.settings.cssAnimation) {
17480      $caption.addClass('caption-visible').removeClass('caption-hidden');
17481    } else {
17482      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
17483          this.settings.captionSettings.visibleOpacity);
17484    }
17485  };
17486
17487  /**
17488   * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
17489   * It hides the caption using jQuery (or using CSS if it is configured so)
17490   *
17491   * @param {Event} eventObject the event object
17492   */
17493  JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
17494    var $caption = this.captionFromEntry($(eventObject.currentTarget));
17495    if (this.settings.cssAnimation) {
17496      $caption.removeClass('caption-visible').removeClass('caption-hidden');
17497    } else {
17498      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
17499          this.settings.captionSettings.nonVisibleOpacity);
17500    }
17501  };
17502
17503  /**
17504   * Add the handlers of the entry for the caption
17505   *
17506   * @param $entry the entry to modify
17507   */
17508  JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
17509    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
17510    if (typeof captionMouseEvents === 'undefined') {
17511      captionMouseEvents = {
17512        mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
17513        mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
17514      };
17515      $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
17516      $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
17517      $entry.data('jg.captionMouseEvents', captionMouseEvents);
17518    }
17519  };
17520
17521  /**
17522   * Remove the handlers of the entry for the caption
17523   *
17524   * @param $entry the entry to modify
17525   */
17526  JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
17527    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
17528    if (typeof captionMouseEvents !== 'undefined') {
17529      $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
17530      $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
17531      $entry.removeData('jg.captionMouseEvents');
17532    }
17533  };
17534
17535  /**
17536   * Justify the building row, preparing it to
17537   *
17538   * @param isLastRow
17539   * @returns a boolean to know if the row has been justified or not
17540   */
17541  JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) {
17542    var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
17543    var minHeight = 0;
17544    var availableWidth = this.galleryWidth - 2 * this.border - (
17545        (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
17546    var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
17547    var defaultRowHeight = this.settings.rowHeight;
17548    var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
17549
17550    //Skip the last row if we can't justify it and the lastRow == 'hide'
17551    if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) {
17552      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17553        $entry = this.buildingRow.entriesBuff[i];
17554        if (this.settings.cssAnimation)
17555          $entry.removeClass('entry-visible');
17556        else {
17557          $entry.stop().fadeTo(0, 0.1);
17558          $entry.find('> img, > a > img').fadeTo(0, 0);
17559        }
17560      }
17561      return -1;
17562    }
17563
17564    // With lastRow = nojustify, justify if is justificable (the images will not become too big)
17565    if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
17566      justify = false;
17567
17568      if (this.rows > 0) {
17569        defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
17570        justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
17571      }
17572    }
17573
17574    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17575      $entry = this.buildingRow.entriesBuff[i];
17576      imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
17577
17578      if (justify) {
17579        newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
17580        newImgH = rowHeight;
17581      } else {
17582        newImgW = defaultRowHeight * imgAspectRatio;
17583        newImgH = defaultRowHeight;
17584      }
17585
17586      availableWidth -= Math.round(newImgW);
17587      $entry.data('jg.jwidth', Math.round(newImgW));
17588      $entry.data('jg.jheight', Math.ceil(newImgH));
17589      if (i === 0 || minHeight > newImgH) minHeight = newImgH;
17590    }
17591
17592    this.buildingRow.height = minHeight;
17593    return justify;
17594  };
17595
17596  /**
17597   * Clear the building row data to be used for a new row
17598   */
17599  JustifiedGallery.prototype.clearBuildingRow = function () {
17600    this.buildingRow.entriesBuff = [];
17601    this.buildingRow.aspectRatio = 0;
17602    this.buildingRow.width = 0;
17603  };
17604
17605  /**
17606   * Flush a row: justify it, modify the gallery height accordingly to the row height
17607   *
17608   * @param isLastRow
17609   */
17610  JustifiedGallery.prototype.flushRow = function (isLastRow) {
17611    var settings = this.settings;
17612    var $entry, buildingRowRes, offX = this.border, i;
17613
17614    buildingRowRes = this.prepareBuildingRow(isLastRow);
17615    if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) {
17616      this.clearBuildingRow();
17617      return;
17618    }
17619
17620    if (this.maxRowHeight) {
17621      if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) {
17622        this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight;
17623      } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) {
17624        this.buildingRow.height = this.maxRowHeight.value;
17625      }
17626    }
17627
17628    //Align last (unjustified) row
17629    if (settings.lastRow === 'center' || settings.lastRow === 'right') {
17630      var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
17631
17632      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17633        $entry = this.buildingRow.entriesBuff[i];
17634        availableWidth -= $entry.data('jg.jwidth');
17635      }
17636
17637      if (settings.lastRow === 'center')
17638        offX += availableWidth / 2;
17639      else if (settings.lastRow === 'right')
17640        offX += availableWidth;
17641    }
17642
17643    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
17644      $entry = this.buildingRow.entriesBuff[i];
17645      this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
17646      offX += $entry.data('jg.jwidth') + settings.margins;
17647    }
17648
17649    //Gallery Height
17650    this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
17651    this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight());
17652
17653    if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
17654      //Ready for a new row
17655      this.offY += this.buildingRow.height + settings.margins;
17656      this.rows += 1;
17657      this.clearBuildingRow();
17658      this.$gallery.trigger('jg.rowflush');
17659    }
17660  };
17661
17662  /**
17663   * Checks the width of the gallery container, to know if a new justification is needed
17664   */
17665  var scrollBarOn = false;
17666  JustifiedGallery.prototype.checkWidth = function () {
17667    this.checkWidthIntervalId = setInterval($.proxy(function () {
17668      var galleryWidth = parseFloat(this.$gallery.width());
17669      if (hasScrollBar() === scrollBarOn) {
17670        if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
17671          this.galleryWidth = galleryWidth;
17672          this.rewind();
17673
17674          // Restart to analyze
17675          this.startImgAnalyzer(true);
17676        }
17677      } else {
17678        scrollBarOn = hasScrollBar();
17679        this.galleryWidth = galleryWidth;
17680      }
17681    }, this), this.settings.refreshTime);
17682  };
17683
17684  /**
17685   * @returns {boolean} a boolean saying if the spinner is active or not
17686   */
17687  JustifiedGallery.prototype.isSpinnerActive = function () {
17688    return this.spinner.intervalId !== null;
17689  };
17690
17691  /**
17692   * @returns {int} the spinner height
17693   */
17694  JustifiedGallery.prototype.getSpinnerHeight = function () {
17695    return this.spinner.$el.innerHeight();
17696  };
17697
17698  /**
17699   * Stops the spinner animation and modify the gallery height to exclude the spinner
17700   */
17701  JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
17702    clearInterval(this.spinner.intervalId);
17703    this.spinner.intervalId = null;
17704    this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight());
17705    this.spinner.$el.detach();
17706  };
17707
17708  /**
17709   * Starts the spinner animation
17710   */
17711  JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
17712    var spinnerContext = this.spinner;
17713    var $spinnerPoints = spinnerContext.$el.find('span');
17714    clearInterval(spinnerContext.intervalId);
17715    this.$gallery.append(spinnerContext.$el);
17716    this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight());
17717    spinnerContext.intervalId = setInterval(function () {
17718      if (spinnerContext.phase < $spinnerPoints.length) {
17719        $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
17720      } else {
vendor: 4,333 bytes, lines 17721-17865
17721        $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
17722      }
17723      spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
17724    }, spinnerContext.timeSlot);
17725  };
17726
17727  /**
17728   * Rewind the image analysis to start from the first entry.
17729   */
17730  JustifiedGallery.prototype.rewind = function () {
17731    this.lastFetchedEntry = null;
17732    this.lastAnalyzedIndex = -1;
17733    this.offY = this.border;
17734    this.rows = 0;
17735    this.clearBuildingRow();
17736  };
17737
17738  /**
17739   * Update the entries searching it from the justified gallery HTML element
17740   *
17741   * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
17742   * @returns {boolean} true if some entries has been founded
17743   */
17744  JustifiedGallery.prototype.updateEntries = function (norewind) {
17745    var newEntries;
17746
17747    if (norewind && this.lastFetchedEntry != null) {
17748      newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray();
17749    } else {
17750      this.entries = [];
17751      newEntries = this.$gallery.children(this.settings.selector).toArray();
17752    }
17753
17754    if (newEntries.length > 0) {
17755
17756      // Sort or randomize
17757      if ($.isFunction(this.settings.sort)) {
17758        newEntries = this.sortArray(newEntries);
17759      } else if (this.settings.randomize) {
17760        newEntries = this.shuffleArray(newEntries);
17761      }
17762      this.lastFetchedEntry = newEntries[newEntries.length - 1];
17763
17764      // Filter
17765      if (this.settings.filter) {
17766        newEntries = this.filterArray(newEntries);
17767      } else {
17768        this.resetFilters(newEntries);
17769      }
17770
17771    }
17772
17773    this.entries = this.entries.concat(newEntries);
17774    return true;
17775  };
17776
17777  /**
17778   * Apply the entries order to the DOM, iterating the entries and appending the images
17779   *
17780   * @param entries the entries that has been modified and that must be re-ordered in the DOM
17781   */
17782  JustifiedGallery.prototype.insertToGallery = function (entries) {
17783    var that = this;
17784    $.each(entries, function () {
17785      $(this).appendTo(that.$gallery);
17786    });
17787  };
17788
17789  /**
17790   * Shuffle the array using the Fisher-Yates shuffle algorithm
17791   *
17792   * @param a the array to shuffle
17793   * @return the shuffled array
17794   */
17795  JustifiedGallery.prototype.shuffleArray = function (a) {
17796    var i, j, temp;
17797    for (i = a.length - 1; i > 0; i--) {
17798      j = Math.floor(Math.random() * (i + 1));
17799      temp = a[i];
17800      a[i] = a[j];
17801      a[j] = temp;
17802    }
17803    this.insertToGallery(a);
17804    return a;
17805  };
17806
17807  /**
17808   * Sort the array using settings.comparator as comparator
17809   *
17810   * @param a the array to sort (it is sorted)
17811   * @return the sorted array
17812   */
17813  JustifiedGallery.prototype.sortArray = function (a) {
17814    a.sort(this.settings.sort);
17815    this.insertToGallery(a);
17816    return a;
17817  };
17818
17819  /**
17820   * Reset the filters removing the 'jg-filtered' class from all the entries
17821   *
17822   * @param a the array to reset
17823   */
17824  JustifiedGallery.prototype.resetFilters = function (a) {
17825    for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
17826  };
17827
17828  /**
17829   * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
17830   *
17831   * @param a the array to filter
17832   * @return the filtered array
17833   */
17834  JustifiedGallery.prototype.filterArray = function (a) {
17835    var settings = this.settings;
17836    if ($.type(settings.filter) === 'string') {
17837      // Filter only keeping the entries passed in the string
17838      return a.filter(function (el) {
17839        var $el = $(el);
17840        if ($el.is(settings.filter)) {
17841          $el.removeClass('jg-filtered');
17842          return true;
17843        } else {
17844          $el.addClass('jg-filtered').removeClass('jg-visible');
17845          return false;
17846        }
17847      });
17848    } else if ($.isFunction(settings.filter)) {
17849      // Filter using the passed function
17850      var filteredArr = a.filter(settings.filter);
17851      for (var i = 0; i < a.length; i++) {
17852        if (filteredArr.indexOf(a[i]) == -1) {
17853          $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
17854        } else {
17855          $(a[i]).removeClass('jg-filtered');
17856        }
17857      }
17858      return filteredArr;
17859    }
17860  };
17861
17862  /**
17863   * Destroy the Justified Gallery instance.
17864   *
17865   * It clears all the css properties added in the style attributes. We doesn't backup the original
17866   * values for those css attributes, because it costs (performance) and because in general one
17867   * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
17868   * classes). Creating a backup is also difficult because JG could be called multiple times and
17869   * with different style attributes.
17870   */
17871  JustifiedGallery.prototype.destroy = function () {
17872    clearInterval(this.checkWidthIntervalId);
17873
17874    $.each(this.entries, $.proxy(function(_, entry) {
17875      var $entry = $(entry);
17876
17877      // Reset entry style
17878      $entry.css('width', '');
17879      $entry.css('height', '');
17880      $entry.css('top', '');
17881      $entry.css('left', '');
17882      $entry.data('jg.loaded', undefined);
17883      $entry.removeClass('jg-entry');
17884
17885      // Reset image style
17886      var $img = this.imgFromEntry($entry);
17887      $img.css('width', '');
17888      $img.css('height', '');
17889      $img.css('margin-left', '');
17890      $img.css('margin-top', '');
17891      $img.attr('src', $img.data('jg.originalSrc'));
17892      $img.data('jg.originalSrc', undefined);
17893
17894      // Remove caption
17895      this.removeCaptionEventsHandlers($entry);
17896      var $caption = this.captionFromEntry($entry);
17897      if ($entry.data('jg.createdCaption')) {
17898        // remove also the caption element (if created by jg)
17899        $entry.data('jg.createdCaption', undefined);
17900        if ($caption !== null) $caption.remove();
17901      } else {
17902        if ($caption !== null) $caption.fadeTo(0, 1);
17903      }
17904
17905    }, this));
17906
17907    this.$gallery.css('height', '');
17908    this.$gallery.removeClass('justified-gallery');
17909    this.$gallery.data('jg.controller', undefined);
17910  };
17911
17912  /**
17913   * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
17914   *
17915   * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
17916   */
17917  JustifiedGallery.prototype.analyzeImages = function (isForResize) {
17918    for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
17919      var $entry = $(this.entries[i]);
17920      if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
17921        var availableWidth = this.galleryWidth - 2 * this.border - (
17922            (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
17923        var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
17924        if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
17925          this.flushRow(false);
17926          if(++this.yield.flushed >= this.yield.every) {
17927            this.startImgAnalyzer(isForResize);
17928            return;
17929          }
17930        }
17931
17932        this.buildingRow.entriesBuff.push($entry);
17933        this.buildingRow.aspectRatio += imgAspectRatio;
17934        this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
17935        this.lastAnalyzedIndex = i;
17936
17937      } else if ($entry.data('jg.loaded') !== 'error') {
17938        return;
17939      }
17940    }
17941
17942    // Last row flush (the row is not full)
17943    if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true);
17944
17945    if (this.isSpinnerActive()) {
17946      this.stopLoadingSpinnerAnimation();
17947    }
17948
17949    /* Stop, if there is, the timeout to start the analyzeImages.
17950     This is because an image can be set loaded, and the timeout can be set,
17951     but this image can be analyzed yet.
17952     */
17953    this.stopImgAnalyzerStarter();
17954
17955    //On complete callback
17956    this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete');
17957    this.$gallery.height(this.galleryHeightToSet);
17958  };
17959
17960  /**
17961   * Stops any ImgAnalyzer starter (that has an assigned timeout)
17962   */
17963  JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
17964    this.yield.flushed = 0;
17965    if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout);
17966  };
17967
17968  /**
17969   * Starts the image analyzer. It is not immediately called to let the browser to update the view
17970   *
17971   * @param isForResize specifies if the image analyzer must be called for resizing or not
17972   */
17973  JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
17974    var that = this;
17975    this.stopImgAnalyzerStarter();
17976    this.imgAnalyzerTimeout = setTimeout(function () {
17977      that.analyzeImages(isForResize);
17978    }, 0.001); // we can't start it immediately due to a IE different behaviour
17979  };
17980
17981  /**
17982   * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
17983   * because some browsers, with a 404 set complete = true.
17984   *
17985   * @param imageSrc the image src to load
17986   * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 17987-18337
17987   * @param onError callback that is called in case of an error
17988   */
17989  JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
17990    if (!onLoad && !onError) return;
17991
17992    var memImage = new Image();
17993    var $memImage = $(memImage);
17994    if (onLoad) {
17995      $memImage.one('load', function () {
17996        $memImage.off('load error');
17997        onLoad(memImage);
17998      });
17999    }
18000    if (onError) {
18001      $memImage.one('error', function() {
18002        $memImage.off('load error');
18003        onError(memImage);
18004      });
18005    }
18006    memImage.src = imageSrc;
18007  };
18008
18009  /**
18010   * Init of Justified Gallery controlled
18011   * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
18012   */
18013  JustifiedGallery.prototype.init = function () {
18014    var imagesToLoad = false, skippedImages = false, that = this;
18015    $.each(this.entries, function (index, entry) {
18016      var $entry = $(entry);
18017      var $image = that.imgFromEntry($entry);
18018
18019      $entry.addClass('jg-entry');
18020
18021      if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
18022
18023        // Link Rel global overwrite
18024        if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
18025
18026        // Link Target global overwrite
18027        if (that.settings.target !== null) $entry.attr('target', that.settings.target);
18028
18029        if ($image !== null) {
18030
18031          // Image src
18032          var imageSrc = that.extractImgSrcFromImage($image);
18033          $image.attr('src', imageSrc);
18034
18035          /* If we have the height and the width, we don't wait that the image is loaded, but we start directly
18036           * with the justification */
18037          if (that.settings.waitThumbnailsLoad === false) {
18038            var width = parseFloat($image.attr('width'));
18039            var height = parseFloat($image.attr('height'));
18040            if (!isNaN(width) && !isNaN(height)) {
18041              $entry.data('jg.width', width);
18042              $entry.data('jg.height', height);
18043              $entry.data('jg.loaded', 'skipped');
18044              skippedImages = true;
18045              that.startImgAnalyzer(false);
18046              return true; // continue
18047            }
18048          }
18049
18050          $entry.data('jg.loaded', false);
18051          imagesToLoad = true;
18052
18053          // Spinner start
18054          if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
18055
18056          that.onImageEvent(imageSrc, function (loadImg) { // image loaded
18057            $entry.data('jg.width', loadImg.width);
18058            $entry.data('jg.height', loadImg.height);
18059            $entry.data('jg.loaded', true);
18060            that.startImgAnalyzer(false);
18061          }, function () { // image load error
18062            $entry.data('jg.loaded', 'error');
18063            that.startImgAnalyzer(false);
18064          });
18065
18066        } else {
18067          $entry.data('jg.loaded', true);
18068          $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
18069          $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
18070        }
18071
18072      }
18073
18074    });
18075
18076    if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
18077    this.checkWidth();
18078  };
18079
18080  /**
18081   * Checks that it is a valid number. If a string is passed it is converted to a number
18082   *
18083   * @param settingContainer the object that contains the setting (to allow the conversion)
18084   * @param settingName the setting name
18085   */
18086  JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
18087    if ($.type(settingContainer[settingName]) === 'string') {
18088      settingContainer[settingName] = parseFloat(settingContainer[settingName]);
18089    }
18090
18091    if ($.type(settingContainer[settingName]) === 'number') {
18092      if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
18093    } else {
18094      throw settingName + ' must be a number';
18095    }
18096  };
18097
18098  /**
18099   * Checks the sizeRangeSuffixes and, if necessary, converts
18100   * its keys from string (e.g. old settings with 'lt100') to int.
18101   */
18102  JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
18103    if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
18104      throw 'sizeRangeSuffixes must be defined and must be an object';
18105    }
18106
18107    var suffixRanges = [];
18108    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
18109      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
18110    }
18111
18112    var newSizeRngSuffixes = {0: ''};
18113    for (var i = 0; i < suffixRanges.length; i++) {
18114      if ($.type(suffixRanges[i]) === 'string') {
18115        try {
18116          var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
18117          newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
18118        } catch (e) {
18119          throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
18120        }
18121      } else {
18122        newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
18123      }
18124    }
18125
18126    this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
18127  };
18128
18129  /**
18130   * check and convert the maxRowHeight setting
18131   */
18132  JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
18133    var newMaxRowHeight = { };
18134
18135    if ($.type(this.settings.maxRowHeight) === 'string') {
18136      if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
18137        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
18138        newMaxRowHeight.isPercentage = false;
18139      } else {
18140        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight);
18141        newMaxRowHeight.isPercentage = true;
18142      }
18143    } else if ($.type(this.settings.maxRowHeight) === 'number') {
18144      newMaxRowHeight.value = this.settings.maxRowHeight;
18145      newMaxRowHeight.isPercentage = false;
18146    } else if (this.settings.maxRowHeight === false ||
18147        this.settings.maxRowHeight === null ||
18148        typeof this.settings.maxRowHeight == 'undefined') {
18149      return null;
18150    } else {
18151      throw 'maxRowHeight must be a number or a percentage';
18152    }
18153
18154    // check if the converted value is not a number
18155    if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight';
18156
18157    // check values
18158    if (newMaxRowHeight.isPercentage) {
18159      if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100;
18160    }
18161
18162    return newMaxRowHeight;
18163  };
18164
18165  /**
18166   * Checks the settings
18167   */
18168  JustifiedGallery.prototype.checkSettings = function () {
18169    this.checkSizeRangesSuffixes();
18170
18171    this.checkOrConvertNumber(this.settings, 'rowHeight');
18172    this.checkOrConvertNumber(this.settings, 'margins');
18173    this.checkOrConvertNumber(this.settings, 'border');
18174
18175    var lastRowModes = [
18176      'justify',
18177      'nojustify',
18178      'left',
18179      'center',
18180      'right',
18181      'hide'
18182    ];
18183    if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
18184      throw 'lastRow must be one of: ' + lastRowModes.join(', ');
18185    }
18186
18187    this.checkOrConvertNumber(this.settings, 'justifyThreshold');
18188    if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
18189      throw 'justifyThreshold must be in the interval [0,1]';
18190    }
18191    if ($.type(this.settings.cssAnimation) !== 'boolean') {
18192      throw 'cssAnimation must be a boolean';
18193    }
18194
18195    if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
18196    this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
18197
18198    this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
18199    if (this.settings.captionSettings.visibleOpacity < 0 ||
18200        this.settings.captionSettings.visibleOpacity > 1) {
18201      throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
18202    }
18203
18204    this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
18205    if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
18206        this.settings.captionSettings.nonVisibleOpacity > 1) {
18207      throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
18208    }
18209
18210    this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
18211    this.checkOrConvertNumber(this.settings, 'refreshTime');
18212    this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
18213    if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
18214    if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
18215
18216    if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
18217      throw 'sort must be false or a comparison function';
18218    }
18219
18220    if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
18221        $.type(this.settings.filter) !== 'string') {
18222      throw 'filter must be false, a string or a filter function';
18223    }
18224  };
18225
18226  /**
18227   * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
18228   * @returns {Array} sorted suffix ranges
18229   */
18230  JustifiedGallery.prototype.retrieveSuffixRanges = function () {
18231    var suffixRanges = [];
18232    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
18233      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
18234    }
18235    suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
18236    return suffixRanges;
18237  };
18238
18239  /**
18240   * Update the existing settings only changing some of them
18241   *
18242   * @param newSettings the new settings (or a subgroup of them)
18243   */
18244  JustifiedGallery.prototype.updateSettings = function (newSettings) {
18245    // In this case Justified Gallery has been called again changing only some options
18246    this.settings = $.extend({}, this.settings, newSettings);
18247    this.checkSettings();
18248
18249    // As reported in the settings: negative value = same as margins, 0 = disabled
18250    this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
18251
18252    this.maxRowHeight = this.retrieveMaxRowHeight();
18253    this.suffixRanges = this.retrieveSuffixRanges();
18254  };
18255
18256  /**
18257   * Justified Gallery plugin for jQuery
18258   *
18259   * Events
18260   *  - jg.complete : called when all the gallery has been created
18261   *  - jg.resize : called when the gallery has been resized
18262   *  - jg.rowflush : when a new row appears
18263   *
18264   * @param arg the action (or the settings) passed when the plugin is called
18265   * @returns {*} the object itself
18266   */
18267  $.fn.justifiedGallery = function (arg) {
18268    return this.each(function (index, gallery) {
18269
18270      var $gallery = $(gallery);
18271      $gallery.addClass('justified-gallery');
18272
18273      var controller = $gallery.data('jg.controller');
18274      if (typeof controller === 'undefined') {
18275        // Create controller and assign it to the object data
18276        if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
18277          if (arg === 'destroy') return; // Just a call to an unexisting object
18278          throw 'The argument must be an object';
18279        }
18280        controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg));
18281        $gallery.data('jg.controller', controller);
18282      } else if (arg === 'norewind') {
18283        // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
18284        // ... left to be more readable
18285      } else if (arg === 'destroy') {
18286        controller.destroy();
18287        return;
18288      } else {
18289        // In this case Justified Gallery has been called again changing only some options
18290        controller.updateSettings(arg);
18291        controller.rewind();
18292      }
18293
18294      // Update the entries list
18295      if (!controller.updateEntries(arg === 'norewind')) return;
18296
18297      // Init justified gallery
18298      controller.init();
18299
18300    });
18301  };
18302
18303  // Default options
18304  $.fn.justifiedGallery.defaults = {
18305    sizeRangeSuffixes: { }, /* e.g. Flickr configuration
18306        {
18307          100: '_t',  // used when longest is less than 100px
18308          240: '_m',  // used when longest is between 101px and 240px
18309          320: '_n',  // ...
18310          500: '',
18311          640: '_z',
18312          1024: '_b'  // used as else case because it is the last
18313        }
18314    */
18315    thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
18316    path relative to a specific thumbnail size. The function should accept respectively three arguments:
18317    current path, width and height */
18318    rowHeight: 120,
18319    maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
18320                         // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
18321                         // can't exceed 3 * rowHeight)
18322    margins: 1,
18323    border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
18324
18325    lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
18326
18327    justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
18328                             * (i.e. lastRow setting is not considered) */
18329    waitThumbnailsLoad: true,
18330    captions: true,
18331    cssAnimation: true,
18332    imagesAnimationDuration: 500, // ignored with css animations
18333    captionSettings: { // ignored with css animations
18334      animationDuration: 500,
18335      visibleOpacity: 0.7,
18336      nonVisibleOpacity: 0.0
18337    },
vendor: 5,759 bytes, lines 18338-18480
18338    rel: null, // rewrite the rel of each analyzed links
18339    target: null, // rewrite the target of all links
18340    extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
18341    refreshTime: 200, // time interval (in ms) to check if the page changes its width
18342    refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
18343    randomize: false,
18344    sort: false, /*
18345      - false: to do not sort
18346      - function: to sort them using the function as comparator (see Array.prototype.sort())
18347    */
18348    filter: false, /*
18349      - false, null or undefined: for a disabled filter
18350      - a string: an entry is kept if entry.is(filter string) returns true
18351                  see jQuery's .is() function for further information
18352      - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
18353                    It follows the specifications of the Array.prototype.filter() function of JavaScript.
18354    */
18355    selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery
18356  };
18357
18358}(jQuery));
18359/*!
18360* Customized version of iScroll.js 0.0.1
18361* It fixes bugs affecting its integration with fullpage.js
18362*/
18363/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
18364(function (window, document, Math) {
18365var rAF = window.requestAnimationFrame  ||
18366    window.webkitRequestAnimationFrame  ||
18367    window.mozRequestAnimationFrame     ||
18368    window.oRequestAnimationFrame       ||
18369    window.msRequestAnimationFrame      ||
18370    function (callback) { window.setTimeout(callback, 1000 / 60); };
18371
18372var utils = (function () {
18373    var me = {};
18374
18375    var _elementStyle = document.createElement('div').style;
18376    var _vendor = (function () {
18377        var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
18378            transform,
18379            i = 0,
18380            l = vendors.length;
18381
18382        for ( ; i < l; i++ ) {
18383            transform = vendors[i] + 'ransform';
18384            if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
18385        }
18386
18387        return false;
18388    })();
18389
18390    function _prefixStyle (style) {
18391        if ( _vendor === false ) return false;
18392        if ( _vendor === '' ) return style;
18393        return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
18394    }
18395
18396    me.getTime = Date.now || function getTime () { return new Date().getTime(); };
18397
18398    me.extend = function (target, obj) {
18399        for ( var i in obj ) {
18400            target[i] = obj[i];
18401        }
18402    };
18403
18404    me.addEvent = function (el, type, fn, capture) {
18405        el.addEventListener(type, fn, !!capture);
18406    };
18407
18408    me.removeEvent = function (el, type, fn, capture) {
18409        el.removeEventListener(type, fn, !!capture);
18410    };
18411
18412    me.prefixPointerEvent = function (pointerEvent) {
18413        return window.MSPointerEvent ?
18414            'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
18415            pointerEvent;
18416    };
18417
18418    me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
18419        var distance = current - start,
18420            speed = Math.abs(distance) / time,
18421            destination,
18422            duration;
18423
18424        deceleration = deceleration === undefined ? 0.0006 : deceleration;
18425
18426        destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
18427        duration = speed / deceleration;
18428
18429        if ( destination < lowerMargin ) {
18430            destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
18431            distance = Math.abs(destination - current);
18432            duration = distance / speed;
18433        } else if ( destination > 0 ) {
18434            destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
18435            distance = Math.abs(current) + destination;
18436            duration = distance / speed;
18437        }
18438
18439        return {
18440            destination: Math.round(destination),
18441            duration: duration
18442        };
18443    };
18444
18445    var _transform = _prefixStyle('transform');
18446
18447    me.extend(me, {
18448        hasTransform: _transform !== false,
18449        hasPerspective: _prefixStyle('perspective') in _elementStyle,
18450        hasTouch: 'ontouchstart' in window,
18451        hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
18452        hasTransition: _prefixStyle('transition') in _elementStyle
18453    });
18454
18455    /*
18456    This should find all Android browsers lower than build 535.19 (both stock browser and webview)
18457    - galaxy S2 is ok
18458    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
18459    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
18460   - galaxy S3 is badAndroid (stock brower, webview)
18461     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
18462   - galaxy S4 is badAndroid (stock brower, webview)
18463     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
18464   - galaxy S5 is OK
18465     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
18466   - galaxy S6 is OK
18467     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
18468  */
18469    me.isBadAndroid = (function() {
18470        var appVersion = window.navigator.appVersion;
18471        // Android browser is not a chrome browser.
18472        if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
18473            var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
18474            if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
18475                return parseFloat(safariVersion[1]) < 535.19;
18476            } else {
18477                return true;
18478            }
18479        } else {
18480            return false;
vendor: 5,536 bytes, lines 18481-18673
18481        }
18482    })();
18483
18484    me.extend(me.style = {}, {
18485        transform: _transform,
18486        transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
18487        transitionDuration: _prefixStyle('transitionDuration'),
18488        transitionDelay: _prefixStyle('transitionDelay'),
18489        transformOrigin: _prefixStyle('transformOrigin')
18490    });
18491
18492    me.hasClass = function (e, c) {
18493        var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
18494        return re.test(e.className);
18495    };
18496
18497    me.addClass = function (e, c) {
18498        if ( me.hasClass(e, c) ) {
18499            return;
18500        }
18501
18502        var newclass = e.className.split(' ');
18503        newclass.push(c);
18504        e.className = newclass.join(' ');
18505    };
18506
18507    me.removeClass = function (e, c) {
18508        if ( !me.hasClass(e, c) ) {
18509            return;
18510        }
18511
18512        var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
18513        e.className = e.className.replace(re, ' ');
18514    };
18515
18516    me.offset = function (el) {
18517        var left = -el.offsetLeft,
18518            top = -el.offsetTop;
18519
18520        // jshint -W084
18521        while (el = el.offsetParent) {
18522            left -= el.offsetLeft;
18523            top -= el.offsetTop;
18524        }
18525        // jshint +W084
18526
18527        return {
18528            left: left,
18529            top: top
18530        };
18531    };
18532
18533    me.preventDefaultException = function (el, exceptions) {
18534        for ( var i in exceptions ) {
18535            if ( exceptions[i].test(el[i]) ) {
18536                return true;
18537            }
18538        }
18539
18540        return false;
18541    };
18542
18543    me.extend(me.eventType = {}, {
18544        touchstart: 1,
18545        touchmove: 1,
18546        touchend: 1,
18547
18548        mousedown: 2,
18549        mousemove: 2,
18550        mouseup: 2,
18551
18552        pointerdown: 3,
18553        pointermove: 3,
18554        pointerup: 3,
18555
18556        MSPointerDown: 3,
18557        MSPointerMove: 3,
18558        MSPointerUp: 3
18559    });
18560
18561    me.extend(me.ease = {}, {
18562        quadratic: {
18563            style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
18564            fn: function (k) {
18565                return k * ( 2 - k );
18566            }
18567        },
18568        circular: {
18569            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)
18570            fn: function (k) {
18571                return Math.sqrt( 1 - ( --k * k ) );
18572            }
18573        },
18574        back: {
18575            style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
18576            fn: function (k) {
18577                var b = 4;
18578                return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
18579            }
18580        },
18581        bounce: {
18582            style: '',
18583            fn: function (k) {
18584                if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
18585                    return 7.5625 * k * k;
18586                } else if ( k < ( 2 / 2.75 ) ) {
18587                    return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
18588                } else if ( k < ( 2.5 / 2.75 ) ) {
18589                    return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
18590                } else {
18591                    return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
18592                }
18593            }
18594        },
18595        elastic: {
18596            style: '',
18597            fn: function (k) {
18598                var f = 0.22,
18599                    e = 0.4;
18600
18601                if ( k === 0 ) { return 0; }
18602                if ( k == 1 ) { return 1; }
18603
18604                return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
18605            }
18606        }
18607    });
18608
18609    me.tap = function (e, eventName) {
18610        var ev = document.createEvent('Event');
18611        ev.initEvent(eventName, true, true);
18612        ev.pageX = e.pageX;
18613        ev.pageY = e.pageY;
18614        e.target.dispatchEvent(ev);
18615    };
18616
18617    me.click = function (e) {
18618        var target = e.target,
18619            ev;
18620
18621        if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
18622            // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
18623            // initMouseEvent is deprecated.
18624            ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
18625            ev.initEvent('click', true, true);
18626            ev.view = e.view || window;
18627            ev.detail = 1;
18628            ev.screenX = target.screenX || 0;
18629            ev.screenY = target.screenY || 0;
18630            ev.clientX = target.clientX || 0;
18631            ev.clientY = target.clientY || 0;
18632            ev.ctrlKey = !!e.ctrlKey;
18633            ev.altKey = !!e.altKey;
18634            ev.shiftKey = !!e.shiftKey;
18635            ev.metaKey = !!e.metaKey;
18636            ev.button = 0;
18637            ev.relatedTarget = null;
18638            ev._constructed = true;
18639            target.dispatchEvent(ev);
18640        }
18641    };
18642
18643    return me;
18644})();
18645function IScroll (el, options) {
18646    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
18647    this.scroller = this.wrapper.children[0];
18648    this.scrollerStyle = this.scroller.style;       // cache style for better performance
18649
18650    this.options = {
18651
18652        resizeScrollbars: true,
18653
18654        mouseWheelSpeed: 20,
18655
18656        snapThreshold: 0.334,
18657
18658// INSERT POINT: OPTIONS
18659        disablePointer : !utils.hasPointer,
18660        disableTouch : utils.hasPointer || !utils.hasTouch,
18661        disableMouse : utils.hasPointer || utils.hasTouch,
18662        startX: 0,
18663        startY: 0,
18664        scrollY: true,
18665        directionLockThreshold: 5,
18666        momentum: true,
18667
18668        bounce: true,
18669        bounceTime: 600,
18670        bounceEasing: '',
18671
18672        preventDefault: true,
18673        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
vendor: 4,420 bytes, lines 18673-18817
18673SELECT|LABEL)$/ },
18674
18675        HWCompositing: true,
18676        useTransition: true,
18677        useTransform: true,
18678        bindToWrapper: typeof window.onmousedown === "undefined"
18679    };
18680
18681    for ( var i in options ) {
18682        this.options[i] = options[i];
18683    }
18684
18685    // Normalize options
18686    this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
18687
18688    this.options.useTransition = utils.hasTransition && this.options.useTransition;
18689    this.options.useTransform = utils.hasTransform && this.options.useTransform;
18690
18691    this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
18692    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
18693
18694    // If you want eventPassthrough I have to lock one of the axes
18695    this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
18696    this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
18697
18698    // With eventPassthrough we also need lockDirection mechanism
18699    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
18700    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
18701
18702    this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
18703
18704    this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
18705
18706    if ( this.options.tap === true ) {
18707        this.options.tap = 'tap';
18708    }
18709
18710    // https://github.com/cubiq/iscroll/issues/1029
18711    if (!this.options.useTransition && !this.options.useTransform) {
18712        if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
18713            this.scrollerStyle.position = "relative";
18714        }
18715    }
18716
18717    if ( this.options.shrinkScrollbars == 'scale' ) {
18718        this.options.useTransition = false;
18719    }
18720
18721    this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
18722
18723// INSERT POINT: NORMALIZATION
18724
18725    // Some defaults
18726    this.x = 0;
18727    this.y = 0;
18728    this.directionX = 0;
18729    this.directionY = 0;
18730    this._events = {};
18731
18732// INSERT POINT: DEFAULTS
18733
18734    this._init();
18735    this.refresh();
18736
18737    this.scrollTo(this.options.startX, this.options.startY);
18738    this.enable();
18739}
18740
18741IScroll.prototype = {
18742    version: '5.2.0',
18743
18744    _init: function () {
18745        this._initEvents();
18746
18747        if ( this.options.scrollbars || this.options.indicators ) {
18748            this._initIndicators();
18749        }
18750
18751        if ( this.options.mouseWheel ) {
18752            this._initWheel();
18753        }
18754
18755        if ( this.options.snap ) {
18756            this._initSnap();
18757        }
18758
18759        if ( this.options.keyBindings ) {
18760            this._initKeys();
18761        }
18762
18763// INSERT POINT: _init
18764
18765    },
18766
18767    destroy: function () {
18768        this._initEvents(true);
18769        clearTimeout(this.resizeTimeout);
18770        this.resizeTimeout = null;
18771        this._execEvent('destroy');
18772    },
18773
18774    _transitionEnd: function (e) {
18775        if ( e.target != this.scroller || !this.isInTransition ) {
18776            return;
18777        }
18778
18779        this._transitionTime();
18780        if ( !this.resetPosition(this.options.bounceTime) ) {
18781            this.isInTransition = false;
18782            this._execEvent('scrollEnd');
18783        }
18784    },
18785
18786    _start: function (e) {
18787        // React to left mouse button only
18788        if ( utils.eventType[e.type] != 1 ) {
18789          // for button property
18790          // http://unixpapa.com/js/mouse.html
18791          var button;
18792        if (!e.which) {
18793          /* IE case */
18794          button = (e.button < 2) ? 0 :
18795                   ((e.button == 4) ? 1 : 2);
18796        } else {
18797          /* All others */
18798          button = e.button;
18799        }
18800            if ( button !== 0 ) {
18801                return;
18802            }
18803        }
18804
18805        if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
18806            return;
18807        }
18808
18809        if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
18810            e.preventDefault();
18811        }
18812
18813        var point = e.touches ? e.touches[0] : e,
18814            pos;
18815
18816        this.initiated  = utils.eventType[e.type];
18817        this.moved      = false;
vendor: 5,928 bytes, lines 18818-18996
18818        this.distX      = 0;
18819        this.distY      = 0;
18820        this.directionX = 0;
18821        this.directionY = 0;
18822        this.directionLocked = 0;
18823
18824        this.startTime = utils.getTime();
18825
18826        if ( this.options.useTransition && this.isInTransition ) {
18827            this._transitionTime();
18828            this.isInTransition = false;
18829            pos = this.getComputedPosition();
18830            this._translate(Math.round(pos.x), Math.round(pos.y));
18831            this._execEvent('scrollEnd');
18832        } else if ( !this.options.useTransition && this.isAnimating ) {
18833            this.isAnimating = false;
18834            this._execEvent('scrollEnd');
18835        }
18836
18837        this.startX    = this.x;
18838        this.startY    = this.y;
18839        this.absStartX = this.x;
18840        this.absStartY = this.y;
18841        this.pointX    = point.pageX;
18842        this.pointY    = point.pageY;
18843
18844        this._execEvent('beforeScrollStart');
18845    },
18846
18847    _move: function (e) {
18848        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
18849            return;
18850        }
18851
18852        if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
18853            e.preventDefault();
18854        }
18855
18856        var point       = e.touches ? e.touches[0] : e,
18857            deltaX      = point.pageX - this.pointX,
18858            deltaY      = point.pageY - this.pointY,
18859            timestamp   = utils.getTime(),
18860            newX, newY,
18861            absDistX, absDistY;
18862
18863        this.pointX     = point.pageX;
18864        this.pointY     = point.pageY;
18865
18866        this.distX      += deltaX;
18867        this.distY      += deltaY;
18868        absDistX        = Math.abs(this.distX);
18869        absDistY        = Math.abs(this.distY);
18870
18871        // We need to move at least 10 pixels for the scrolling to initiate
18872        if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
18873            return;
18874        }
18875
18876        // If you are scrolling in one direction lock the other
18877        if ( !this.directionLocked && !this.options.freeScroll ) {
18878            if ( absDistX > absDistY + this.options.directionLockThreshold ) {
18879                this.directionLocked = 'h';     // lock horizontally
18880            } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
18881                this.directionLocked = 'v';     // lock vertically
18882            } else {
18883                this.directionLocked = 'n';     // no lock
18884            }
18885        }
18886
18887        if ( this.directionLocked == 'h' ) {
18888            if ( this.options.eventPassthrough == 'vertical' ) {
18889                e.preventDefault();
18890            } else if ( this.options.eventPassthrough == 'horizontal' ) {
18891                this.initiated = false;
18892                return;
18893            }
18894
18895            deltaY = 0;
18896        } else if ( this.directionLocked == 'v' ) {
18897            if ( this.options.eventPassthrough == 'horizontal' ) {
18898                e.preventDefault();
18899            } else if ( this.options.eventPassthrough == 'vertical' ) {
18900                this.initiated = false;
18901                return;
18902            }
18903
18904            deltaX = 0;
18905        }
18906
18907        deltaX = this.hasHorizontalScroll ? deltaX : 0;
18908        deltaY = this.hasVerticalScroll ? deltaY : 0;
18909
18910        newX = this.x + deltaX;
18911        newY = this.y + deltaY;
18912
18913        // Slow down if outside of the boundaries
18914        if ( newX > 0 || newX < this.maxScrollX ) {
18915            newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
18916        }
18917        if ( newY > 0 || newY < this.maxScrollY ) {
18918            newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
18919        }
18920
18921        this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
18922        this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
18923
18924        if ( !this.moved ) {
18925            this._execEvent('scrollStart');
18926        }
18927
18928        this.moved = true;
18929
18930        this._translate(newX, newY);
18931
18932/* REPLACE START: _move */
18933
18934        if ( timestamp - this.startTime > 300 ) {
18935            this.startTime = timestamp;
18936            this.startX = this.x;
18937            this.startY = this.y;
18938        }
18939
18940/* REPLACE END: _move */
18941
18942    },
18943
18944    _end: function (e) {
18945        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
18946            return;
18947        }
18948
18949        if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
18950            e.preventDefault();
18951        }
18952
18953        var point = e.changedTouches ? e.changedTouches[0] : e,
18954            momentumX,
18955            momentumY,
18956            duration = utils.getTime() - this.startTime,
18957            newX = Math.round(this.x),
18958            newY = Math.round(this.y),
18959            distanceX = Math.abs(newX - this.startX),
18960            distanceY = Math.abs(newY - this.startY),
18961            time = 0,
18962            easing = '';
18963
18964        this.isInTransition = 0;
18965        this.initiated = 0;
18966        this.endTime = utils.getTime();
18967
18968        // reset if we are outside of the boundaries
18969        if ( this.resetPosition(this.options.bounceTime) ) {
18970            return;
18971        }
18972
18973        this.scrollTo(newX, newY);  // ensures that the last position is rounded
18974
18975        // we scrolled less than 10 pixels
18976        if ( !this.moved ) {
18977            if ( this.options.tap ) {
18978                utils.tap(e, this.options.tap);
18979            }
18980
18981            if ( this.options.click ) {
18982                utils.click(e);
18983            }
18984
18985            this._execEvent('scrollCancel');
18986            return;
18987        }
18988
18989        if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
18990            this._execEvent('flick');
18991            return;
18992        }
18993
18994        // start momentum animation if needed
18995        if ( this.options.momentum && duration < 300 ) {
18996            momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 7,740 bytes, lines 18996-19269
18996idth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
18997            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 };
18998            newX = momentumX.destination;
18999            newY = momentumY.destination;
19000            time = Math.max(momentumX.duration, momentumY.duration);
19001            this.isInTransition = 1;
19002        }
19003
19004
19005        if ( this.options.snap ) {
19006            var snap = this._nearestSnap(newX, newY);
19007            this.currentPage = snap;
19008            time = this.options.snapSpeed || Math.max(
19009                    Math.max(
19010                        Math.min(Math.abs(newX - snap.x), 1000),
19011                        Math.min(Math.abs(newY - snap.y), 1000)
19012                    ), 300);
19013            newX = snap.x;
19014            newY = snap.y;
19015
19016            this.directionX = 0;
19017            this.directionY = 0;
19018            easing = this.options.bounceEasing;
19019        }
19020
19021// INSERT POINT: _end
19022
19023        if ( newX != this.x || newY != this.y ) {
19024            // change easing function when scroller goes out of the boundaries
19025            if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
19026                easing = utils.ease.quadratic;
19027            }
19028
19029            this.scrollTo(newX, newY, time, easing);
19030            return;
19031        }
19032
19033        this._execEvent('scrollEnd');
19034    },
19035
19036    _resize: function () {
19037        var that = this;
19038
19039        clearTimeout(this.resizeTimeout);
19040
19041        this.resizeTimeout = setTimeout(function () {
19042            that.refresh();
19043        }, this.options.resizePolling);
19044    },
19045
19046    resetPosition: function (time) {
19047        var x = this.x,
19048            y = this.y;
19049
19050        time = time || 0;
19051
19052        if ( !this.hasHorizontalScroll || this.x > 0 ) {
19053            x = 0;
19054        } else if ( this.x < this.maxScrollX ) {
19055            x = this.maxScrollX;
19056        }
19057
19058        if ( !this.hasVerticalScroll || this.y > 0 ) {
19059            y = 0;
19060        } else if ( this.y < this.maxScrollY ) {
19061            y = this.maxScrollY;
19062        }
19063
19064        if ( x == this.x && y == this.y ) {
19065            return false;
19066        }
19067
19068        this.scrollTo(x, y, time, this.options.bounceEasing);
19069
19070        return true;
19071    },
19072
19073    disable: function () {
19074        this.enabled = false;
19075    },
19076
19077    enable: function () {
19078        this.enabled = true;
19079    },
19080
19081    refresh: function () {
19082        var rf = this.wrapper.offsetHeight;     // Force reflow
19083
19084        this.wrapperWidth   = this.wrapper.clientWidth;
19085        this.wrapperHeight  = this.wrapper.clientHeight;
19086
19087/* REPLACE START: refresh */
19088
19089        this.scrollerWidth  = this.scroller.offsetWidth;
19090        this.scrollerHeight = this.scroller.offsetHeight;
19091
19092        this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
19093        this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
19094
19095/* REPLACE END: refresh */
19096
19097        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
19098        this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
19099
19100        if ( !this.hasHorizontalScroll ) {
19101            this.maxScrollX = 0;
19102            this.scrollerWidth = this.wrapperWidth;
19103        }
19104
19105        if ( !this.hasVerticalScroll ) {
19106            this.maxScrollY = 0;
19107            this.scrollerHeight = this.wrapperHeight;
19108        }
19109
19110        this.endTime = 0;
19111        this.directionX = 0;
19112        this.directionY = 0;
19113
19114        this.wrapperOffset = utils.offset(this.wrapper);
19115
19116        this._execEvent('refresh');
19117
19118        this.resetPosition();
19119
19120// INSERT POINT: _refresh
19121
19122    },
19123
19124    on: function (type, fn) {
19125        if ( !this._events[type] ) {
19126            this._events[type] = [];
19127        }
19128
19129        this._events[type].push(fn);
19130    },
19131
19132    off: function (type, fn) {
19133        if ( !this._events[type] ) {
19134            return;
19135        }
19136
19137        var index = this._events[type].indexOf(fn);
19138
19139        if ( index > -1 ) {
19140            this._events[type].splice(index, 1);
19141        }
19142    },
19143
19144    _execEvent: function (type) {
19145        if ( !this._events[type] ) {
19146            return;
19147        }
19148
19149        var i = 0,
19150            l = this._events[type].length;
19151
19152        if ( !l ) {
19153            return;
19154        }
19155
19156        for ( ; i < l; i++ ) {
19157            this._events[type][i].apply(this, [].slice.call(arguments, 1));
19158        }
19159    },
19160
19161    scrollBy: function (x, y, time, easing) {
19162        x = this.x + x;
19163        y = this.y + y;
19164        time = time || 0;
19165
19166        this.scrollTo(x, y, time, easing);
19167    },
19168
19169    scrollTo: function (x, y, time, easing) {
19170        easing = easing || utils.ease.circular;
19171
19172        this.isInTransition = this.options.useTransition && time > 0;
19173        var transitionType = this.options.useTransition && easing.style;
19174        if ( !time || transitionType ) {
19175                if(transitionType) {
19176                    this._transitionTimingFunction(easing.style);
19177                    this._transitionTime(time);
19178                }
19179            this._translate(x, y);
19180        } else {
19181            this._animate(x, y, time, easing.fn);
19182        }
19183    },
19184
19185    scrollToElement: function (el, time, offsetX, offsetY, easing) {
19186        el = el.nodeType ? el : this.scroller.querySelector(el);
19187
19188        if ( !el ) {
19189            return;
19190        }
19191
19192        var pos = utils.offset(el);
19193
19194        pos.left -= this.wrapperOffset.left;
19195        pos.top  -= this.wrapperOffset.top;
19196
19197        // if offsetX/Y are true we center the element to the screen
19198        if ( offsetX === true ) {
19199            offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
19200        }
19201        if ( offsetY === true ) {
19202            offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
19203        }
19204
19205        pos.left -= offsetX || 0;
19206        pos.top  -= offsetY || 0;
19207
19208        pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
19209        pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
19210
19211        time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
19212
19213        this.scrollTo(pos.left, pos.top, time, easing);
19214    },
19215
19216    _transitionTime: function (time) {
19217        if (!this.options.useTransition) {
19218            return;
19219        }
19220        time = time || 0;
19221        var durationProp = utils.style.transitionDuration;
19222        if(!durationProp) {
19223            return;
19224        }
19225
19226        this.scrollerStyle[durationProp] = time + 'ms';
19227
19228        if ( !time && utils.isBadAndroid ) {
19229            this.scrollerStyle[durationProp] = '0.0001ms';
19230            // remove 0.0001ms
19231            var self = this;
19232            rAF(function() {
19233                if(self.scrollerStyle[durationProp] === '0.0001ms') {
19234                    self.scrollerStyle[durationProp] = '0s';
19235                }
19236            });
19237        }
19238
19239
19240        if ( this.indicators ) {
19241            for ( var i = this.indicators.length; i--; ) {
19242                this.indicators[i].transitionTime(time);
19243            }
19244        }
19245
19246
19247// INSERT POINT: _transitionTime
19248
19249    },
19250
19251    _transitionTimingFunction: function (easing) {
19252        this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
19253
19254
19255        if ( this.indicators ) {
19256            for ( var i = this.indicators.length; i--; ) {
19257                this.indicators[i].transitionTimingFunction(easing);
19258            }
19259        }
19260
19261
19262// INSERT POINT: _transitionTimingFunction
19263
19264    },
19265
19266    _translate: function (x, y) {
19267        //Uncode addition
19268        if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
19269            return false;
vendor: 9,939 bytes, lines 19270-19581
19270
19271        if ( this.options.useTransform ) {
19272
19273/* REPLACE START: _translate */
19274
19275            this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
19276
19277/* REPLACE END: _translate */
19278
19279        } else {
19280            x = Math.round(x);
19281            y = Math.round(y);
19282            this.scrollerStyle.left = x + 'px';
19283            this.scrollerStyle.top = y + 'px';
19284        }
19285
19286        this.x = x;
19287        this.y = y;
19288
19289
19290        if ( this.indicators ) {
19291            for ( var i = this.indicators.length; i--; ) {
19292                this.indicators[i].updatePosition();
19293            }
19294        }
19295
19296        //Uncode addition
19297        var uncodevent = new CustomEvent('fp-slide-scroll');
19298        window.dispatchEvent(uncodevent);
19299
19300// INSERT POINT: _translate
19301
19302    },
19303
19304    _initEvents: function (remove) {
19305        var eventType = remove ? utils.removeEvent : utils.addEvent,
19306            target = this.options.bindToWrapper ? this.wrapper : window;
19307
19308        eventType(window, 'orientationchange', this);
19309        eventType(window, 'resize', this);
19310
19311        if ( this.options.click ) {
19312            eventType(this.wrapper, 'click', this, true);
19313        }
19314
19315        if ( !this.options.disableMouse ) {
19316            eventType(this.wrapper, 'mousedown', this);
19317            eventType(target, 'mousemove', this);
19318            eventType(target, 'mousecancel', this);
19319            eventType(target, 'mouseup', this);
19320        }
19321
19322        if ( utils.hasPointer && !this.options.disablePointer ) {
19323            eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
19324            eventType(target, utils.prefixPointerEvent('pointermove'), this);
19325            eventType(target, utils.prefixPointerEvent('pointercancel'), this);
19326            eventType(target, utils.prefixPointerEvent('pointerup'), this);
19327        }
19328
19329        if ( utils.hasTouch && !this.options.disableTouch ) {
19330            eventType(this.wrapper, 'touchstart', this);
19331            eventType(target, 'touchmove', this);
19332            eventType(target, 'touchcancel', this);
19333            eventType(target, 'touchend', this);
19334        }
19335
19336        eventType(this.scroller, 'transitionend', this);
19337        eventType(this.scroller, 'webkitTransitionEnd', this);
19338        eventType(this.scroller, 'oTransitionEnd', this);
19339        eventType(this.scroller, 'MSTransitionEnd', this);
19340    },
19341
19342    getComputedPosition: function () {
19343        var matrix = window.getComputedStyle(this.scroller, null),
19344            x, y;
19345
19346        if ( this.options.useTransform ) {
19347            matrix = matrix[utils.style.transform].split(')')[0].split(', ');
19348            x = +(matrix[12] || matrix[4]);
19349            y = +(matrix[13] || matrix[5]);
19350        } else {
19351            x = +matrix.left.replace(/[^-\d.]/g, '');
19352            y = +matrix.top.replace(/[^-\d.]/g, '');
19353        }
19354
19355        return { x: x, y: y };
19356    },
19357    _initIndicators: function () {
19358        var interactive = this.options.interactiveScrollbars,
19359            customStyle = typeof this.options.scrollbars != 'string',
19360            indicators = [],
19361            indicator;
19362
19363        var that = this;
19364
19365        this.indicators = [];
19366
19367        if ( this.options.scrollbars ) {
19368            // Vertical scrollbar
19369            if ( this.options.scrollY ) {
19370                indicator = {
19371                    el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
19372                    interactive: interactive,
19373                    defaultScrollbars: true,
19374                    customStyle: customStyle,
19375                    resize: this.options.resizeScrollbars,
19376                    shrink: this.options.shrinkScrollbars,
19377                    fade: this.options.fadeScrollbars,
19378                    listenX: false
19379                };
19380
19381                this.wrapper.appendChild(indicator.el);
19382                indicators.push(indicator);
19383            }
19384
19385            // Horizontal scrollbar
19386            if ( this.options.scrollX ) {
19387                indicator = {
19388                    el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
19389                    interactive: interactive,
19390                    defaultScrollbars: true,
19391                    customStyle: customStyle,
19392                    resize: this.options.resizeScrollbars,
19393                    shrink: this.options.shrinkScrollbars,
19394                    fade: this.options.fadeScrollbars,
19395                    listenY: false
19396                };
19397
19398                this.wrapper.appendChild(indicator.el);
19399                indicators.push(indicator);
19400            }
19401        }
19402
19403        if ( this.options.indicators ) {
19404            // TODO: check concat compatibility
19405            indicators = indicators.concat(this.options.indicators);
19406        }
19407
19408        for ( var i = indicators.length; i--; ) {
19409            this.indicators.push( new Indicator(this, indicators[i]) );
19410        }
19411
19412        // TODO: check if we can use array.map (wide compatibility and performance issues)
19413        function _indicatorsMap (fn) {
19414            if (that.indicators) {
19415                for ( var i = that.indicators.length; i--; ) {
19416                    fn.call(that.indicators[i]);
19417                }
19418            }
19419        }
19420
19421        if ( this.options.fadeScrollbars ) {
19422            this.on('scrollEnd', function () {
19423                _indicatorsMap(function () {
19424                    this.fade();
19425                });
19426            });
19427
19428            this.on('scrollCancel', function () {
19429                _indicatorsMap(function () {
19430                    this.fade();
19431                });
19432            });
19433
19434            this.on('scrollStart', function () {
19435                _indicatorsMap(function () {
19436                    this.fade(1);
19437                });
19438            });
19439
19440            this.on('beforeScrollStart', function () {
19441                _indicatorsMap(function () {
19442                    this.fade(1, true);
19443                });
19444            });
19445        }
19446
19447
19448        this.on('refresh', function () {
19449            _indicatorsMap(function () {
19450                this.refresh();
19451            });
19452        });
19453
19454        this.on('destroy', function () {
19455            _indicatorsMap(function () {
19456                this.destroy();
19457            });
19458
19459            delete this.indicators;
19460        });
19461    },
19462
19463    _initWheel: function () {
19464        utils.addEvent(this.wrapper, 'wheel', this);
19465        utils.addEvent(this.wrapper, 'mousewheel', this);
19466        utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
19467
19468        this.on('destroy', function () {
19469            clearTimeout(this.wheelTimeout);
19470            this.wheelTimeout = null;
19471            utils.removeEvent(this.wrapper, 'wheel', this);
19472            utils.removeEvent(this.wrapper, 'mousewheel', this);
19473            utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
19474        });
19475    },
19476
19477    _wheel: function (e) {
19478        if ( !this.enabled ) {
19479            return;
19480        }
19481
19482        var wheelDeltaX, wheelDeltaY,
19483            newX, newY,
19484            that = this;
19485
19486        if ( this.wheelTimeout === undefined ) {
19487            that._execEvent('scrollStart');
19488        }
19489
19490        // Execute the scrollEnd event after 400ms the wheel stopped scrolling
19491        clearTimeout(this.wheelTimeout);
19492        this.wheelTimeout = setTimeout(function () {
19493            if(!that.options.snap) {
19494                that._execEvent('scrollEnd');
19495            }
19496            that.wheelTimeout = undefined;
19497        }, 400);
19498
19499        if ( 'deltaX' in e ) {
19500            if (e.deltaMode === 1) {
19501                wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
19502                wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
19503            } else {
19504                wheelDeltaX = -e.deltaX;
19505                wheelDeltaY = -e.deltaY;
19506            }
19507        } else if ( 'wheelDeltaX' in e ) {
19508            wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
19509            wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
19510        } else if ( 'wheelDelta' in e ) {
19511            wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
19512        } else if ( 'detail' in e ) {
19513            wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
19514        } else {
19515            return;
19516        }
19517
19518        wheelDeltaX *= this.options.invertWheelDirection;
19519        wheelDeltaY *= this.options.invertWheelDirection;
19520
19521        if ( !this.hasVerticalScroll ) {
19522            wheelDeltaX = wheelDeltaY;
19523            wheelDeltaY = 0;
19524        }
19525
19526        if ( this.options.snap ) {
19527            newX = this.currentPage.pageX;
19528            newY = this.currentPage.pageY;
19529
19530            if ( wheelDeltaX > 0 ) {
19531                newX--;
19532            } else if ( wheelDeltaX < 0 ) {
19533                newX++;
19534            }
19535
19536            if ( wheelDeltaY > 0 ) {
19537                newY--;
19538            } else if ( wheelDeltaY < 0 ) {
19539                newY++;
19540            }
19541
19542            this.goToPage(newX, newY);
19543
19544            return;
19545        }
19546
19547        newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
19548        newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
19549
19550        this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
19551        this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
19552
19553        if ( newX > 0 ) {
19554            newX = 0;
19555        } else if ( newX < this.maxScrollX ) {
19556            newX = this.maxScrollX;
19557        }
19558
19559        if ( newY > 0 ) {
19560            newY = 0;
19561        } else if ( newY < this.maxScrollY ) {
19562            newY = this.maxScrollY;
19563        }
19564
19565        this.scrollTo(newX, newY, 0);
19566
19567// INSERT POINT: _wheel
19568    },
19569
19570    _initSnap: function () {
19571        this.currentPage = {};
19572
19573        if ( typeof this.options.snap == 'string' ) {
19574            this.options.snap = this.scroller.querySelectorAll(this.options.snap);
19575        }
19576
19577        this.on('refresh', function () {
19578            var i = 0, l,
19579                m = 0, n,
19580                cx, cy,
19581                x = 0, y,
vendor: 7,339 bytes, lines 19582-19835
19582                stepX = this.options.snapStepX || this.wrapperWidth,
19583                stepY = this.options.snapStepY || this.wrapperHeight,
19584                el;
19585
19586            this.pages = [];
19587
19588            if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
19589                return;
19590            }
19591
19592            if ( this.options.snap === true ) {
19593                cx = Math.round( stepX / 2 );
19594                cy = Math.round( stepY / 2 );
19595
19596                while ( x > -this.scrollerWidth ) {
19597                    this.pages[i] = [];
19598                    l = 0;
19599                    y = 0;
19600
19601                    while ( y > -this.scrollerHeight ) {
19602                        this.pages[i][l] = {
19603                            x: Math.max(x, this.maxScrollX),
19604                            y: Math.max(y, this.maxScrollY),
19605                            width: stepX,
19606                            height: stepY,
19607                            cx: x - cx,
19608                            cy: y - cy
19609                        };
19610
19611                        y -= stepY;
19612                        l++;
19613                    }
19614
19615                    x -= stepX;
19616                    i++;
19617                }
19618            } else {
19619                el = this.options.snap;
19620                l = el.length;
19621                n = -1;
19622
19623                for ( ; i < l; i++ ) {
19624                    if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
19625                        m = 0;
19626                        n++;
19627                    }
19628
19629                    if ( !this.pages[m] ) {
19630                        this.pages[m] = [];
19631                    }
19632
19633                    x = Math.max(-el[i].offsetLeft, this.maxScrollX);
19634                    y = Math.max(-el[i].offsetTop, this.maxScrollY);
19635                    cx = x - Math.round(el[i].offsetWidth / 2);
19636                    cy = y - Math.round(el[i].offsetHeight / 2);
19637
19638                    this.pages[m][n] = {
19639                        x: x,
19640                        y: y,
19641                        width: el[i].offsetWidth,
19642                        height: el[i].offsetHeight,
19643                        cx: cx,
19644                        cy: cy
19645                    };
19646
19647                    if ( x > this.maxScrollX ) {
19648                        m++;
19649                    }
19650                }
19651            }
19652
19653            this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
19654
19655            // Update snap threshold if needed
19656            if ( this.options.snapThreshold % 1 === 0 ) {
19657                this.snapThresholdX = this.options.snapThreshold;
19658                this.snapThresholdY = this.options.snapThreshold;
19659            } else {
19660                this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
19661                this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
19662            }
19663        });
19664
19665        this.on('flick', function () {
19666            var time = this.options.snapSpeed || Math.max(
19667                    Math.max(
19668                        Math.min(Math.abs(this.x - this.startX), 1000),
19669                        Math.min(Math.abs(this.y - this.startY), 1000)
19670                    ), 300);
19671
19672            this.goToPage(
19673                this.currentPage.pageX + this.directionX,
19674                this.currentPage.pageY + this.directionY,
19675                time
19676            );
19677        });
19678    },
19679
19680    _nearestSnap: function (x, y) {
19681        if ( !this.pages.length ) {
19682            return { x: 0, y: 0, pageX: 0, pageY: 0 };
19683        }
19684
19685        var i = 0,
19686            l = this.pages.length,
19687            m = 0;
19688
19689        // Check if we exceeded the snap threshold
19690        if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
19691            Math.abs(y - this.absStartY) < this.snapThresholdY ) {
19692            return this.currentPage;
19693        }
19694
19695        if ( x > 0 ) {
19696            x = 0;
19697        } else if ( x < this.maxScrollX ) {
19698            x = this.maxScrollX;
19699        }
19700
19701        if ( y > 0 ) {
19702            y = 0;
19703        } else if ( y < this.maxScrollY ) {
19704            y = this.maxScrollY;
19705        }
19706
19707        for ( ; i < l; i++ ) {
19708            if ( x >= this.pages[i][0].cx ) {
19709                x = this.pages[i][0].x;
19710                break;
19711            }
19712        }
19713
19714        l = this.pages[i].length;
19715
19716        for ( ; m < l; m++ ) {
19717            if ( y >= this.pages[0][m].cy ) {
19718                y = this.pages[0][m].y;
19719                break;
19720            }
19721        }
19722
19723        if ( i == this.currentPage.pageX ) {
19724            i += this.directionX;
19725
19726            if ( i < 0 ) {
19727                i = 0;
19728            } else if ( i >= this.pages.length ) {
19729                i = this.pages.length - 1;
19730            }
19731
19732            x = this.pages[i][0].x;
19733        }
19734
19735        if ( m == this.currentPage.pageY ) {
19736            m += this.directionY;
19737
19738            if ( m < 0 ) {
19739                m = 0;
19740            } else if ( m >= this.pages[0].length ) {
19741                m = this.pages[0].length - 1;
19742            }
19743
19744            y = this.pages[0][m].y;
19745        }
19746
19747        return {
19748            x: x,
19749            y: y,
19750            pageX: i,
19751            pageY: m
19752        };
19753    },
19754
19755    goToPage: function (x, y, time, easing) {
19756        easing = easing || this.options.bounceEasing;
19757
19758        if ( x >= this.pages.length ) {
19759            x = this.pages.length - 1;
19760        } else if ( x < 0 ) {
19761            x = 0;
19762        }
19763
19764        if ( y >= this.pages[x].length ) {
19765            y = this.pages[x].length - 1;
19766        } else if ( y < 0 ) {
19767            y = 0;
19768        }
19769
19770        var posX = this.pages[x][y].x,
19771            posY = this.pages[x][y].y;
19772
19773        time = time === undefined ? this.options.snapSpeed || Math.max(
19774            Math.max(
19775                Math.min(Math.abs(posX - this.x), 1000),
19776                Math.min(Math.abs(posY - this.y), 1000)
19777            ), 300) : time;
19778
19779        this.currentPage = {
19780            x: posX,
19781            y: posY,
19782            pageX: x,
19783            pageY: y
19784        };
19785
19786        this.scrollTo(posX, posY, time, easing);
19787    },
19788
19789    next: function (time, easing) {
19790        var x = this.currentPage.pageX,
19791            y = this.currentPage.pageY;
19792
19793        x++;
19794
19795        if ( x >= this.pages.length && this.hasVerticalScroll ) {
19796            x = 0;
19797            y++;
19798        }
19799
19800        this.goToPage(x, y, time, easing);
19801    },
19802
19803    prev: function (time, easing) {
19804        var x = this.currentPage.pageX,
19805            y = this.currentPage.pageY;
19806
19807        x--;
19808
19809        if ( x < 0 && this.hasVerticalScroll ) {
19810            x = 0;
19811            y--;
19812        }
19813
19814        this.goToPage(x, y, time, easing);
19815    },
19816
19817    _initKeys: function (e) {
19818        // default key bindings
19819        var keys = {
19820            pageUp: 33,
19821            pageDown: 34,
19822            end: 35,
19823            home: 36,
19824            left: 37,
19825            up: 38,
19826            right: 39,
19827            down: 40
19828        };
19829        var i;
19830
19831        // if you give me characters I give you keycode
19832        if ( typeof this.options.keyBindings == 'object' ) {
19833            for ( i in this.options.keyBindings ) {
19834                if ( typeof this.options.keyBindings[i] == 'string' ) {
19835                    this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 19835-20188
19835deAt(0);
19836                }
19837            }
19838        } else {
19839            this.options.keyBindings = {};
19840        }
19841
19842        for ( i in keys ) {
19843            this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
19844        }
19845
19846        utils.addEvent(window, 'keydown', this);
19847
19848        this.on('destroy', function () {
19849            utils.removeEvent(window, 'keydown', this);
19850        });
19851    },
19852
19853    _key: function (e) {
19854        if ( !this.enabled ) {
19855            return;
19856        }
19857
19858        var snap = this.options.snap,   // we are using this alot, better to cache it
19859            newX = snap ? this.currentPage.pageX : this.x,
19860            newY = snap ? this.currentPage.pageY : this.y,
19861            now = utils.getTime(),
19862            prevTime = this.keyTime || 0,
19863            acceleration = 0.250,
19864            pos;
19865
19866        if ( this.options.useTransition && this.isInTransition ) {
19867            pos = this.getComputedPosition();
19868
19869            this._translate(Math.round(pos.x), Math.round(pos.y));
19870            this.isInTransition = false;
19871        }
19872
19873        this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
19874
19875        switch ( e.keyCode ) {
19876            case this.options.keyBindings.pageUp:
19877                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
19878                    newX += snap ? 1 : this.wrapperWidth;
19879                } else {
19880                    newY += snap ? 1 : this.wrapperHeight;
19881                }
19882                break;
19883            case this.options.keyBindings.pageDown:
19884                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
19885                    newX -= snap ? 1 : this.wrapperWidth;
19886                } else {
19887                    newY -= snap ? 1 : this.wrapperHeight;
19888                }
19889                break;
19890            case this.options.keyBindings.end:
19891                newX = snap ? this.pages.length-1 : this.maxScrollX;
19892                newY = snap ? this.pages[0].length-1 : this.maxScrollY;
19893                break;
19894            case this.options.keyBindings.home:
19895                newX = 0;
19896                newY = 0;
19897                break;
19898            case this.options.keyBindings.left:
19899                newX += snap ? -1 : 5 + this.keyAcceleration>>0;
19900                break;
19901            case this.options.keyBindings.up:
19902                newY += snap ? 1 : 5 + this.keyAcceleration>>0;
19903                break;
19904            case this.options.keyBindings.right:
19905                newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
19906                break;
19907            case this.options.keyBindings.down:
19908                newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
19909                break;
19910            default:
19911                return;
19912        }
19913
19914        if ( snap ) {
19915            this.goToPage(newX, newY);
19916            return;
19917        }
19918
19919        if ( newX > 0 ) {
19920            newX = 0;
19921            this.keyAcceleration = 0;
19922        } else if ( newX < this.maxScrollX ) {
19923            newX = this.maxScrollX;
19924            this.keyAcceleration = 0;
19925        }
19926
19927        if ( newY > 0 ) {
19928            newY = 0;
19929            this.keyAcceleration = 0;
19930        } else if ( newY < this.maxScrollY ) {
19931            newY = this.maxScrollY;
19932            this.keyAcceleration = 0;
19933        }
19934
19935        this.scrollTo(newX, newY, 0);
19936
19937        this.keyTime = now;
19938    },
19939
19940    _animate: function (destX, destY, duration, easingFn) {
19941        var that = this,
19942            startX = this.x,
19943            startY = this.y,
19944            startTime = utils.getTime(),
19945            destTime = startTime + duration;
19946
19947        function step () {
19948            var now = utils.getTime(),
19949                newX, newY,
19950                easing;
19951
19952            if ( now >= destTime ) {
19953                that.isAnimating = false;
19954                that._translate(destX, destY);
19955
19956                if ( !that.resetPosition(that.options.bounceTime) ) {
19957                    that._execEvent('scrollEnd');
19958                }
19959
19960                return;
19961            }
19962
19963            now = ( now - startTime ) / duration;
19964            easing = easingFn(now);
19965            newX = ( destX - startX ) * easing + startX;
19966            newY = ( destY - startY ) * easing + startY;
19967            that._translate(newX, newY);
19968
19969            if ( that.isAnimating ) {
19970                rAF(step);
19971            }
19972        }
19973
19974        this.isAnimating = true;
19975        step();
19976    },
19977    handleEvent: function (e) {
19978        switch ( e.type ) {
19979            case 'touchstart':
19980            case 'pointerdown':
19981            case 'MSPointerDown':
19982            case 'mousedown':
19983                this._start(e);
19984                break;
19985            case 'touchmove':
19986            case 'pointermove':
19987            case 'MSPointerMove':
19988            case 'mousemove':
19989                this._move(e);
19990                break;
19991            case 'touchend':
19992            case 'pointerup':
19993            case 'MSPointerUp':
19994            case 'mouseup':
19995            case 'touchcancel':
19996            case 'pointercancel':
19997            case 'MSPointerCancel':
19998            case 'mousecancel':
19999                this._end(e);
20000                break;
20001            case 'orientationchange':
20002            case 'resize':
20003                this._resize();
20004                break;
20005            case 'transitionend':
20006            case 'webkitTransitionEnd':
20007            case 'oTransitionEnd':
20008            case 'MSTransitionEnd':
20009                this._transitionEnd(e);
20010                break;
20011            case 'wheel':
20012            case 'DOMMouseScroll':
20013            case 'mousewheel':
20014                this._wheel(e);
20015                break;
20016            case 'keydown':
20017                this._key(e);
20018                break;
20019            case 'click':
20020                if ( this.enabled && !e._constructed ) {
20021                    e.preventDefault();
20022                    e.stopPropagation();
20023                }
20024                break;
20025        }
20026    }
20027};
20028function createDefaultScrollbar (direction, interactive, type) {
20029    var scrollbar = document.createElement('div'),
20030        indicator = document.createElement('div');
20031
20032    if ( type === true ) {
20033        scrollbar.style.cssText = 'position:absolute;z-index:9999';
20034        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';
20035    }
20036
20037    indicator.className = 'iScrollIndicator';
20038
20039    if ( direction == 'h' ) {
20040        if ( type === true ) {
20041            scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
20042            indicator.style.height = '100%';
20043        }
20044        scrollbar.className = 'iScrollHorizontalScrollbar';
20045    } else {
20046        if ( type === true ) {
20047            scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
20048            indicator.style.width = '100%';
20049        }
20050        scrollbar.className = 'iScrollVerticalScrollbar';
20051    }
20052
20053    scrollbar.style.cssText += ';overflow:hidden';
20054
20055    if ( !interactive ) {
20056        scrollbar.style.pointerEvents = 'none';
20057    }
20058
20059    scrollbar.appendChild(indicator);
20060
20061    return scrollbar;
20062}
20063
20064function Indicator (scroller, options) {
20065    this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
20066    this.wrapperStyle = this.wrapper.style;
20067    this.indicator = this.wrapper.children[0];
20068    this.indicatorStyle = this.indicator.style;
20069    this.scroller = scroller;
20070
20071    this.options = {
20072        listenX: true,
20073        listenY: true,
20074        interactive: false,
20075        resize: true,
20076        defaultScrollbars: false,
20077        shrink: false,
20078        fade: false,
20079        speedRatioX: 0,
20080        speedRatioY: 0
20081    };
20082
20083    for ( var i in options ) {
20084        this.options[i] = options[i];
20085    }
20086
20087    this.sizeRatioX = 1;
20088    this.sizeRatioY = 1;
20089    this.maxPosX = 0;
20090    this.maxPosY = 0;
20091
20092    if ( this.options.interactive ) {
20093        if ( !this.options.disableTouch ) {
20094            utils.addEvent(this.indicator, 'touchstart', this);
20095            utils.addEvent(window, 'touchend', this);
20096        }
20097        if ( !this.options.disablePointer ) {
20098            utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
20099            utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
20100        }
20101        if ( !this.options.disableMouse ) {
20102            utils.addEvent(this.indicator, 'mousedown', this);
20103            utils.addEvent(window, 'mouseup', this);
20104        }
20105    }
20106
20107    if ( this.options.fade ) {
20108        this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
20109        var durationProp = utils.style.transitionDuration;
20110        if(!durationProp) {
20111            return;
20112        }
20113        this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
20114        // remove 0.0001ms
20115        var self = this;
20116        if(utils.isBadAndroid) {
20117            rAF(function() {
20118                if(self.wrapperStyle[durationProp] === '0.0001ms') {
20119                    self.wrapperStyle[durationProp] = '0s';
20120                }
20121            });
20122        }
20123        this.wrapperStyle.opacity = '0';
20124    }
20125}
20126
20127Indicator.prototype = {
20128    handleEvent: function (e) {
20129        switch ( e.type ) {
20130            case 'touchstart':
20131            case 'pointerdown':
20132            case 'MSPointerDown':
20133            case 'mousedown':
20134                this._start(e);
20135                break;
20136            case 'touchmove':
20137            case 'pointermove':
20138            case 'MSPointerMove':
20139            case 'mousemove':
20140                this._move(e);
20141                break;
20142            case 'touchend':
20143            case 'pointerup':
20144            case 'MSPointerUp':
20145            case 'mouseup':
20146            case 'touchcancel':
20147            case 'pointercancel':
20148            case 'MSPointerCancel':
20149            case 'mousecancel':
20150                this._end(e);
20151                break;
20152        }
20153    },
20154
20155    destroy: function () {
20156        if ( this.options.fadeScrollbars ) {
20157            clearTimeout(this.fadeTimeout);
20158            this.fadeTimeout = null;
20159        }
20160        if ( this.options.interactive ) {
20161            utils.removeEvent(this.indicator, 'touchstart', this);
20162            utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
20163            utils.removeEvent(this.indicator, 'mousedown', this);
20164
20165            utils.removeEvent(window, 'touchmove', this);
20166            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
20167            utils.removeEvent(window, 'mousemove', this);
20168
20169            utils.removeEvent(window, 'touchend', this);
20170            utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
20171            utils.removeEvent(window, 'mouseup', this);
20172        }
20173
20174        if ( this.options.defaultScrollbars ) {
20175            this.wrapper.parentNode.removeChild(this.wrapper);
20176        }
20177    },
20178
20179    _start: function (e) {
20180        var point = e.touches ? e.touches[0] : e;
20181
20182        e.preventDefault();
20183        e.stopPropagation();
20184
20185        this.transitionTime();
20186
20187        this.initiated = true;
20188        this.moved = false;
vendor: 9,615 bytes, lines 20189-20447
20189        this.lastPointX = point.pageX;
20190        this.lastPointY = point.pageY;
20191
20192        this.startTime  = utils.getTime();
20193
20194        if ( !this.options.disableTouch ) {
20195            utils.addEvent(window, 'touchmove', this);
20196        }
20197        if ( !this.options.disablePointer ) {
20198            utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
20199        }
20200        if ( !this.options.disableMouse ) {
20201            utils.addEvent(window, 'mousemove', this);
20202        }
20203
20204        this.scroller._execEvent('beforeScrollStart');
20205    },
20206
20207    _move: function (e) {
20208        var point = e.touches ? e.touches[0] : e,
20209            deltaX, deltaY,
20210            newX, newY,
20211            timestamp = utils.getTime();
20212
20213        if ( !this.moved ) {
20214            this.scroller._execEvent('scrollStart');
20215        }
20216
20217        this.moved = true;
20218
20219        deltaX = point.pageX - this.lastPointX;
20220        this.lastPointX = point.pageX;
20221
20222        deltaY = point.pageY - this.lastPointY;
20223        this.lastPointY = point.pageY;
20224
20225        newX = this.x + deltaX;
20226        newY = this.y + deltaY;
20227
20228        this._pos(newX, newY);
20229
20230// INSERT POINT: indicator._move
20231
20232        e.preventDefault();
20233        e.stopPropagation();
20234    },
20235
20236    _end: function (e) {
20237        if ( !this.initiated ) {
20238            return;
20239        }
20240
20241        this.initiated = false;
20242
20243        e.preventDefault();
20244        e.stopPropagation();
20245
20246        utils.removeEvent(window, 'touchmove', this);
20247        utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
20248        utils.removeEvent(window, 'mousemove', this);
20249
20250        if ( this.scroller.options.snap ) {
20251            var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
20252
20253            var time = this.options.snapSpeed || Math.max(
20254                    Math.max(
20255                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
20256                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
20257                    ), 300);
20258
20259            if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
20260                this.scroller.directionX = 0;
20261                this.scroller.directionY = 0;
20262                this.scroller.currentPage = snap;
20263                this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
20264            }
20265        }
20266
20267        if ( this.moved ) {
20268            this.scroller._execEvent('scrollEnd');
20269        }
20270    },
20271
20272    transitionTime: function (time) {
20273        time = time || 0;
20274        var durationProp = utils.style.transitionDuration;
20275        if(!durationProp) {
20276            return;
20277        }
20278
20279        this.indicatorStyle[durationProp] = time + 'ms';
20280
20281        if ( !time && utils.isBadAndroid ) {
20282            this.indicatorStyle[durationProp] = '0.0001ms';
20283            // remove 0.0001ms
20284            var self = this;
20285            rAF(function() {
20286                if(self.indicatorStyle[durationProp] === '0.0001ms') {
20287                    self.indicatorStyle[durationProp] = '0s';
20288                }
20289            });
20290        }
20291    },
20292
20293    transitionTimingFunction: function (easing) {
20294        this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
20295    },
20296
20297    refresh: function () {
20298        this.transitionTime();
20299
20300        if ( this.options.listenX && !this.options.listenY ) {
20301            this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
20302        } else if ( this.options.listenY && !this.options.listenX ) {
20303            this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
20304        } else {
20305            this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
20306        }
20307
20308        if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
20309            utils.addClass(this.wrapper, 'iScrollBothScrollbars');
20310            utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
20311
20312            if ( this.options.defaultScrollbars && this.options.customStyle ) {
20313                if ( this.options.listenX ) {
20314                    this.wrapper.style.right = '8px';
20315                } else {
20316                    this.wrapper.style.bottom = '8px';
20317                }
20318            }
20319        } else {
20320            utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
20321            utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
20322
20323            if ( this.options.defaultScrollbars && this.options.customStyle ) {
20324                if ( this.options.listenX ) {
20325                    this.wrapper.style.right = '2px';
20326                } else {
20327                    this.wrapper.style.bottom = '2px';
20328                }
20329            }
20330        }
20331
20332        var r = this.wrapper.offsetHeight;  // force refresh
20333
20334        if ( this.options.listenX ) {
20335            this.wrapperWidth = this.wrapper.clientWidth;
20336            if ( this.options.resize ) {
20337                this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
20338                this.indicatorStyle.width = this.indicatorWidth + 'px';
20339            } else {
20340                this.indicatorWidth = this.indicator.clientWidth;
20341            }
20342
20343            this.maxPosX = this.wrapperWidth - this.indicatorWidth;
20344
20345            if ( this.options.shrink == 'clip' ) {
20346                this.minBoundaryX = -this.indicatorWidth + 8;
20347                this.maxBoundaryX = this.wrapperWidth - 8;
20348            } else {
20349                this.minBoundaryX = 0;
20350                this.maxBoundaryX = this.maxPosX;
20351            }
20352
20353            this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
20354        }
20355
20356        if ( this.options.listenY ) {
20357            this.wrapperHeight = this.wrapper.clientHeight;
20358            if ( this.options.resize ) {
20359                this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
20360                this.indicatorStyle.height = this.indicatorHeight + 'px';
20361            } else {
20362                this.indicatorHeight = this.indicator.clientHeight;
20363            }
20364
20365            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
20366
20367            if ( this.options.shrink == 'clip' ) {
20368                this.minBoundaryY = -this.indicatorHeight + 8;
20369                this.maxBoundaryY = this.wrapperHeight - 8;
20370            } else {
20371                this.minBoundaryY = 0;
20372                this.maxBoundaryY = this.maxPosY;
20373            }
20374
20375            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
20376            this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
20377        }
20378
20379        this.updatePosition();
20380    },
20381
20382    updatePosition: function () {
20383        var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
20384            y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
20385
20386        if ( !this.options.ignoreBoundaries ) {
20387            if ( x < this.minBoundaryX ) {
20388                if ( this.options.shrink == 'scale' ) {
20389                    this.width = Math.max(this.indicatorWidth + x, 8);
20390                    this.indicatorStyle.width = this.width + 'px';
20391                }
20392                x = this.minBoundaryX;
20393            } else if ( x > this.maxBoundaryX ) {
20394                if ( this.options.shrink == 'scale' ) {
20395                    this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
20396                    this.indicatorStyle.width = this.width + 'px';
20397                    x = this.maxPosX + this.indicatorWidth - this.width;
20398                } else {
20399                    x = this.maxBoundaryX;
20400                }
20401            } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
20402                this.width = this.indicatorWidth;
20403                this.indicatorStyle.width = this.width + 'px';
20404            }
20405
20406            if ( y < this.minBoundaryY ) {
20407                if ( this.options.shrink == 'scale' ) {
20408                    this.height = Math.max(this.indicatorHeight + y * 3, 8);
20409                    this.indicatorStyle.height = this.height + 'px';
20410                }
20411                y = this.minBoundaryY;
20412            } else if ( y > this.maxBoundaryY ) {
20413                if ( this.options.shrink == 'scale' ) {
20414                    this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
20415                    this.indicatorStyle.height = this.height + 'px';
20416                    y = this.maxPosY + this.indicatorHeight - this.height;
20417                } else {
20418                    y = this.maxBoundaryY;
20419                }
20420            } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
20421                this.height = this.indicatorHeight;
20422                this.indicatorStyle.height = this.height + 'px';
20423            }
20424        }
20425
20426        this.x = x;
20427        this.y = y;
20428
20429        if ( this.scroller.options.useTransform ) {
20430            this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
20431        } else {
20432            this.indicatorStyle.left = x + 'px';
20433            this.indicatorStyle.top = y + 'px';
20434        }
20435    },
20436
20437    _pos: function (x, y) {
20438        if ( x < 0 ) {
20439            x = 0;
20440        } else if ( x > this.maxPosX ) {
20441            x = this.maxPosX;
20442        }
20443
20444        if ( y < 0 ) {
20445            y = 0;
20446        } else if ( y > this.maxPosY ) {
20447            y = this.maxPosY;
20448        }
20449
20450        x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
20451        y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
20452
20453        this.scroller.scrollTo(x, y);
20454    },
20455
20456    fade: function (val, hold) {
20457        if ( hold && !this.visible ) {
20458            return;
20459        }
20460
20461        clearTimeout(this.fadeTimeout);
20462        this.fadeTimeout = null;
20463
20464        var time = val ? 250 : 500,
20465            delay = val ? 0 : 300;
20466
20467        val = val ? '1' : '0';
20468
20469        this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
20470
20471        this.fadeTimeout = setTimeout((function (val) {
20472            this.wrapperStyle.opacity = val;
20473            this.visible = +val;
20474        }).bind(this, val), delay);
20475    }
20476};
20477
20478IScroll.utils = utils;
20479
20480if ( typeof module != 'undefined' && module.exports ) {
20481    module.exports = IScroll;
20482} else if ( typeof define == 'function' && define.amd ) {
20483        define( function () { return IScroll; } );
20484} else {
20485    window.IScroll = IScroll;
20486}
20487
20488})(window, document, Math);
20489/*!
20490 * fullPage 2.9.4
20491 * https://github.com/alvarotrigo/fullPage.js
20492 * @license MIT licensed
20493 *
20494 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
20495 */
20496(function(global, factory) {
20497    'use strict';
20498    if (typeof define === 'function' && define.amd) {
20499        define(['jquery'], function($) {
20500          return factory($, global, global.document, global.Math);
20501        });
20502    } else if (typeof exports === "object" && exports) {
20503        module.exports = factory(require('jquery'), global, global.document, global.Math);
20504    } else {
20505        factory(jQuery, global, global.document, global.Math);
20506    }
20507})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
20508    'use strict';
20509
20510    // keeping central set of classnames and selectors
20511    var WRAPPER =               'fullpage-wrapper';
20512    var WRAPPER_SEL =           '.' + WRAPPER;
20513
20514    // slimscroll
20515    var SCROLLABLE =            'fp-scrollable';
20516    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
20517
20518    // util
20519    var RESPONSIVE =            'fp-responsive';
20520    var NO_TRANSITION =         'fp-notransition';
20521    var DESTROYED =             'fp-destroyed';
20522    var ENABLED =               'fp-enabled';
20523    var VIEWING_PREFIX =        'fp-viewing';
20524    var ACTIVE =                'active';
20525    var ACTIVE_SEL =            '.' + ACTIVE;
20526    var COMPLETELY =            'fp-completely';
20527    var COMPLETELY_SEL =        '.' + COMPLETELY;
20528
20529    // section
20530    var SECTION_DEFAULT_SEL =   '.section';
20531    var SECTION =               'fp-section';
20532    var SECTION_SEL =           '.' + SECTION;
20533    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
20534    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
20535    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
20536    var TABLE_CELL =            'fp-tableCell';
20537    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
20538    var AUTO_HEIGHT =           'fp-auto-height';
20539    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
20540    var NORMAL_SCROLL =         'fp-normal-scroll';
20541    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
20542
20543    // section nav
20544    var SECTION_NAV =           'fp-nav';
20545    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
20546    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
20547    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
20548    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
20549
20550    // slide
20551    var SLIDE_DEFAULT_SEL =     '.slide';
20552    var SLIDE =                 'fp-slide';
20553    var SLIDE_SEL =             '.' + SLIDE;
20554    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
20555    var SLIDES_WRAPPER =        'fp-slides';
20556    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
20557    var SLIDES_CONTAINER =      'fp-slidesContainer';
20558    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
20559    var TABLE =                 'fp-table';
20560
20561    // slide nav
20562    var SLIDES_NAV =            'fp-slidesNav';
20563    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
20564    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
20565    var SLIDES_ARROW =          'fp-controlArrow';
20566    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
20567    var SLIDES_PREV =           'fp-prev';
20568    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
20569    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
20570    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
20571    var SLIDES_NEXT =           'fp-next';
20572    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
20573    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
20574    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
20575
20576    var $window = $(window);
20577    var $document = $(document);
20578
20579    // Default options for iScroll.js used when using scrollOverflow
20580    var iscrollOptions = {
20581        scrollbars: true,
20582        mouseWheel: true,
20583        hideScrollbars: false,
20584        fadeScrollbars: false,
20585        disableMouse: true,
20586        interactiveScrollbars: true,
20587        bounce: false,
20588    };
20589
20590    $.fn.fullpage = function(options) {
20591        //only once my friend!
20592        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
20593
20594        // common jQuery objects
20595        var $htmlBody = $('html, body');
20596        var $body = $('body');
20597
20598        var FP = $.fn.fullpage;
20599
20600        // Creating some defaults, extending them with any options that were provided
20601        options = $.extend({
20602            //navigation
20603            menu: false,
20604            anchors:[],
20605            lockAnchors: false,
20606            navigation: false,
20607            navigationPosition: 'right',
20608            navigationTooltips: [],
20609            showActiveTooltip: false,
20610            slidesNavigation: false,
20611            slidesNavPosition: 'bottom',
20612            scrollBar: false,
20613            hybrid: false,
20614
20615            //scrolling
20616            css3: true,
20617            scrollingSpeed: 700,
20618            autoScrolling: true,
20619            fitToSection: true,
20620            fitToSectionDelay: 1000,
20621            easing: 'easeInOutCubic',
20622            easingcss3: 'ease',
20623            loopBottom: false,
20624            loopTop: false,
20625            loopHorizontal: true,
20626            continuousVertical: false,
20627            continuousHorizontal: false,
20628            scrollHorizontally: false,
20629            interlockedSlides: false,
20630            dragAndMove: false,
20631            offsetSections: false,
20632            resetSliders: false,
20633            fadingEffect: false,
20634            normalScrollElements: null,
20635            scrollOverflow: false,
20636            scrollOverflowReset: false,
20637            scrollOverflowHandler: iscrollHandler,
20638            scrollOverflowOptions: null,
20639            touchSensitivity: 5,
20640            normalScrollElementTouchThreshold: 5,
20641            bigSectionsDestination: null,
20642
20643            //Accessibility
20644            keyboardScrolling: true,
20645            animateAnchor: true,
20646            recordHistory: true,
20647
20648            //design
20649            controlArrows: true,
20650            controlArrowColor: '#fff',
20651            verticalCentered: true,
20652            sectionsColor : [],
20653            paddingTop: 0,
20654            paddingBottom: 0,
20655            fixedElements: null,
20656            responsive: 0, //backwards compabitility with responsiveWiddth
20657            responsiveWidth: 0,
20658            responsiveHeight: 0,
20659            responsiveSlides: false,
20660            parallax: false,
20661            parallaxOptions: {
20662                type: 'reveal',
20663                percentage: 62,
20664                property: 'translate'
20665            },
20666
20667            //Custom selectors
20668            sectionSelector: SECTION_DEFAULT_SEL,
20669            slideSelector: SLIDE_DEFAULT_SEL,
20670
20671            //events
20672            afterLoad: null,
20673            onLeave: null,
20674            afterRender: null,
20675            afterResize: null,
20676            afterReBuild: null,
20677            afterSlideLoad: null,
20678            onSlideLeave: null,
20679            afterResponsive: null,
20680
20681            lazyLoading: true
20682        }, options);
20683
20684        //flag to avoid very fast sliding for landscape sliders
20685        var slideMoving = false;
20686
20687        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
20688        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
20689        var container = $(this);
20690        var windowsHeight = $window.height();
20691        var isResizing = false;
20692        var isWindowFocused = true;
20693        var lastScrolledDestiny;
20694        var lastScrolledSlide;
20695        var canScroll = true;
20696        var scrollings = [];
20697        var controlPressed;
20698        var startingSection;
20699        var isScrollAllowed = {};
20700        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
20701        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
20702        var MSPointer = getMSPointer();
20703        var events = {
20704            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
20705            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
20706        };
20707
20708        //cheks for passive event support
20709        //added by Uncode from new fullPage updates
20710        var g_supportsPassive = false;
20711        try {
20712          var opts = Object.defineProperty({}, 'passive', {
20713            get: function() {
20714              g_supportsPassive = true;
20715            }
20716          });
20717          window.addEventListener("testPassive", null, opts);
20718          window.removeEventListener("testPassive", null, opts);
20719        } catch (e) {}
20720
20721        //timeouts
20722        var resizeId;
20723        var afterSectionLoadsId;
20724        var afterSlideLoadsId;
20725        var scrollId;
20726        var scrollId2;
20727        var keydownId;
20728        var originals = $.extend(true, {}, options); //deep copy
20729
20730        //Uncode addition
20731        var $masthead = $('#masthead');
20732        var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
20733        var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
20734        var bodyBorder = UNCODE.bodyBorder;
20735        var adminBarHeight = UNCODE.adminBarHeight;
20736
20737        displayWarnings();
20738
20739        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
20740        iscrollOptions.click = isTouch; // see #2035
20741
20742        //extending iScroll options with the user custom ones
20743        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
20744
20745        //easeInOutCubic animation included in the plugin
20746        $.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;}});
20747
20748        /**
20749        * Sets the autoScroll option.
20750        * It changes the scroll bar visibility and the history of the site as a result.
20751        */
20752        function setAutoScrolling(value, type){
20753            //removing the transformation
20754            if(!value){
20755                silentScroll(0);
20756            }
20757
20758            setVariableState('autoScrolling', value, type);
20759
20760            var element = $(SECTION_ACTIVE_SEL);
20761
20762            if(options.autoScrolling && !options.scrollBar){
20763                $htmlBody.css({
20764                    'overflow' : 'hidden !important',
20765                    'height' : '100%'
20766                });
20767
20768                //Uncode addition
20769                //setRecordHistory(originals.recordHistory, 'internal');
20770
20771                //for IE touch devices
20772                container.css({
20773                    '-ms-touch-action': 'none',
20774                    'touch-action': 'none'
20775                });
20776
20777                if(element.length){
20778                    //moving the container up
20779                    silentScroll(element.position().top);
20780                }
20781
20782            }else{
20783                $htmlBody.css({
20784                    'overflow' : 'visible !important',
20785                    'height' : 'initial'
20786                });
20787
20788                //Uncode addition
20789                //setRecordHistory(false, 'internal');
20790
20791                //for IE touch devices
20792                container.css({
20793                    '-ms-touch-action': '',
20794                    'touch-action': ''
20795                });
20796
20797                //scrolling the page to the section with no animation
20798                if (element.length) {
20799                    $htmlBody.scrollTop(element.position().top);
20800                }
20801            }
20802        }
20803
20804        /**
20805        * Defines wheter to record the history for each hash change in the URL.
20806        */
20807        function setRecordHistory(value, type){
20808            setVariableState('recordHistory', value, type);
20809        }
20810
20811        /**
20812        * Defines the scrolling speed
20813        */
20814        function setScrollingSpeed(value, type){
20815            setVariableState('scrollingSpeed', value, type);
20816        }
20817
20818        /**
20819        * Sets fitToSection
20820        */
20821        function setFitToSection(value, type){
20822            setVariableState('fitToSection', value, type);
20823        }
20824
20825        /**
20826        * Sets lockAnchors
20827        */
20828        function setLockAnchors(value){
20829            options.lockAnchors = value;
20830        }
20831
20832        /**
20833        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
20834        */
20835        function setMouseWheelScrolling(value){
20836            if(value){
20837                addMouseWheelHandler();
20838                addMiddleWheelHandler();
20839            }else{
20840                removeMouseWheelHandler();
20841                removeMiddleWheelHandler();
20842            }
20843        }
20844
20845        /**
20846        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
20847        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
20848        *
20849        * @param directions string containing the direction or directions separated by comma.
20850        */
20851        function setAllowScrolling(value, directions){
20852            if(typeof directions !== 'undefined'){
20853                directions = directions.replace(/ /g,'').split(',');
20854
20855                $.each(directions, function (index, direction){
20856                    setIsScrollAllowed(value, direction, 'm');
20857                });
20858            }
20859            else if(value){
20860                setMouseWheelScrolling(true);
20861                addTouchHandler();
20862            }else{
20863                setMouseWheelScrolling(false);
20864                removeTouchHandler();
20865            }
20866        }
20867
20868        /**
20869        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
20870        */
20871        function setKeyboardScrolling(value, directions){
20872            if(typeof directions !== 'undefined'){
20873                directions = directions.replace(/ /g,'').split(',');
20874
20875                $.each(directions, function (index, direction){
20876                    setIsScrollAllowed(value, direction, 'k');
20877                });
20878            }else{
20879                options.keyboardScrolling = value;
20880            }
20881        }
20882
20883        /**
20884        * Moves the page up one section.
20885        */
20886        function moveSectionUp(){
20887            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
20888
20889            //looping to the bottom if there's no more sections above
20890            if (!prev.length && (options.loopTop || options.continuousVertical)) {
20891                prev = $(SECTION_SEL).last();
20892            }
20893
20894            if (prev.length) {
20895                scrollPage(prev, null, true);
20896            }
20897        }
20898
20899        /**
20900        * Moves the page down one section.
20901        */
20902        function moveSectionDown(){
20903            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
20904
20905            //looping to the top if there's no more sections below
20906            if(!next.length &&
20907                (options.loopBottom || options.continuousVertical)){
20908                next = $(SECTION_SEL).first();
20909            }
20910
20911            if(next.length){
20912                scrollPage(next, null, false);
20913            }
20914        }
20915
20916        /**
20917        * Moves the page to the given section and slide with no animation.
20918        * Anchors or index positions can be used as params.
20919        */
20920        function silentMoveTo(sectionAnchor, slideAnchor){
20921            setScrollingSpeed (0, 'internal');
20922            moveTo(sectionAnchor, slideAnchor);
20923            setScrollingSpeed (originals.scrollingSpeed, 'internal');
20924        }
20925
20926        /**
20927        * Moves the page to the given section and slide.
20928        * Anchors or index positions can be used as params.
20929        */
20930        function moveTo(sectionAnchor, slideAnchor){
20931            var destiny = getSectionByAnchor(sectionAnchor);
20932
20933            if (typeof slideAnchor !== 'undefined'){
20934                scrollPageAndSlide(sectionAnchor, slideAnchor);
20935            }else if(destiny.length > 0){
20936                scrollPage(destiny);
20937            }
20938        }
20939
20940        /**
20941        * Slides right the slider of the active section.
20942        * Optional `section` param.
20943        */
20944        function moveSlideRight(section){
20945            moveSlide('right', section);
20946        }
20947
20948        /**
20949        * Slides left the slider of the active section.
20950        * Optional `section` param.
20951        */
20952        function moveSlideLeft(section){
20953            moveSlide('left', section);
20954        }
20955
20956        /**
20957         * When resizing is finished, we adjust the slides sizes and positions
20958         */
20959        function reBuild(resizing){
20960            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
20961
20962            isResizing = true;
20963
20964            windowsHeight = $window.height();  //updating global var
20965
20966            $(SECTION_SEL).each(function(){
20967                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
20968                var slides = $(this).find(SLIDE_SEL);
20969
20970                //adjusting the height of the table-cell for IE and Firefox
20971                if(options.verticalCentered){
20972                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
20973                }
20974
20975                $(this).css('height', windowsHeight + 'px');
20976
20977                //resizing the scrolling divs
20978                if(options.scrollOverflow){
20979                    if(slides.length){
20980                        slides.each(function(){
20981                            createScrollBar($(this));
20982                        });
20983                    }else{
20984                        createScrollBar($(this));
20985                    }
20986                }
20987
20988                //adjusting the position fo the FULL WIDTH slides...
20989                if (slides.length > 1) {
20990                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
20991                }
20992            });
20993
20994            var activeSection = $(SECTION_ACTIVE_SEL);
20995            var sectionIndex = activeSection.index(SECTION_SEL);
20996
20997            //isn't it the first section?
20998            if(sectionIndex){
20999                //adjusting the position for the current section
21000                silentMoveTo(sectionIndex + 1);
21001            }
21002
21003            isResizing = false;
21004            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
21005            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
21006        }
21007
21008        /**
21009        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
21010        * are smaller than the set limit values.
21011        */
21012        function setResponsive(active){
21013            var isResponsive = $body.hasClass(RESPONSIVE);
21014
21015            if(active){
21016                if(!isResponsive){
21017                    setAutoScrolling(false, 'internal');
21018                    setFitToSection(false, 'internal');
21019                    $(SECTION_NAV_SEL).hide();
21020                    $body.addClass(RESPONSIVE);
21021                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
21022                }
21023            }
21024            else if(isResponsive){
21025                setAutoScrolling(originals.autoScrolling, 'internal');
21026                setFitToSection(originals.autoScrolling, 'internal');
21027                $(SECTION_NAV_SEL).show();
21028                $body.removeClass(RESPONSIVE);
21029                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
21030            }
21031        }
21032
21033        if($(this).length){
21034            //public functions
21035            FP.setAutoScrolling = setAutoScrolling;
21036            FP.setRecordHistory = setRecordHistory;
21037            FP.setScrollingSpeed = setScrollingSpeed;
21038            FP.setFitToSection = setFitToSection;
21039            FP.setLockAnchors = setLockAnchors;
21040            FP.setMouseWheelScrolling = setMouseWheelScrolling;
21041            FP.setAllowScrolling = setAllowScrolling;
21042            FP.setKeyboardScrolling = setKeyboardScrolling;
21043            FP.moveSectionUp = moveSectionUp;
21044            FP.moveSectionDown = moveSectionDown;
21045            FP.silentMoveTo = silentMoveTo;
21046            FP.moveTo = moveTo;
21047            FP.moveSlideRight = moveSlideRight;
21048            FP.moveSlideLeft = moveSlideLeft;
21049            FP.fitToSection = fitToSection;
21050            FP.reBuild = reBuild;
21051            FP.setResponsive = setResponsive;
21052            FP.destroy = destroy;
21053
21054            init();
21055
21056            bindEvents();
21057        }
21058
21059        function init(){
21060            //if css3 is not supported, it will use jQuery animations
21061            if(options.css3){
21062                options.css3 = support3d();
21063            }
21064
21065            options.scrollBar = options.scrollBar || options.hybrid;
21066
21067            setOptionsFromDOM();
21068            prepareDom();
21069            setAllowScrolling(true);
21070            setAutoScrolling(options.autoScrolling, 'internal');
21071            responsive();
21072
21073            //setting the class for the body element
21074            setBodyClass();
21075
21076            //Uncode addition
21077            // if(document.readyState === 'complete'){
21078            //     scrollToAnchor();
21079            // }
21080            // $window.on('load', scrollToAnchor);
21081        }
21082
21083        function bindEvents(){
21084            $window
21085                //when scrolling...
21086                //.on('scroll', scrollHandler)
21087
21088                //detecting any change on the URL to scroll to the given anchor link
21089                //(a way to detect back history button as we play with the hashes on the URL)
21090                .on('hashchange', hashChangeHandler)
21091
21092                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
21093                .blur(blurHandler)
21094
21095                //when resizing the site, we adjust the heights of the sections, slimScroll...
21096                .resize(resizeHandler);
21097
21098            $document
21099                //Sliding with arrow keys, both, vertical and horizontal
21100                .keydown(keydownHandler)
21101
21102                //to prevent scrolling while zooming
21103                .keyup(keyUpHandler)
21104
21105                //Scrolls to the section when clicking the navigation bullet
21106                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
21107
21108                //Scrolls the slider to the given slide destination for the given section
21109                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
21110
21111                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
21112
21113            //Scrolling horizontally when clicking on the slider controls.
21114            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
21115
21116            /**
21117            * Applying normalScroll elements.
21118            * Ignoring the scrolls over the specified selectors.
21119            */
21120            if(options.normalScrollElements){
21121                $document.on('mouseenter', options.normalScrollElements, function () {
21122                    setMouseWheelScrolling(false);
21123                });
21124
21125                $document.on('mouseleave', options.normalScrollElements, function(){
21126                    setMouseWheelScrolling(true);
21127                });
21128            }
21129        }
21130
21131        /**
21132        * Setting options from DOM elements if they are not provided.
21133        */
21134        function setOptionsFromDOM(){
21135            var sections = container.find(options.sectionSelector);
21136
21137            //no anchors option? Checking for them in the DOM attributes
21138            if(!options.anchors.length){
21139                options.anchors = sections.filter('[data-anchor]').map(function(){
21140                    return $(this).data('anchor').toString();
21141                }).get();
21142            }
21143
21144            //no tooltips option? Checking for them in the DOM attributes
21145            if(!options.navigationTooltips.length){
21146                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
21147                    return $(this).data('tooltip').toString();
21148                }).get();
21149            }
21150        }
21151
21152        /**
21153        * Works over the DOM structure to set it up for the current fullpage options.
21154        */
21155        function prepareDom(){
21156            container.css({
21157                'height': '100%',
21158                'position': 'relative'
21159            });
21160
21161            //adding a class to recognize the container internally in the code
21162            container.addClass(WRAPPER);
21163            $('html').addClass(ENABLED);
21164
21165            windowsHeight = $window.height();
21166
21167            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
21168
21169            addInternalSelectors();
21170
21171             //styling the sections / slides / menu
21172            $(SECTION_SEL).each(function(index){
21173                var section = $(this);
21174                var slides = section.find(SLIDE_SEL);
21175                var numSlides = slides.length;
21176
21177                styleSection(section, index);
21178                styleMenu(section, index);
21179
21180                // if there's any slide
21181                if (numSlides > 0) {
21182                    styleSlides(section, slides, numSlides);
21183                }else{
21184                    if(options.verticalCentered){
21185                        addTableClass(section);
21186                    }
21187                }
21188            });
21189
21190            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
21191            if(options.fixedElements && options.css3){
21192                $(options.fixedElements).appendTo($body);
21193            }
21194
21195            //vertical centered of the navigation + active bullet
21196            if(options.navigation){
21197                addVerticalNavigation();
21198            }
21199
21200            enableYoutubeAPI();
21201
21202            if(options.scrollOverflow){
21203                if(document.readyState === 'complete'){
21204                    createScrollBarHandler();
21205                }
21206                //after DOM and images are loaded
21207                $window.on('load', createScrollBarHandler);
21208            }else{
21209                afterRenderActions();
21210            }
21211        }
21212
21213        /**
21214        * Styles the horizontal slides for a section.
21215        */
21216        function styleSlides(section, slides, numSlides){
21217            var sliderWidth = numSlides * 100;
21218            var slideWidth = 100 / numSlides;
21219
21220            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
21221            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
21222
21223            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
21224
21225            if(numSlides > 1){
21226                if(options.controlArrows){
21227                    createSlideArrows(section);
21228                }
21229
21230                if(options.slidesNavigation){
21231                    addSlidesNavigation(section, numSlides);
21232                }
21233            }
21234
21235            slides.each(function(index) {
21236                $(this).css('width', slideWidth + '%');
21237
21238                if(options.verticalCentered){
21239                    addTableClass($(this));
21240                }
21241            });
21242
21243            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
21244
21245            //if the slide won't be an starting point, the default will be the first one
21246            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
21246ide by default.
21247            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
21248                silentLandscapeScroll(startingSlide, 'internal');
21249            }else{
21250                slides.eq(0).addClass(ACTIVE);
21251            }
21252        }
21253
21254        /**
21255        * Styling vertical sections
21256        */
21257        function styleSection(section, index){
21258            //if no active section is defined, the 1st one will be the default one
21259            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
21260                section.addClass(ACTIVE);
21261            }
21262            startingSection = $(SECTION_ACTIVE_SEL);
21263
21264            section.css('height', windowsHeight + 'px');
21265
21266            if(options.paddingTop){
21267                section.css('padding-top', options.paddingTop);
21268            }
21269
21270            if(options.paddingBottom){
21271                section.css('padding-bottom', options.paddingBottom);
21272            }
21273
21274            if (typeof options.sectionsColor[index] !==  'undefined') {
21275                section.css('background-color', options.sectionsColor[index]);
21276            }
21277
21278            if (typeof options.anchors[index] !== 'undefined') {
21279                section.attr('data-anchor', options.anchors[index]);
21280            }
21281        }
21282
21283        /**
21284        * Sets the data-anchor attributes to the menu elements and activates the current one.
21285        */
21286        function styleMenu(section, index){
21287            if (typeof options.anchors[index] !== 'undefined') {
21288                //activating the menu / nav element on load
21289                if(section.hasClass(ACTIVE)){
21290                    activateMenuAndNav(options.anchors[index], index);
21291                }
21292            }
21293
21294            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
21295            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
21296                $(options.menu).appendTo($body);
21297            }
21298        }
21299
21300        /**
21301        * Adds internal classes to be able to provide customizable selectors
21302        * keeping the link with the style sheet.
21303        */
21304        function addInternalSelectors(){
21305            container.find(options.sectionSelector).addClass(SECTION);
21306            container.find(options.slideSelector).addClass(SLIDE);
21307        }
21308
21309        /**
21310        * Creates the control arrows for the given section
21311        */
21312        function createSlideArrows(section){
21313            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
21314
21315            if(options.controlArrowColor!='#fff'){
21316                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
21317                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
21318            }
21319
21320            if(!options.loopHorizontal){
21321                section.find(SLIDES_ARROW_PREV_SEL).hide();
21322            }
21323        }
21324
21325        /**
21326        * Creates a vertical navigation bar.
21327        */
21328        function addVerticalNavigation(){
21329            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
21330            var nav = $(SECTION_NAV_SEL);
21331
21332            nav.addClass(function() {
21333                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
21334            });
21335
21336            for (var i = 0; i < $(SECTION_SEL).length; i++) {
21337                var link = '';
21338                if (options.anchors.length) {
21339                    link = options.anchors[i];
21340                }
21341
21342                var li = '<li><a href="#' + link + '"><span></span></a>';
21343
21344                // Only add tooltip if needed (defined by user)
21345                var tooltip = options.navigationTooltips[i];
21346
21347                if (typeof tooltip !== 'undefined' && tooltip !== '') {
21348                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
21349                }
21350
21351                li += '</li>';
21352
21353                nav.find('ul').append(li);
21354            }
21355
21356            //centering it vertically
21357            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
21358
21359            //activating the current active section
21360            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
21361        }
21362
21363        /**
21364        * Creates the slim scroll scrollbar for the sections and slides inside them.
21365        */
21366        function createScrollBarHandler(){
21367            $(SECTION_SEL).each(function(){
21368                var slides = $(this).find(SLIDE_SEL);
21369
21370                if(slides.length){
21371                    slides.each(function(){
21372                        createScrollBar($(this));
21373                    });
21374                }else{
21375                    createScrollBar($(this));
21376                }
21377
21378            });
21379            afterRenderActions();
21380        }
21381
21382        /*
21383        * Enables the Youtube videos API so we can control their flow if necessary.
21384        */
21385        function enableYoutubeAPI(){
21386            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
21387                addURLParam($(this), 'enablejsapi=1');
21388            });
21389        }
21390
21391        /**
21392        * Adds a new parameter and its value to the `src` of a given element
21393        */
21394        function addURLParam(element, newParam){
21395            var originalSrc = element.attr('src');
21396            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
21397        }
21398
21399        /*
21400        * Returns the prefix sign to use for a new parameter in an existen URL.
21401        *
21402        * @return {String}  ? | &
21403        */
21404        function getUrlParamSign(url){
21405            return ( !/\?/.test( url ) ) ? '?' : '&';
21406        }
21407
21408        /**
21409        * Actions and callbacks to fire afterRender
21410        */
21411        function afterRenderActions(){
21412            var section = $(SECTION_ACTIVE_SEL);
21413
21414            section.addClass(COMPLETELY);
21415
21416            if(options.scrollOverflowHandler.afterRender){
21417                options.scrollOverflowHandler.afterRender(section);
21418            }
21419            lazyLoad(section);
21420            playMedia(section);
21421            options.scrollOverflowHandler.afterLoad();
21422
21423            if(isDestinyTheStartingSection()){
21424                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
21425            }
21426
21427            $.isFunction( options.afterRender ) && options.afterRender.call(container);
21428        }
21429
21430        /**
21431        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
21432        */
21433        function isDestinyTheStartingSection(){
21434            var anchors =  window.location.hash.replace('#', '').split('/');
21435            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
21436
21437            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
21438        }
21439
21440
21441        var isScrolling = false;
21442        var lastScroll = 0;
21443
21444        //when scrolling...
21445        function scrollHandler(){
21446            var currentSection;
21447
21448            if(!options.autoScrolling || options.scrollBar){
21449                var currentScroll = $window.scrollTop();
21450                var scrollDirection = getScrollDirection(currentScroll);
21451                var visibleSectionIndex = 0;
21452                var screen_mid = currentScroll + ($window.height() / 2.0);
21453                var isAtBottom = $body.height() - $window.height() === currentScroll;
21454                var sections =  document.querySelectorAll(SECTION_SEL);
21455
21456                //when using `auto-height` for a small last section it won't be centered in the viewport
21457                if(isAtBottom){
21458                    visibleSectionIndex = sections.length - 1;
21459                }
21460                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
21461                else if(!currentScroll){
21462                    visibleSectionIndex = 0;
21463                }
21464
21465                //taking the section which is showing more content in the viewport
21466                else{
21467                    for (var i = 0; i < sections.length; ++i) {
21468                        var section = sections[i];
21469
21470                        // Pick the the last section which passes the middle line of the screen.
21471                        if (section.offsetTop <= screen_mid)
21472                        {
21473                            visibleSectionIndex = i;
21474                        }
21475                    }
21476                }
21477
21478                if(isCompletelyInViewPort(scrollDirection)){
21479                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
21480                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
21481                    }
21482                }
21483
21484                //geting the last one, the current one on the screen
21485                currentSection = $(sections).eq(visibleSectionIndex);
21486
21487                //setting the visible section as active when manually scrolling
21488                //executing only once the first time we reach the section
21489                if(!currentSection.hasClass(ACTIVE)){
21490                    isScrolling = true;
21491                    var leavingSection = $(SECTION_ACTIVE_SEL);
21492                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
21493                    var yMovement = getYmovement(currentSection);
21494                    var anchorLink  = currentSection.data('anchor');
21495                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
21496                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
21497                    var slideIndex;
21498                    var slideAnchorLink;
21499
21500                    if(activeSlide.length){
21501                        slideAnchorLink = activeSlide.data('anchor');
21502                        slideIndex = activeSlide.index();
21503                    }
21504
21505                    if(canScroll){
21506                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
21507
21508                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
21509                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
21510
21511                        stopMedia(leavingSection);
21512                        lazyLoad(currentSection);
21513                        playMedia(currentSection);
21514
21515                        activateMenuAndNav(anchorLink, sectionIndex - 1);
21516
21517                        if(options.anchors.length){
21518                            //needed to enter in hashChange event when using the menu with anchor links
21519                            lastScrolledDestiny = anchorLink;
21520                        }
21521                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
21522                    }
21523
21524                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
21525                    clearTimeout(scrollId);
21526                    scrollId = setTimeout(function(){
21527                        isScrolling = false;
21528                    }, 100);
21529                }
21530
21531                if(options.fitToSection){
21532                    //for the auto adjust of the viewport to fit a whole section
21533                    clearTimeout(scrollId2);
21534
21535                    scrollId2 = setTimeout(function(){
21536                        //checking it again in case it changed during the delay
21537                        if(options.fitToSection){
21538                            fitToSection();
21539                        }
21540                    }, options.fitToSectionDelay);
21541                }
21542            }
21543        }
21544
21545        /**
21546        * Fits the site to the nearest active section
21547        */
21548        function fitToSection(){
21549            //checking fitToSection again in case it was set to false before the timeout delay
21550            if(canScroll){
21551                //allows to scroll to an active section and
21552                //if the section is already active, we prevent firing callbacks
21553                isResizing = true;
21554
21555                scrollPage($(SECTION_ACTIVE_SEL));
21556                isResizing = false;
21557            }
21558        }
21559
21560        /**
21561        * Determines whether the active section has seen in its whole or not.
21562        */
21563        function isCompletelyInViewPort(movement){
21564            var top = $(SECTION_ACTIVE_SEL).position().top;
21565            var bottom = top + $window.height();
21566
21567            if(movement == 'up'){
21568                return bottom >= ($window.scrollTop() + $window.height());
21569            }
21570            return top <= $window.scrollTop();
21571        }
21572
21573        /**
21574        * Gets the directon of the the scrolling fired by the scroll event.
21575        */
21576        function getScrollDirection(currentScroll){
21577            var direction = currentScroll > lastScroll ? 'down' : 'up';
21578
21579            lastScroll = currentScroll;
21580
21581            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
21582            previousDestTop = currentScroll;
21583
21584            return direction;
21585        }
21586
21587        /**
21588        * Determines the way of scrolling up or down:
21589        * by 'automatically' scrolling a section or by using the default and normal scrolling.
21590        */
21591        function scrolling(type, scrollable){
21592            if (!isScrollAllowed.m[type]){
21593                return;
21594            }
21595            var check = (type === 'down') ? 'bottom' : 'top';
21596            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
21597
21598            if(scrollable.length > 0 ){
21599                //is the scrollbar at the start/end of the scroll?
21600                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
21601                    scrollSection();
21602                }else{
21603                    return true;
21604                }
21605            }else{
21606                // moved up/down
21607                scrollSection();
21608            }
21609        }
21610
21611        /*
21612        * Preventing bouncing in iOS #2285
21613        */
21614        function preventBouncing(event){
21615            var e = event.originalEvent;
21616            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){
21617                //preventing the easing on iOS devices
21618                event.preventDefault();
21619            }
21620        }
21621
21622        var touchStartY = 0;
21623        var touchStartX = 0;
21624        var touchEndY = 0;
21625        var touchEndX = 0;
21626
21627        /* Detecting touch events
21628
21629        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
21630        * This way, the touchstart and the touch moves shows an small difference between them which is the
21631        * used one to determine the direction.
21632        */
21633        function touchMoveHandler(event){
21634            var e = event.originalEvent;
21635            var activeSection = $(e.target).closest(SECTION_SEL);
21636
21637            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
21638            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
21639
21640                if(options.autoScrolling){
21641                    //preventing the easing on iOS devices
21642                    event.preventDefault();
21643                }
21644
21645                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
21646                var touchEvents = getEventsPage(e);
21647
21648                touchEndY = touchEvents.y;
21649                touchEndX = touchEvents.x;
21650
21651                //if movement in the X axys is greater than in the Y and the currect section has slides...
21652                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
21653
21654                    //is the movement greater than the minimum resistance to scroll?
21655                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
21656                        if (touchStartX > touchEndX) {
21657                            if(isScrollAllowed.m.right){
21658                                moveSlideRight(activeSection); //next
21659                            }
21660                        } else {
21661                            if(isScrollAllowed.m.left){
21662                                moveSlideLeft(activeSection); //prev
21663                            }
21664                        }
21665                    }
21666                }
21667
21668                //vertical scrolling (only when autoScrolling is enabled)
21669                else if(options.autoScrolling && canScroll){
21670
21671                    //is the movement greater than the minimum resistance to scroll?
21672                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
21673                        if (touchStartY > touchEndY) {
21674                            scrolling('down', scrollable);
21675                        } else if (touchEndY > touchStartY) {
21676                            scrolling('up', scrollable);
21677                        }
21678                    }
21679                }
21680            }
21681        }
21682
21683        /**
21684         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
21685         * Currently works well for iOS - Android might need some testing
21686         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
21687         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
21688         * @return {boolean} true if there is a match to options.normalScrollElements
21689         */
21690        function checkParentForNormalScrollElement (el, hop) {
21691            hop = hop || 0;
21692            var parent = $(el).parent();
21693
21694            if (hop < options.normalScrollElementTouchThreshold &&
21695                parent.is(options.normalScrollElements) ) {
21696                return true;
21697            } else if (hop == options.normalScrollElementTouchThreshold) {
21698                return false;
21699            } else {
21700                return checkParentForNormalScrollElement(parent, ++hop);
21701            }
21702        }
21703
21704        /**
21705        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
21706        * this way we make sure that is really a touch event what IE is detecting.
21707        */
21708        function isReallyTouch(e){
21709            //if is not IE   ||  IE is detecting `touch` or `pen`
21710            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
21711        }
21712
21713        /**
21714        * Handler for the touch start event.
21715        */
21716        function touchStartHandler(event){
21717            var e = event.originalEvent;
21718
21719            //stopping the auto scroll to adjust to a section
21720            if(options.fitToSection){
21721                $htmlBody.stop();
21722            }
21723
21724            if(isReallyTouch(e)){
21725                var touchEvents = getEventsPage(e);
21726                touchStartY = touchEvents.y;
21727                touchStartX = touchEvents.x;
21728            }
21729        }
21730
21731        /**
21732        * Gets the average of the last `number` elements of the given array.
21733        */
21734        function getAverage(elements, number){
21735            var sum = 0;
21736
21737            //taking `number` elements from the end to make the average, if there are not enought, 1
21738            var lastElements = elements.slice(Math.max(elements.length - number, 1));
21739
21740            for(var i = 0; i < lastElements.length; i++){
21741                sum = sum + lastElements[i];
21742            }
21743
21744            return Math.ceil(sum/number);
21745        }
21746
21747        /**
21748         * Detecting mousewheel scrolling
21749         *
21750         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
21751         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
21752         */
21753        var prevTime = new Date().getTime();
21754
21755        function MouseWheelHandler(e) {
21756            var curTime = new Date().getTime();
21757            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
21758
21759            //autoscrolling and not zooming?
21760            if(options.autoScrolling && !controlPressed && !isNormalScroll){
21761                // cross-browser wheel delta
21762                e = e || window.event;
21763                var value = e.wheelDelta || -e.deltaY || -e.detail;
21764                var delta = Math.max(-1, Math.min(1, value));
21765
21766                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
21767                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
21768
21769                //Limiting the array to 150 (lets not waste memory!)
21770                if(scrollings.length > 149){
21771                    scrollings.shift();
21772                }
21773
21774                //keeping record of the previous scrollings
21775                scrollings.push(Math.abs(value));
21776
21777                //preventing to scroll the site on mouse wheel when scrollbar is present
21778                if(options.scrollBar){
21779                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
21780                }
21781
21782                var activeSection = $(SECTION_ACTIVE_SEL);
21783                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
21784
21785                //time difference between the last scroll and the current one
21786                var timeDiff = curTime-prevTime;
21787                prevTime = curTime;
21788
21789                //haven't they scrolled in a while?
21790                //(enough to be consider a different scrolling action to scroll another section)
21791                if(timeDiff > 200){
21792                    //emptying the array, we dont care about old scrollings for our averages
21793                    scrollings = [];
21794                }
21795
21796                if(canScroll){
21797                    var averageEnd = getAverage(scrollings, 10);
21798                    var averageMiddle = getAverage(scrollings, 70);
21799                    var isAccelerating = averageEnd >= averageMiddle;
21800
21801                    //to avoid double swipes...
21802                    if(isAccelerating && isScrollingVertically){
21803                        //scrolling down?
21804                        if (delta < 0) {
21805                            scrolling('down', scrollable);
21806
21807                        //scrolling up?
21808                        }else {
21809                            scrolling('up', scrollable);
21810                        }
21811                    }
21812                }
21813
21814                return false;
21815            }
21816
21817            if(options.fitToSection){
21818                //stopping the auto scroll to adjust to a section
21819                $htmlBody.stop();
21820            }
21821        }
21822
21823        /**
21824        * Slides a slider to the given direction.
21825        * Optional `section` param.
21826        */
21827        function moveSlide(direction, section){
21828            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
21829            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
21830            var numSlides = slides.find(SLIDE_SEL).length;
21831
21832            // more than one slide needed and nothing should be sliding
21833            if (!slides.length || slideMoving || numSlides < 2) {
21834                return;
21835            }
21836
21837            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
21838            var destiny = null;
21839
21840            if(direction === 'left'){
21841                destiny = currentSlide.prev(SLIDE_SEL);
21842            }else{
21843                destiny = currentSlide.next(SLIDE_SEL);
21844            }
21845
21846            //isn't there a next slide in the secuence?
21847            if(!destiny.length){
21848                //respect loopHorizontal settin
21849                if (!options.loopHorizontal) return;
21850
21851                if(direction === 'left'){
21852                    destiny = currentSlide.siblings(':last');
21853                }else{
21854                    destiny = currentSlide.siblings(':first');
21855                }
21856            }
21857
21858            slideMoving = true;
21859
21860            landscapeScroll(slides, destiny, direction);
21861        }
21862
21863        /**
21864        * Maintains the active slides in the viewport
21865        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
21866        */
21867        function keepSlidesPosition(){
21868            $(SLIDE_ACTIVE_SEL).each(function(){
21869                silentLandscapeScroll($(this), 'internal');
21870            });
21871        }
21872
21873        var previousDestTop = 0;
21874        /**
21875        * Returns the destination Y position based on the scrolling direction and
21876        * the height of the section.
21877        */
21878        function getDestinationPosition(element){
21879            var elemPosition = element.position();
21880
21881            //top of the desination will be at the top of the viewport
21882            var position = elemPosition.top;
21883            var isScrollingDown =  elemPosition.top > previousDestTop;
21884            var sectionBottom = position - windowsHeight + element.outerHeight();
21885            var bigSectionsDestination = options.bigSectionsDestination;
21886
21887            //Uncode addition
21888            var containerH = container.outerHeight();
21889            var containerPosition = container.offset();
21890
21891            //########### Commented by Uncode - START ###########
21892            //is the destination element bigger than the viewport?
21893            // if(element.outerHeight() > windowsHeight){
21894            //     //scrolling up?
21895            //     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
21896            //         position = sectionBottom;
21897            //     }
21898            // }
21899
21900            // //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
21901            // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
21902            //     //The bottom of the destination will be at the bottom of the viewport
21903            //     position = sectionBottom;
21904            // }
21905            //########### Commented by Uncode - END ###########
21906
21907            //Uncode addition
21908            if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
21909                position += 18;
21910            if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
21911                position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
21912            }
21913
21914            /*
21915            Keeping record of the last scrolled position to determine the scrolling direction.
21916            No conventional methods can be used as the scroll bar might not be present
21917            AND the section might not be active if it is auto-height and didnt reach the middle
21918            of the viewport.
21919            */
21920            previousDestTop = position;
21921            return position;
21922        }
21923
21924        /**
21925        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
21926        */
21927        function scrollPage(element, callback, isMovementUp){
21928            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
21929
21930            var dtop = getDestinationPosition(element);
21931            var slideAnchorLink;
21932            var slideIndex;
21933
21934            //local variables
21935            var v = {
21936                element: element,
21937                callback: callback,
21938                isMovementUp: isMovementUp,
21939                dtop: dtop,
21940                yMovement: getYmovement(element),
21941                anchorLink: element.data('anchor'),
21942                sectionIndex: element.index(SECTION_SEL),
21943                activeSlide: element.find(SLIDE_ACTIVE_SEL),
21944                activeSection: $(SECTION_ACTIVE_SEL),
21945                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
21946
21947                //caching the value of isResizing at the momment the function is called
21948                //because it will be checked later inside a setTimeout and the value might change
21949                localIsResizing: isResizing
21950            };
21951
21952            //quiting when destination scroll is the same as the current one
21953            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
21954
21955            if(v.activeSlide.length){
21956                slideAnchorLink = v.activeSlide.data('anchor');
21957                slideIndex = v.activeSlide.index();
21958            }
21959
21960            // If continuousVertical && we need to wrap around
21961            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
21962                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
21963                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
21964
21965                v = createInfiniteSections(v);
21966            }
21967
21968            //callback (onLeave) if the site is not just resizing and readjusting the slides
21969            if($.isFunction(options.onLeave) && !v.localIsResizing){
21970                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
21971                    return;
21972                }
21973            }
21974
21975            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
21976            if(!v.localIsResizing){
21977                stopMedia(v.activeSection);
21978            }
21979
21980            options.scrollOverflowHandler.beforeLeave();
21981            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
21982            lazyLoad(element);
21983            options.scrollOverflowHandler.onLeave();
21984
21985
21986            //preventing from activating the MouseWheelHandler event
21987            //more than once if the page is scrolling
21988            canScroll = false;
21989
21990            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
21991
21992            performMovement(v);
21993
21994            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
21995            lastScrolledDestiny = v.anchorLink;
21996
21997            //avoid firing it twice (as it does also on scroll)
21998            activateMenuAndNav(v.anchorLink, v.sectionIndex);
21999        }
22000
22001        /**
22002        * Performs the vertical movement (by CSS3 or by jQuery)
22003        */
22004        function performMovement(v){
22005            // using CSS3 translate functionality
22006            if (options.css3 && options.autoScrolling && !options.scrollBar) {
22007
22008                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
22009                // that's why we round it to 0.
22010                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
22011                transformContainer(translate3d, true);
22012
22013                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
22014                //scrollingSpeed to change in case of using silentMoveTo();
22015                if(options.scrollingSpeed){
22016                    clearTimeout(afterSectionLoadsId);
22017                    afterSectionLoadsId = setTimeout(function () {
22018                        afterSectionLoads(v);
22019                    }, options.scrollingSpeed);
22020                }else{
22021                    afterSectionLoads(v);
22022                }
22023            }
22024
22025            // using jQuery animate
22026            else{
22027                var scrollSettings = getScrollSettings(v);
22028
22029                $(scrollSettings.element).animate(
22030                    scrollSettings.options,
22031                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
22032                    if(options.scrollBar){
22033
22034                        /* Hack!
22035                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
22036                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
22037
22038                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
22039                        */
22040                        setTimeout(function(){
22041                            afterSectionLoads(v);
22042                        },30);
22043                    }else{
22044                        afterSectionLoads(v);
22045                    }
22046                });
22047            }
22048        }
22049
22050        /**
22051        * Gets the scrolling settings depending on the plugin autoScrolling option
22052        */
22053        function getScrollSettings(v){
22054            var scroll = {};
22055
22056            if(options.autoScrolling && !options.scrollBar){
22057                scroll.options = { 'top': -v.dtop};
22058                scroll.element = WRAPPER_SEL;
22059            }else{
22060                scroll.options = { 'scrollTop': v.dtop};
22061                scroll.element = 'html, body';
22062            }
22063
22064            return scroll;
22065        }
22066
22067        /**
22068        * Adds sections before or after the current one to create the infinite effect.
22069        */
22070        function createInfiniteSections(v){
22071            // Scrolling down
22072            if (!v.isMovementUp) {
22073                // Move all previous sections to after the active section
22074                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
22075            }
22076            else { // Scrolling up
22077                // Move all next sections to before the active section
22078                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
22079            }
22080
22081            // Maintain the displayed position (now that we changed the element order)
22082            silentScroll($(SECTION_ACTIVE_SEL).position().top);
22083
22084            // Maintain the active slides visible in the viewport
22085            keepSlidesPosition();
22086
22087            // save for later the elements that still need to be reordered
22088            v.wrapAroundElements = v.activeSection;
22089
22090            // Recalculate animation variables
22091            v.dtop = v.element.position().top;
22092            v.yMovement = getYmovement(v.element);
22093
22094            return v;
22095        }
22096
22097        /**
22098        * Fix section order after continuousVertical changes have been animated
22099        */
22100        function continuousVerticalFixSectionOrder (v) {
22101            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
22102            // finish moving the elements around so the direct navigation will function more simply
22103            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
22104                return;
22105            }
22106
22107            if (v.isMovementUp) {
22108                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
22109            }
22110            else {
22111                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
22112            }
22113
22114            silentScroll($(SECTION_ACTIVE_SEL).position().top);
22115
22116            // Maintain the active slides visible in the viewport
22117            keepSlidesPosition();
22118        }
22119
22120
22121        /**
22122        * Actions to do once the section is loaded.
22123        */
22124        function afterSectionLoads (v){
22125            continuousVerticalFixSectionOrder(v);
22126
22127            //callback (afterLoad) if the site is not just resizing and readjusting the slides
22128            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
22129            options.scrollOverflowHandler.afterLoad();
22130
22131            if(!v.localIsResizing){
22132                playMedia(v.element);
22133            }
22134
22135            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
22136
22137            canScroll = true;
22138
22139            $.isFunction(v.callback) && v.callback.call(this);
22140        }
22141
22142        /**
22143        * Sets the value for the given attribute from the `data-` attribute with the same suffix
22144        * ie: data-srcset ==> srcset  |  data-src ==> src
22145        */
22146        function setSrc(element, attribute){
22147            element
22148                .attr(attribute, element.data(attribute))
22149                .removeAttr('data-' + attribute);
22150        }
22151
22152        /**
22153        * Lazy loads image, video and audio elements.
22154        */
22155        function lazyLoad(destiny){
22156            if (!options.lazyLoading){
22157                return;
22158            }
22159
22160            var panel = getSlideOrSection(destiny);
22161            var element;
22162
22163            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
22164                element = $(this);
22165
22166                $.each(['src', 'srcset'], function(index, type){
22167                    var attribute = element.attr('data-' + type);
22168                    if(typeof attribute !== 'undefined' && attribute){
22169                        setSrc(element, type);
22170                    }
22171                });
22172
22173                if(element.is('source')){
22174                    element.closest('video').get(0).load();
22175                }
22176            });
22177        }
22178
22179        /**
22180        * Plays video and audio elements.
22181        */
22182        function playMedia(destiny){
22183            var panel = getSlideOrSection(destiny);
22184
22185            //playing HTML5 media elements
22186            panel.find('video, audio').each(function(){
22187                var element = $(this).get(0);
22188
22189                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
22190                    element.play();
22191                }
22192            });
22193
22194            //youtube videos
22195            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
22196                var element = $(this).get(0);
22197
22198                if ( element.hasAttribute('data-autoplay') ){
22199                    playYoutube(element);
22200                }
22201
22202                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
22203                element.onload = function() {
22204                    if ( element.hasAttribute('data-autoplay') ){
22205                        playYoutube(element);
22206                    }
22207                };
22208            });
22209        }
22210
22211        /**
22212        * Plays a youtube video
22213        */
22214        function playYoutube(element){
22215            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
22216        }
22217
22218        /**
22219        * Stops video and audio elements.
22220        */
22221        function stopMedia(destiny){
22222            var panel = getSlideOrSection(destiny);
22223
22224            //stopping HTML5 media elements
22225            panel.find('video, audio').each(function(){
22226                var element = $(this).get(0);
22227
22228                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
22229                    element.pause();
22230                }
22231            });
22232
22233            //youtube videos
22234            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
22235                var element = $(this).get(0);
22236
22237                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
22238                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
22239                }
22240            });
22241        }
22242
22243        /**
22244        * Gets the active slide (or section) for the given section
22245        */
22246        function getSlideOrSection(destiny){
22247            var slide = destiny.find(SLIDE_ACTIVE_SEL);
22248            if( slide.length ) {
22249                destiny = $(slide);
22250            }
22251
22252            return destiny;
22253        }
22254
22255        /**
22256        * Scrolls to the anchor in the URL when loading the site
22257        */
22258        function scrollToAnchor(){
22259            //getting the anchor link in the URL and deleting the `#`
22260            var value =  window.location.hash.replace('#', '').split('/');
22261            var sectionAnchor = decodeURIComponent(value[0]);
22262            var slideAnchor = decodeURIComponent(value[1]);
22263
22264            if(sectionAnchor){  //if theres any #
22265                if(options.animateAnchor){
22266                    scrollPageAndSlide(sectionAnchor, slideAnchor);
22267                }else{
22268                    silentMoveTo(sectionAnchor, slideAnchor);
22269                }
22270            }
22271        }
22272
22273        /**
22274        * Detecting any change on the URL to scroll to the given anchor link
22275        * (a way to detect back history button as we play with the hashes on the URL)
22276        */
22277        function hashChangeHandler(){
22278            if(!isScrolling && !options.lockAnchors){
22279                var value =  window.location.hash.replace('#', '').split('/');
22280                var sectionAnchor = decodeURIComponent(value[0]);
22281                var slideAnchor = decodeURIComponent(value[1]);
22282
22283                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
22284                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
22285                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
22286
22287
22288                if(sectionAnchor.length){
22289                    /*in order to call scrollpage() only once for each destination at a time
22290                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
22291                    event is fired on every scroll too.*/
22292                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
22293                        scrollPageAndSlide(sectionAnchor, slideAnchor);
22294                    }
22295                }
22296            }
22297        }
22298
22299        //Sliding with arrow keys, both, vertical and horizontal
22300        function keydownHandler(e) {
22301
22302            clearTimeout(keydownId);
22303
22304            var activeElement = $(':focus');
22305
22306            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
22307                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
22308                options.keyboardScrolling && options.autoScrolling){
22309                var keyCode = e.which;
22310
22311                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
22312                var keyControls = [40, 38, 32, 33, 34];
22313                if($.inArray(keyCode, keyControls) > -1){
22314                    e.preventDefault();
22315                }
22316
22317                controlPressed = e.ctrlKey;
22318
22319                keydownId = setTimeout(function(){
22320                    onkeydown(e);
22321                },150);
22322            }
22323        }
22324
22325        function tooltipTextHandler(){
22326            $(this).prev().trigger('click');
22327        }
22328
22329        //to prevent scrolling while zooming
22330        function keyUpHandler(e){
22331            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
22332                controlPressed = e.ctrlKey;
22333            }
22334        }
22335
22336        //binding the mousemove when the mouse's middle button is released
22337        function mouseDownHandler(e){
22338            //middle button
22339            if (e.which == 2){
22340                oldPageY = e.pageY;
22341                container.on('mousemove', mouseMoveHandler);
22342            }
22343        }
22344
22345        //unbinding the mousemove when the mouse's middle button is released
22346        function mouseUpHandler(e){
22347            //middle button
22348            if (e.which == 2){
22349                container.off('mousemove');
22350            }
22351        }
22352
22353        //Scrolling horizontally when clicking on the slider controls.
22354        function slideArrowHandler(){
22355            var section = $(this).closest(SECTION_SEL);
22356
22357            if ($(this).hasClass(SLIDES_PREV)) {
22358                if(isScrollAllowed.m.left){
22359                    moveSlideLeft(section);
22360                }
22361            } else {
22362                if(isScrollAllowed.m.right){
22363                    moveSlideRight(section);
22364                }
22365            }
22366        }
22367
22368        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
22369        function blurHandler(){
22370            isWindowFocused = false;
22371            controlPressed = false;
22372        }
22373
22374        //Scrolls to the section when clicking the navigation bullet
22375        function sectionBulletHandler(e){
22376            e.preventDefault();
22377            var index = $(this).parent().index();
22378            scrollPage($(SECTION_SEL).eq(index));
22379        }
22380
22381        //Scrolls the slider to the given slide destination for the given section
22382        function slideBulletHandler(e){
22383            e.preventDefault();
22384            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
22385            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
22386
22387            landscapeScroll(slides, destiny);
22388        }
22389
22390        /**
22391        * Keydown event
22392        */
22393        function onkeydown(e){
22394            var shiftPressed = e.shiftKey;
22395
22396            //do nothing if we can not scroll or we are not using horizotnal key arrows.
22397            if(!canScroll && [37,39].indexOf(e.which) < 0){
22398                return;
22399            }
22400
22401            switch (e.which) {
22402                //up
22403                case 38:
22404                case 33:
22405                    if(isScrollAllowed.k.up){
22406                        moveSectionUp();
22407                    }
22408                    break;
22409
22410                //down
22411                case 32: //spacebar
22412                    if(shiftPressed && isScrollAllowed.k.up){
22413                        moveSectionUp();
22414                        break;
22415                    }
22416                /* falls through */
22417                case 40:
22418                case 34:
22419                    if(isScrollAllowed.k.down){
22420                        moveSectionDown();
22421                    }
22422                    break;
22423
22424                //Home
22425                case 36:
22426                    if(isScrollAllowed.k.up){
22427                        moveTo(1);
22428                    }
22429                    break;
22430
22431                //End
22432                case 35:
22433                     if(isScrollAllowed.k.down){
22434                        moveTo( $(SECTION_SEL).length );
22435                    }
22436                    break;
22437
22438                //left
22439                case 37:
22440                    if(isScrollAllowed.k.left){
22441                        moveSlideLeft();
22442                    }
22443                    break;
22444
22445                //right
22446                case 39:
22447                    if(isScrollAllowed.k.right){
22448                        moveSlideRight();
22449                    }
22450                    break;
22451
22452                default:
22453                    return; // exit this handler for other keys
22454            }
22455        }
22456
22457        /**
22458        * Detecting the direction of the mouse movement.
22459        * Used only for the middle button of the mouse.
22460        */
22461        var oldPageY = 0;
22462        function mouseMoveHandler(e){
22463            if(canScroll){
22464                // moving up
22465                if (e.pageY < oldPageY && isScrollAllowed.m.up){
22466                    moveSectionUp();
22467                }
22468
22469                // moving down
22470                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
22471                    moveSectionDown();
22472                }
22473            }
22474            oldPageY = e.pageY;
22475        }
22476
22477        /**
22478        * Scrolls horizontal sliders.
22479        */
22480        function landscapeScroll(slides, destiny, direction){
22481            var section = slides.closest(SECTION_SEL);
22482            var v = {
22483                slides: slides,
22484                destiny: destiny,
22485                direction: direction,
22486                destinyPos: destiny.position(),
22487                slideIndex: destiny.index(),
22488                section: section,
22489                sectionIndex: section.index(SECTION_SEL),
22490                anchorLink: section.data('anchor'),
22491                slidesNav: section.find(SLIDES_NAV_SEL),
22492                slideAnchor:  getAnchor(destiny),
22493                prevSlide: section.find(SLIDE_ACTIVE_SEL),
22494                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
22495
22496                //caching the value of isResizing at the momment the function is called
22497                //because it will be checked later inside a setTimeout and the value might change
22498                localIsResizing: isResizing
22499            };
22500            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
22501            v.direction = v.direction ? v.direction : v.xMovement;
22502
22503            //important!! Only do it when not resizing
22504            if(!v.localIsResizing){
22505                //preventing from scrolling to the next/prev section when using scrollHorizontally
22506                canScroll = false;
22507            }
22508
22509            if(options.onSlideLeave){
22510
22511                //if the site is not just resizing and readjusting the slides
22512                if(!v.localIsResizing && v.xMovement!=='none'){
22513                    if($.isFunction( options.onSlideLeave )){
22514                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
22515                            slideMoving = false;
22516                            return;
22517                        }
22518                    }
22519                }
22520            }
22521
22522            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
22523
22524            if(!v.localIsResizing){
22525                stopMedia(v.prevSlide);
22526                lazyLoad(destiny);
22527            }
22528
22529            if(!options.loopHorizontal && options.controlArrows){
22530                //hidding it for the fist slide, showing for the rest
22531                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
22532
22533                //hidding it for the last slide, showing for the rest
22534                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
22535            }
22536
22537            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
22538            if(section.hasClass(ACTIVE) && !v.localIsResizing){
22539                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
22540            }
22541
22542            performHorizontalMove(slides, v, true);
22543        }
22544
22545
22546        function afterSlideLoads(v){
22547            activeSlidesNavigation(v.slidesNav, v.slideIndex);
22548
22549            //if the site is not just resizing and readjusting the slides
22550            if(!v.localIsResizing){
22551                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
22552
22553                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
22554                //and to prevent double scroll right after a windows resize
22555                canScroll = true;
22556
22557                playMedia(v.destiny);
22558            }
22559
22560            //letting them slide again
22561            slideMoving = false;
22562        }
22563
22564        /**
22565        * Performs the horizontal movement. (CSS3 or jQuery)
22566        *
22567        * @param fireCallback {Bool} - determines whether or not to fire the callback
22568        */
22569        function performHorizontalMove(slides, v, fireCallback){
22570            var destinyPos = v.destinyPos;
22571
22572            if(options.css3){
22573                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
22574
22575                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
22576
22577                afterSlideLoadsId = setTimeout(function(){
22578                    fireCallback && afterSlideLoads(v);
22579                }, options.scrollingSpeed, options.easing);
22580            }else{
22581                slides.animate({
22582                    scrollLeft : Math.round(destinyPos.left)
22583                }, options.scrollingSpeed, options.easing, function() {
22584
22585                    fireCallback && afterSlideLoads(v);
22586                });
22587            }
22588        }
22589
22590        /**
22591        * Sets the state for the horizontal bullet navigations.
22592        */
22593        function activeSlidesNavigation(slidesNav, slideIndex){
22594            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
22595            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
22596        }
22597
22598        var previousHeight = windowsHeight;
22599
22600        //when resizing the site, we adjust the heights of the sections, slimScroll...
22601        function resizeHandler(){
22602            //checking if it needs to get responsive
22603            responsive();
22604
22605            // rebuild immediately on touch devices
22606            if (isTouchDevice) {
22607                var activeElement = $(document.activeElement);
22608
22609                //if the keyboard is NOT visible
22610                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
22611                    var currentHeight = $window.height();
22612
22613                    //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)
22614                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
22615                        reBuild(true);
22616                        previousHeight = currentHeight;
22617                    }
22618                }
22619            }else{
22620                //in order to call the functions only when the resize is finished
22621                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
22622                clearTimeout(resizeId);
22623
22624                resizeId = setTimeout(function(){
22625                    reBuild(true);
22626                }, 350);
22627            }
22628        }
22629
22630        /**
22631        * Checks if the site needs to get responsive and disables autoScrolling if so.
22632        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
22633        */
22634        function responsive(){
22635            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
22636            var heightLimit = options.responsiveHeight;
22637
22638            //only calculating what we need. Remember its called on the resize event.
22639            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
22640            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
22641
22642            if(widthLimit && heightLimit){
22643                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
22644            }
22645            else if(widthLimit){
22646                setResponsive(isBreakingPointWidth);
22647            }
22648            else if(heightLimit){
22649                setResponsive(isBreakingPointHeight);
22650            }
22651        }
22652
22653        /**
22654        * Adds transition animations for the given element
22655        */
22656        function addAnimation(container, element){
22657            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
22658
22659            container.removeClass(NO_TRANSITION);
22660            return container.css({
22661                '-webkit-transition': transition,
22662                'transition': transition
22663            });
22664        }
22665
22666        /**
22667        * Remove transition animations for the given element
22668        */
22669        function removeAnimation(element){
22670            return element.addClass(NO_TRANSITION);
22671        }
22672
22673        /**
22674        * Activating the vertical navigation bullets according to the given slide name.
22675        */
22676        function activateNavDots(name, sectionIndex){
22677            if(options.navigation){
22678                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
22679                if(name){
22680                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
22681                }else{
22682                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
22683                }
22684            }
22685        }
22686
22687        /**
22688        * Activating the website main menu elements according to the given slide name.
22689        */
22690        function activateMenuElement(name){
22691            if(options.menu){
22692                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
22693                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
22694            }
22695        }
22696
22697        /**
22698        * Sets to active the current menu and vertical nav items.
22699        */
22700        function activateMenuAndNav(anchor, index){
22701            activateMenuElement(anchor);
22702            activateNavDots(anchor, index);
22703        }
22704
22705        /**
22706        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
22707        * from the current section.
22708        */
22709        function getYmovement(destiny){
22710            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
22711            var toIndex = destiny.index(SECTION_SEL);
22712            if( fromIndex == toIndex){
22713                return 'none';
22714            }
22715            if(fromIndex > toIndex){
22716                return 'up';
22717            }
22718            return 'down';
22719        }
22720
22721        /**
22722        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
22723        * from the current slide.
22724        */
22725        function getXmovement(fromIndex, toIndex){
22726            if( fromIndex == toIndex){
22727                return 'none';
22728            }
22729            if(fromIndex > toIndex){
22730                return 'left';
22731            }
22732            return 'right';
22733        }
22734
22735        /**
22736        * Checks if the element needs scrollbar and if the user wants to apply it.
22737        * If so it creates it.
22738        *
22739        * @param {Object} element   jQuery object of the section or slide
22740        */
22741        function createScrollBar(element){
22742            //User doesn't want scrollbar here? Sayonara baby!
22743            if(element.hasClass('fp-noscroll')) return;
22744
22745            //needed to make `scrollHeight` work under Opera 12
22746            element.css('overflow', 'hidden');
22747
22748            var scrollOverflowHandler = options.scrollOverflowHandler;
22749            var wrap = scrollOverflowHandler.wrapContent();
22750            //in case element is a slide
22751            var section = element.closest(SECTION_SEL);
22752            var scrollable = scrollOverflowHandler.scrollable(element);
22753            var contentHeight;
22754
22755            //if there was scroll, the contentHeight will be the one in the scrollable section
22756            if(scrollable.length){
22757                contentHeight = scrollOverflowHandler.scrollHeight(element);
22758            }else{
22759                contentHeight = element.get(0).scrollHeight;
22760                if(options.verticalCentered){
22761                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
22762                }
22763            }
22764
22765            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
22766
22767            //needs scroll?
22768            if ( contentHeight > scrollHeight) {
22769                //did we already have an scrollbar ? Updating it
22770                if(scrollable.length){
22771                    scrollOverflowHandler.update(element, scrollHeight);
22772                }
22773                //creating the scrolling
22774                else{
22775                    if(options.verticalCentered){
22776                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
22777                    }else{
22778                        element.wrapInner(wrap);
22779                    }
22780                    scrollOverflowHandler.create(element, scrollHeight);
22781                }
22782            }
22783            //removing the scrolling when it is not necessary anymore
22784            else{
22785                scrollOverflowHandler.remove(element);
22786            }
22787
22788            //undo
22789            element.css('overflow', '');
22790        }
22791
22792        function addTableClass(element){
22793            //In case we are styling for the 2nd time as in with reponsiveSlides
22794            if(!element.hasClass(TABLE)){
22795                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
22796            }
22797        }
22798
22799        function getTableHeight(element){
22800            var sectionHeight = windowsHeight;
22801
22802            if(options.paddingTop || options.paddingBottom){
22803                var section = element;
22804                if(!section.hasClass(SECTION)){
22805                    section = element.closest(SECTION_SEL);
22806                }
22807
22808                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
22809                sectionHeight = (windowsHeight - paddings);
22810            }
22811
22812            return sectionHeight;
22813        }
22814
22815        /**
22816        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
22817        */
22818        function transformContainer(translate3d, animated){
22819            if(animated){
22820                addAnimation(container);
22821            }else{
22822                removeAnimation(container);
22823            }
22824
22825            container.css(getTransforms(translate3d));
22826
22827            //syncronously removing the class after the animation has been applied.
22828            setTimeout(function(){
22829                container.removeClass(NO_TRANSITION);
22830            },10);
22831        }
22832
22833        /**
22834        * Gets a section by its anchor / index
22835        */
22836        function getSectionByAnchor(sectionAnchor){
22837            if(!sectionAnchor) return [];
22838
22839            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
22840            if(!section.length){
22841                section = $(SECTION_SEL).eq( sectionAnchor -1);
22842            }
22843
22844            return section;
22845        }
22846
22847        /**
22848        * Gets a slide inside a given section by its anchor / index
22849        */
22850        function getSlideByAnchor(slideAnchor, section){
22851            var slides = section.find(SLIDES_WRAPPER_SEL);
22852            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
22853
22854            if(!slide.length){
22855                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
22856            }
22857
22858            return slide;
22859        }
22860
22861        /**
22862        * Scrolls to the given section and slide anchors
22863        */
22864        function scrollPageAndSlide(destiny, slide){
22865            var section = getSectionByAnchor(destiny);
22866
22867            //do nothing if there's no section with the given anchor name
22868            if(!section.length) return;
22869
22870            //default slide
22871            if (typeof slide === 'undefined') {
22872                slide = 0;
22873            }
22874
22875            //we need to scroll to the section and then to the slide
22876            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
22877                scrollPage(section, function(){
22878                    scrollSlider(section, slide);
22879                });
22880            }
22881            //if we were already in the section
22882            else{
22883                scrollSlider(section, slide);
22884            }
22885        }
22886
22887        /**
22888        * Scrolls the slider to the given slide destination for the given section
22889        */
22890        function scrollSlider(section, slideAnchor){
22891            if(typeof slideAnchor !== 'undefined'){
22892                var slides = section.find(SLIDES_WRAPPER_SEL);
22893                var destiny =  getSlideByAnchor(slideAnchor, section);
22894
22895                if(destiny.length){
22896                    landscapeScroll(slides, destiny);
22897                }
22898            }
22899        }
22900
22901        /**
22902        * Creates a landscape navigation bar with dots for horizontal sliders.
22903        */
22904        function addSlidesNavigation(section, numSlides){
22905            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
22906            var nav = section.find(SLIDES_NAV_SEL);
22907
22908            //top or bottom
22909            nav.addClass(options.slidesNavPosition);
22910
22911            for(var i=0; i< numSlides; i++){
22912                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
22913            }
22914
22915            //centering it
22916            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
22917
22918            nav.find('li').first().find('a').addClass(ACTIVE);
22919        }
22920
22921
22922        /**
22923        * Sets the state of the website depending on the active section/slide.
22924        * It changes the URL hash when needed and updates the body class.
22925        */
22926        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
22927            var sectionHash = '';
22928
22929            if(options.anchors.length && !options.lockAnchors){
22930
22931                //isn't it the first slide?
22932                if(slideIndex){
22933                    if(typeof anchorLink !== 'undefined'){
22934                        sectionHash = anchorLink;
22935                    }
22936
22937                    //slide without anchor link? We take the index instead.
22938                    if(typeof slideAnchor === 'undefined'){
22939                        slideAnchor = slideIndex;
22940                    }
22941
22942                    lastScrolledSlide = slideAnchor;
22943                    setUrlHash(sectionHash + '/' + slideAnchor);
22944
22945                //first slide won't have slide anchor, just the section one
22946                }else if(typeof slideIndex !== 'undefined'){
22947                    lastScrolledSlide = slideAnchor;
22948                    setUrlHash(anchorLink);
22949                }
22950
22951                //section without slides
22952                else{
22953                    setUrlHash(anchorLink);
22954                }
22955            }
22956
22957            setBodyClass();
22958        }
22959
22960        /**
22961        * Sets the URL hash.
22962        */
22963        function setUrlHash(url){
22964            //Uncode addition
22965            if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
22966                return false;
22967
22968            if(options.recordHistory){
22969                location.hash = url;
22970            }else{
22971                //Uncode addition
22972                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
22973                // if(isTouchDevice || isTouch){
22974                //     window.history.replaceState(undefined, undefined, '#' + url);
22975                // }else{
22976                //     var baseUrl = window.location.href.split('#')[0];
22977                //     window.location.replace( baseUrl + '#' + url );
22978                // }
22979                return false;
22980            }
22981        }
22982
22983        /**
22984        * Gets the anchor for the given slide / section. Its index will be used if there's none.
22985        */
22986        function getAnchor(element){
22987            var anchor = element.data('anchor');
22988            var index = element.index();
22989
22990            //Slide without anchor link? We take the index instead.
22991            if(typeof anchor === 'undefined'){
22992                anchor = index;
22993            }
22994
22995            return anchor;
22996        }
22997
22998        /**
22999        * Sets a class for the body of the page depending on the active section / slide
23000        */
23001        function setBodyClass(){
23002            var section = $(SECTION_ACTIVE_SEL);
23003            var slide = section.find(SLIDE_ACTIVE_SEL);
23004
23005            var sectionAnchor = getAnchor(section);
23006            var slideAnchor = getAnchor(slide);
23007
23008            var text = String(sectionAnchor);
23009
23010            if(slide.length){
23011                text = text + '-' + slideAnchor;
23012            }
23013
23014            //changing slash for dash to make it a valid CSS style
23015            text = text.replace('/', '-').replace('#','');
23016
23017            //removing previous anchor classes
23018            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
23019            $body[0].className = $body[0].className.replace(classRe, '');
23020
23021            //adding the current anchor
23022            $body.addClass(VIEWING_PREFIX + '-' + text);
23023        }
23024
23025        /**
23026        * Checks for translate3d support
23027        * @return boolean
23028        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
23029        */
23030        function support3d() {
23031            var el = document.createElement('p'),
23032                has3d,
23033                transforms = {
23034                    'webkitTransform':'-webkit-transform',
23035                    'OTransform':'-o-transform',
23036                    'msTransform':'-ms-transform',
23037                    'MozTransform':'-moz-transform',
23038                    'transform':'transform'
23039                };
23040
23041            // Add it to the body to get the computed style.
23042            document.body.insertBefore(el, null);
23043
23044            for (var t in transforms) {
23045                if (el.style[t] !== undefined) {
23046                    el.style[t] = 'translate3d(1px,1px,1px)';
23047                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
23048                }
23049            }
23050
23051            document.body.removeChild(el);
23052
23053            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
23054        }
23055
23056        /**
23057        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
23058        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
23059        */
23060        function removeMouseWheelHandler(){
23061            if (document.addEventListener) {
23062                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
23063                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
23064                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
23065            } else {
23066                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
23067            }
23068        }
23069
23070        /**
23071        * Adds the auto scrolling action for the mouse wheel and trackpad.
23072        * After this function is called, the mousewheel and trackpad movements will scroll through sections
23073        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
23074        */
23075        function addMouseWheelHandler(){
23076            var prefix = '';
23077            var _addEventListener;
23078
23079            if (window.addEventListener){
23080                _addEventListener = "addEventListener";
23081            }else{
23082                _addEventListener = "attachEvent";
23083                prefix = 'on';
23084            }
23085
23086             // detect available wheel event
23087            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
23088                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
23089                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
23090            var passiveEvent = g_supportsPassive ? {passive: false }
23090: false;
23091
23092
23093            if(support == 'DOMMouseScroll'){
23094                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent);
23095            }
23096
23097            //handle MozMousePixelScroll in older Firefox
23098            else{
23099                document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent);
23100            }
23101        }
23102
23103        /**
23104        * Binding the mousemove when the mouse's middle button is pressed
23105        */
23106        function addMiddleWheelHandler(){
23107            container
23108                .on('mousedown', mouseDownHandler)
23109                .on('mouseup', mouseUpHandler);
23110        }
23111
23112        /**
23113        * Unbinding the mousemove when the mouse's middle button is released
23114        */
23115        function removeMiddleWheelHandler(){
23116            container
23117                .off('mousedown', mouseDownHandler)
23118                .off('mouseup', mouseUpHandler);
23119        }
23120
23121        /**
23122        * Adds the possibility to auto scroll through sections on touch devices.
23123        */
23124        function addTouchHandler(){
23125            if(isTouchDevice || isTouch){
23126                if(options.autoScrolling){
23127                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
23128                }
23129
23130                $(WRAPPER_SEL)
23131                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
23132                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
23133            }
23134        }
23135
23136        /**
23137        * Removes the auto scrolling for touch devices.
23138        */
23139        function removeTouchHandler(){
23140            if(isTouchDevice || isTouch){
23141                $(WRAPPER_SEL)
23142                    .off(events.touchstart)
23143                    .off(events.touchmove);
23144            }
23145        }
23146
23147        /*
23148        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
23149        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
23150        */
23151        function getMSPointer(){
23152            var pointer;
23153
23154            //IE >= 11 & rest of browsers
23155            if(window.PointerEvent){
23156                pointer = { down: 'pointerdown', move: 'pointermove'};
23157            }
23158
23159            //IE < 11
23160            else{
23161                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
23162            }
23163
23164            return pointer;
23165        }
23166
23167        /**
23168        * Gets the pageX and pageY properties depending on the browser.
23169        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
23170        */
23171        function getEventsPage(e){
23172            var events = [];
23173
23174            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
23175            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
23176
23177            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
23178            if(isTouch && isReallyTouch(e) && options.scrollBar){
23179                events.y = e.touches[0].pageY;
23180                events.x = e.touches[0].pageX;
23181            }
23182
23183            return events;
23184        }
23185
23186        /**
23187        * Slides silently (with no animation) the active slider to the given slide.
23188        * @param noCallback {bool} true or defined -> no callbacks
23189        */
23190        function silentLandscapeScroll(activeSlide, noCallbacks){
23191            setScrollingSpeed (0, 'internal');
23192
23193            if(typeof noCallbacks !== 'undefined'){
23194                //preventing firing callbacks afterSlideLoad etc.
23195                isResizing = true;
23196            }
23197
23198            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
23199
23200            if(typeof noCallbacks !== 'undefined'){
23201                isResizing = false;
23202            }
23203
23204            setScrollingSpeed(originals.scrollingSpeed, 'internal');
23205        }
23206
23207        /**
23208        * Scrolls silently (with no animation) the page to the given Y position.
23209        */
23210        function silentScroll(top){
23211            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
23212            // that's why we round it to 0.
23213            var roundedTop = Math.round(top);
23214
23215            if (options.css3 && options.autoScrolling && !options.scrollBar){
23216                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
23217                transformContainer(translate3d, false);
23218            }
23219            else if(options.autoScrolling && !options.scrollBar){
23220                container.css('top', -roundedTop);
23221            }
23222            else{
23223                $htmlBody.scrollTop(roundedTop);
23224            }
23225        }
23226
23227        /**
23228        * Returns the cross-browser transform string.
23229        */
23230        function getTransforms(translate3d){
23231            return {
23232                '-webkit-transform': translate3d,
23233                '-moz-transform': translate3d,
23234                '-ms-transform':translate3d,
23235                'transform': translate3d
23236            };
23237        }
23238
23239        /**
23240        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
23241        * @type  m (mouse) or k (keyboard)
23242        */
23243        function setIsScrollAllowed(value, direction, type){
23244            switch (direction){
23245                case 'up': isScrollAllowed[type].up = value; break;
23246                case 'down': isScrollAllowed[type].down = value; break;
23247                case 'left': isScrollAllowed[type].left = value; break;
23248                case 'right': isScrollAllowed[type].right = value; break;
23249                case 'all':
23250                    if(type == 'm'){
23251                        setAllowScrolling(value);
23252                    }else{
23253                        setKeyboardScrolling(value);
23254                    }
23255            }
23256        }
23257
23258        /*
23259        * Destroys fullpage.js plugin events and optinally its html markup and styles
23260        */
23261        function destroy(all){
23262            setAutoScrolling(false, 'internal');
23263            setAllowScrolling(false);
23264            setKeyboardScrolling(false);
23265            container.addClass(DESTROYED);
23266
23267            clearTimeout(afterSlideLoadsId);
23268            clearTimeout(afterSectionLoadsId);
23269            clearTimeout(resizeId);
23270            clearTimeout(scrollId);
23271            clearTimeout(scrollId2);
23272
23273            $window
23274                .off('scroll', scrollHandler)
23275                .off('hashchange', hashChangeHandler)
23276                .off('resize', resizeHandler);
23277
23278            $document
23279                .off('click touchstart', SECTION_NAV_SEL + ' a')
23280                .off('mouseenter', SECTION_NAV_SEL + ' li')
23281                .off('mouseleave', SECTION_NAV_SEL + ' li')
23282                .off('click touchstart', SLIDES_NAV_LINK_SEL)
23283                .off('mouseover', options.normalScrollElements)
23284                .off('mouseout', options.normalScrollElements);
23285
23286            $(SECTION_SEL)
23287                .off('click touchstart', SLIDES_ARROW_SEL);
23288
23289            clearTimeout(afterSlideLoadsId);
23290            clearTimeout(afterSectionLoadsId);
23291
23292            //lets make a mess!
23293            if(all){
23294                destroyStructure();
23295            }
23296        }
23297
23298        /*
23299        * Removes inline styles added by fullpage.js
23300        */
23301        function destroyStructure(){
23302            //reseting the `top` or `translate` properties to 0
23303            silentScroll(0);
23304
23305            //loading all the lazy load content
23306            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
23307                setSrc($(this), 'src');
23308            });
23309
23310            container.find('img[data-srcset]').each(function(){
23311                setSrc($(this), 'srcset');
23312            });
23313
23314            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
23315
23316            //removing inline styles
23317            $(SECTION_SEL).css( {
23318                'height': '',
23319                'background-color' : '',
23320                'padding': ''
23321            });
23322
23323            $(SLIDE_SEL).css( {
23324                'width': ''
23325            });
23326
23327            container.css({
23328                'height': '',
23329                'position': '',
23330                '-ms-touch-action': '',
23331                'touch-action': ''
23332            });
23333
23334            $htmlBody.css({
23335                'overflow': '',
23336                'height': ''
23337            });
23338
23339            // remove .fp-enabled class
23340            $('html').removeClass(ENABLED);
23341
23342            // remove .fp-responsive class
23343            $body.removeClass(RESPONSIVE);
23344
23345            // remove all of the .fp-viewing- classes
23346            $.each($body.get(0).className.split(/\s+/), function (index, className) {
23347                if (className.indexOf(VIEWING_PREFIX) === 0) {
23348                    $body.removeClass(className);
23349                }
23350            });
23351
23352            //removing added classes
23353            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
23354                options.scrollOverflowHandler.remove($(this));
23355                $(this).removeClass(TABLE + ' ' + ACTIVE);
23356            });
23357
23358            removeAnimation(container);
23359
23360            //Unwrapping content
23361            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
23362                //unwrap not being use in case there's no child element inside and its just text
23363                $(this).replaceWith(this.childNodes);
23364            });
23365
23366            //removing the applied transition from the fullpage wrapper
23367            container.css({
23368                '-webkit-transition': 'none',
23369                'transition': 'none'
23370            });
23371
23372            //scrolling the page to the top with no animation
23373            $htmlBody.scrollTop(0);
23374
23375            //removing selectors
23376            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
23377            $.each(usedSelectors, function(index, value){
23378                $('.' + value).removeClass(value);
23379            });
23380        }
23381
23382        /*
23383        * Sets the state for a variable with multiple states (original, and temporal)
23384        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
23385        * This function is used to keep track of both states, the original and the temporal one.
23386        * If type is not 'internal', then we assume the user is globally changing the variable.
23387        */
23388        function setVariableState(variable, value, type){
23389            options[variable] = value;
23390            if(type !== 'internal'){
23391                originals[variable] = value;
23392            }
23393        }
23394
23395        /**
23396        * Displays warnings
23397        */
23398        function displayWarnings(){
23399            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
23400            //UNCODE.addition
23401            // if($('html').hasClass(ENABLED)){
23402            //     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
23403            //     return;
23404            // }
23405
23406            // Disable mutually exclusive settings
23407            //UNCODE.addition
23408            // if (options.continuousVertical &&
23409            //     (options.loopTop || options.loopBottom)) {
23410            //     options.continuousVertical = false;
23411            //     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
23412            // }
23413
23414            // if(options.scrollBar && options.scrollOverflow){
23415            //     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
23416            // }
23417
23418            // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
23419            //     options.continuousVertical = false;
23420            //     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
23421            // }
23422
23423            //using extensions? Wrong file!
23424            $.each(extensions, function(index, extension){
23425                //is the option set to true?
23426                if(options[extension]){
23427                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
23428                }
23429            });
23430
23431            //anchors can not have the same value as any element ID or NAME
23432            $.each(options.anchors, function(index, name){
23433
23434                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
23435                var nameAttr = $document.find('[name]').filter(function() {
23436                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
23437                });
23438
23439                var idAttr = $document.find('[id]').filter(function() {
23440                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
23441                });
23442
23443                if(idAttr.length || nameAttr.length ){
23444                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
23445                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
23446                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
23447                }
23448            });
23449        }
23450
23451        /**
23452        * Shows a message in the console of the given type.
23453        */
23454        function showError(type, text){
23455            console && console[type] && console[type]('fullPage: ' + text);
23456        }
23457
23458    }; //end of $.fn.fullpage
23459
23460    if(typeof IScroll !== 'undefined'){
23461        /*
23462        * Turns iScroll `mousewheel` option off dynamically
23463        * https://github.com/cubiq/iscroll/issues/1036
23464        */
23465        IScroll.prototype.wheelOn = function () {
23466            this.wrapper.addEventListener('wheel', this);
23467            this.wrapper.addEventListener('mousewheel', this);
23468            this.wrapper.addEventListener('DOMMouseScroll', this);
23469        };
23470
23471        /*
23472        * Turns iScroll `mousewheel` option on dynamically
23473        * https://github.com/cubiq/iscroll/issues/1036
23474        */
23475        IScroll.prototype.wheelOff = function () {
23476            this.wrapper.removeEventListener('wheel', this);
23477            this.wrapper.removeEventListener('mousewheel', this);
23478            this.wrapper.removeEventListener('DOMMouseScroll', this);
23479        };
23480    }
23481
23482    /**
23483     * An object to handle overflow scrolling.
23484     * This uses jquery.slimScroll to accomplish overflow scrolling.
23485     * It is possible to pass in an alternate scrollOverflowHandler
23486     * to the fullpage.js option that implements the same functions
23487     * as this handler.
23488     *
23489     * @type {Object}
23490     */
23491    var iscrollHandler = {
23492        refreshId: null,
23493        iScrollInstances: [],
23494
23495        // Enables or disables the mouse wheel for the active section or all slides in it
23496        toggleWheel: function(value){
23497            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
23498            scrollable.each(function(){
23499                var iScrollInstance = $(this).data('iscrollInstance');
23500                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
23501                    if(value){
23502                        iScrollInstance.wheelOn();
23503                    }
23504                    else{
23505                        iScrollInstance.wheelOff();
23506                    }
23507                }
23508            });
23509        },
23510
23511        /**
23512        * Turns off iScroll for the destination section.
23513        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
23514        * scroll the destination section/slide before the sections animations ends.
23515        */
23516        onLeave: function(){
23517            iscrollHandler.toggleWheel(false);
23518        },
23519
23520        // Turns off iScroll for the leaving section
23521        beforeLeave: function(){
23522            iscrollHandler.onLeave()
23523        },
23524
23525        // Turns on iScroll on section load
23526        afterLoad: function(){
23527            iscrollHandler.toggleWheel(true);
23528        },
23529
23530        /**
23531         * Called when overflow scrolling is needed for a section.
23532         *
23533         * @param  {Object} element      jQuery object containing current section
23534         * @param  {Number} scrollHeight Current window height in pixels
23535         */
23536        create: function(element, scrollHeight) {
23537            var scrollable = element.find(SCROLLABLE_SEL);
23538
23539            scrollable.height(scrollHeight);
23540            scrollable.each(function() {
23541                var $this = $(this);
23542                var iScrollInstance = $this.data('iscrollInstance');
23543                if (iScrollInstance) {
23544                    $.each(iscrollHandler.iScrollInstances, function(){
23545                        $(this).destroy();
23546                    });
23547                }
23548
23549                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
23550                iscrollHandler.iScrollInstances.push(iScrollInstance);
23551
23552                //off by default until the section gets active
23553                iScrollInstance.wheelOff();
23554
23555                $this.data('iscrollInstance', iScrollInstance);
23556            });
23557        },
23558
23559        /**
23560         * Return a boolean depending on whether the scrollable element is a
23561         * the end or at the start of the scrolling depending on the given type.
23562         *
23563         * @param  {String}  type       Either 'top' or 'bottom'
23564         * @param  {Object}  scrollable jQuery object for the scrollable element
23565         * @return {Boolean}
23566         */
23567        isScrolled: function(type, scrollable) {
23568            var scroller = scrollable.data('iscrollInstance');
23569
23570            //no scroller?
23571            if (!scroller) {
23572                return true;
23573            }
23574
23575            if (type === 'top') {
23576                return scroller.y >= 0 && !scrollable.scrollTop();
23577            } else if (type === 'bottom') {
23578                return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
23579            }
23580        },
23581
23582        /**
23583         * Returns the scrollable element for the given section.
23584         * If there are landscape slides, will only return a scrollable element
23585         * if it is in the active slide.
23586         *
23587         * @param  {Object}  activeSection jQuery object containing current section
23588         * @return {Boolean}
23589         */
23590        scrollable: function(activeSection){
23591            // if there are landscape slides, we check if the scrolling bar is in the current one or not
23592            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
23593                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
23594            }
23595            return activeSection.find(SCROLLABLE_SEL);
23596        },
23597
23598        /**
23599         * Returns the scroll height of the wrapped content.
23600         * If this is larger than the window height minus section padding,
23601         * overflow scrolling is needed.
23602         *
23603         * @param  {Object} element jQuery object containing current section
23604         * @return {Number}
23605         */
23606        scrollHeight: function(element) {
23607            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
23608        },
23609
23610        /**
23611         * Called when overflow scrolling is no longer needed for a section.
23612         *
23613         * @param  {Object} element      jQuery object containing current section
23614         */
23615        remove: function(element) {
23616            var scrollable = element.find(SCROLLABLE_SEL);
23617            if (scrollable.length) {
23618                var iScrollInstance = scrollable.data('iscrollInstance');
23619                iScrollInstance.destroy();
23620
23621                scrollable.data('iscrollInstance', null);
23622            }
23623            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
23624        },
23625
23626        /**
23627         * Called when overflow scrolling has already been setup but the
23628         * window height has potentially changed.
23629         *
23630         * @param  {Object}
vendor: 16,384 bytes, lines 23630-24181
23630 element      jQuery object containing current section
23631         * @param  {Number} scrollHeight Current window height in pixels
23632         */
23633        update: function(element, scrollHeight) {
23634            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
23635            //short period of time.
23636            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
23637            clearTimeout(iscrollHandler.refreshId);
23638            iscrollHandler.refreshId = setTimeout(function(){
23639                $.each(iscrollHandler.iScrollInstances, function(){
23640                    $(this).get(0).refresh();
23641                });
23642            }, 150);
23643
23644            //updating the wrappers height
23645            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
23646        },
23647
23648        /**
23649         * Called to get any additional elements needed to wrap the section
23650         * content in order to facilitate overflow scrolling.
23651         *
23652         * @return {String|Object} Can be a string containing HTML,
23653         *                         a DOM element, or jQuery object.
23654         */
23655        wrapContent: function() {
23656            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
23657        }
23658    };
23659});
23660
23661/* ========================================================================
23662 * Bootstrap: collapse.js v3.1.1
23663 * http://getbootstrap.com/javascript/#collapse
23664 * ========================================================================
23665 * Copyright 2011-2014 Twitter, Inc.
23666 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
23667 * ======================================================================== */
23668
23669
23670+function ($) {
23671	'use strict';
23672
23673	// COLLAPSE PUBLIC CLASS DEFINITION
23674	// ================================
23675
23676	var Collapse = function (element, options) {
23677		this.$element      = $(element)
23678		this.options       = $.extend({}, Collapse.DEFAULTS, options)
23679		this.transitioning = null
23680
23681		if (this.options.parent) this.$parent = $(this.options.parent)
23682		if (this.options.toggle) this.toggle()
23683	}
23684
23685	Collapse.DEFAULTS = {
23686		toggle: true
23687	}
23688
23689	Collapse.prototype.dimension = function () {
23690		var hasWidth = this.$element.hasClass('width')
23691		return hasWidth ? 'width' : 'height'
23692	}
23693
23694	Collapse.prototype.show = function () {
23695		if (this.transitioning || this.$element.hasClass('in')) return
23696
23697		var startEvent = $.Event('show.bs.collapse')
23698		this.$element.trigger(startEvent)
23699		if (startEvent.isDefaultPrevented()) return
23700
23701		var actives = this.$parent && this.$parent.find('> .panel > .in')
23702
23703		if (actives && actives.length) {
23704			var hasData = actives.data('bs.collapse')
23705			if (hasData && hasData.transitioning) return
23706			actives.collapse('hide')
23707			hasData || actives.data('bs.collapse', null)
23708		}
23709
23710		var dimension = this.dimension()
23711
23712		this.$element
23713			.removeClass('collapse')
23714			.addClass('collapsing')[dimension](0)
23715
23716		this.transitioning = 1
23717
23718		var complete = function (e) {
23719			if (e && e.target != this.$element[0]) return
23720			this.$element
23721				.removeClass('collapsing')
23722				.addClass('collapse in')[dimension]('auto')
23723			this.transitioning = 0
23724			this.$element.trigger('shown.bs.collapse')
23725		}
23726
23727		if (!$.support.transition) return complete.call(this)
23728
23729		var scrollSize = $.camelCase(['scroll', dimension].join('-'))
23730
23731		this.$element
23732			.one($.support.transition.end, $.proxy(complete, this))
23733			.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
23734	}
23735
23736	Collapse.prototype.hide = function () {
23737		if (this.transitioning || !this.$element.hasClass('in')) return
23738
23739		var startEvent = $.Event('hide.bs.collapse')
23740		this.$element.trigger(startEvent)
23741		if (startEvent.isDefaultPrevented()) return
23742
23743		var dimension = this.dimension()
23744
23745		this.$element[dimension](this.$element[dimension]())[0].offsetHeight
23746
23747		this.$element
23748			.addClass('collapsing')
23749			.removeClass('collapse')
23750			.removeClass('in')
23751
23752		this.transitioning = 1
23753
23754		var complete = function (e) {
23755			if (e && e.target != this.$element[0]) return
23756			this.transitioning = 0
23757			this.$element
23758				.trigger('hidden.bs.collapse')
23759				.removeClass('collapsing')
23760				.addClass('collapse')
23761		}
23762
23763		if (!$.support.transition) return complete.call(this)
23764
23765		this.$element
23766			[dimension](0)
23767			.one($.support.transition.end, $.proxy(complete, this))
23768			.emulateTransitionEnd(350)
23769	}
23770
23771	Collapse.prototype.toggle = function () {
23772		this[this.$element.hasClass('in') ? 'hide' : 'show']()
23773	}
23774
23775
23776	// COLLAPSE PLUGIN DEFINITION
23777	// ==========================
23778
23779	var old = $.fn.collapse
23780
23781	$.fn.collapse = function (option) {
23782		return this.each(function () {
23783			var $this   = $(this)
23784			var data    = $this.data('bs.collapse')
23785			var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
23786
23787			if (!data && options.toggle && option == 'show') option = !option
23788			if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
23789			if (typeof option == 'string') data[option]()
23790		})
23791	}
23792
23793	$.fn.collapse.Constructor = Collapse
23794
23795
23796	// COLLAPSE NO CONFLICT
23797	// ====================
23798
23799	$.fn.collapse.noConflict = function () {
23800		$.fn.collapse = old
23801		return this
23802	}
23803
23804
23805	// COLLAPSE DATA-API
23806	// =================
23807
23808	$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
23809		var $this   = $(this), href
23810		var target  = $this.attr('data-target')
23811				|| e.preventDefault()
23812				|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
23813		//Edited by Uncode to replace ID in panel [START]
23814		var _target = href.replace(/^#/, "");
23815		if ( $('[data-id="' + _target + '"]').length ) {
23816			var $target = $('[data-id="' + _target + '"]')
23817		} else {
23818			var $target = $(target)
23819		}
23820		//Edited by Uncode to replace ID in panel [END]
23821		var data    = $target.data('bs.collapse')
23822		var option  = data ? 'toggle' : $this.data()
23823		var parent  = $this.attr('data-parent')
23824		var $parent = parent && $(parent)
23825
23826		if (!data || !data.transitioning) {
23827			if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
23828			$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
23829		}
23830
23831		$target.collapse(option)
23832	})
23833
23834}(jQuery);
23835
23836/* ========================================================================
23837 * Bootstrap: tab.js v3.1.1
23838 * http://getbootstrap.com/javascript/#tabs
23839 * ========================================================================
23840 * Copyright 2011-2014 Twitter, Inc.
23841 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
23842 * ======================================================================== */
23843
23844
23845+function ($) {
23846  'use strict';
23847
23848  // TAB CLASS DEFINITION
23849  // ====================
23850
23851  var Tab = function (element) {
23852    this.element = $(element)
23853  }
23854
23855  Tab.prototype.show = function () {
23856    var $this    = this.element
23857    var $ul      = $this.closest('ul:not(.dropdown-menu)')
23858    var selector = $this.data('target')
23859
23860    if (!selector) {
23861      selector = $this.attr('href')
23862      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
23863    }
23864
23865    if ($this.parent('li').hasClass('active')) return
23866
23867    var previous = $ul.find('.active:last a')[0]
23868    var e        = $.Event('show.bs.tab', {
23869      relatedTarget: previous
23870    })
23871
23872    $this.trigger(e)
23873
23874    if (e.isDefaultPrevented()) return
23875
23876    //Edited by Uncode to replace ID in panel [START]
23877    var _target = selector.replace(/^#/, "");
23878    if ( $('[data-id="' + _target + '"]').length )
23879      var $target = $('[data-id="' + _target + '"]')
23880    else
23881      var $target = $(selector)
23882    //Edited by Uncode to replace ID in panel [END]
23883
23884    this.activate($this.parent('li'), $ul)
23885    this.activate($target, $target.parent(), function () {
23886      $this.trigger({
23887        type: 'shown.bs.tab',
23888        relatedTarget: previous
23889      })
23890    })
23891  }
23892
23893  Tab.prototype.activate = function (element, container, callback) {
23894    var $active    = container.find('> .active')
23895    var transition = callback
23896      && $.support.transition
23897      && $active.hasClass('fade')
23898
23899    function next() {
23900      $active
23901        .removeClass('active')
23902        .find('> .dropdown-menu > .active')
23903        .removeClass('active')
23904
23905      element.addClass('active')
23906
23907      if (transition) {
23908        element[0].offsetWidth // reflow for transition
23909        element.addClass('in')
23910      } else {
23911        element.removeClass('fade')
23912      }
23913
23914      if (element.parent('.dropdown-menu')) {
23915        element.closest('li.dropdown').addClass('active')
23916      }
23917
23918      callback && callback()
23919    }
23920
23921    transition ?
23922      $active
23923        .one($.support.transition.end, next)
23924        .emulateTransitionEnd(150) :
23925      next()
23926
23927    $active.removeClass('in')
23928  }
23929
23930
23931  // TAB PLUGIN DEFINITION
23932  // =====================
23933
23934  var old = $.fn.tab
23935
23936  $.fn.tab = function ( option ) {
23937    return this.each(function () {
23938      var $this = $(this)
23939      var data  = $this.data('bs.tab')
23940
23941      if (!data) $this.data('bs.tab', (data = new Tab(this)))
23942      if (typeof option == 'string') data[option]()
23943    })
23944  }
23945
23946  $.fn.tab.Constructor = Tab
23947
23948
23949  // TAB NO CONFLICT
23950  // ===============
23951
23952  $.fn.tab.noConflict = function () {
23953    $.fn.tab = old
23954    return this
23955  }
23956
23957
23958  // TAB DATA-API
23959  // ============
23960
23961  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
23962    e.preventDefault()
23963    $(this).tab('show')
23964  })
23965
23966}(jQuery);
23967
23968/* ========================================================================
23969 * Bootstrap: tooltip.js v3.1.1
23970 * http://getbootstrap.com/javascript/#tooltip
23971 * Inspired by the original jQuery.tipsy by Jason Frame
23972 * ========================================================================
23973 * Copyright 2011-2014 Twitter, Inc.
23974 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
23975 * ======================================================================== */
23976
23977
23978+function ($) {
23979  'use strict';
23980
23981  // TOOLTIP PUBLIC CLASS DEFINITION
23982  // ===============================
23983
23984  var Tooltip = function (element, options) {
23985    this.type       =
23986    this.options    =
23987    this.enabled    =
23988    this.timeout    =
23989    this.hoverState =
23990    this.$element   = null
23991
23992    this.init('tooltip', element, options)
23993  }
23994
23995  Tooltip.DEFAULTS = {
23996    animation: true,
23997    placement: 'top',
23998    selector: false,
23999    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
24000    trigger: 'hover focus',
24001    title: '',
24002    delay: 0,
24003    html: false,
24004    container: false,
24005    viewport: {
24006      selector: 'body',
24007      padding: 0
24008    }
24009  }
24010
24011  Tooltip.prototype.init = function (type, element, options) {
24012    this.enabled   = true
24013    this.type      = type
24014    this.$element  = $(element)
24015    this.options   = this.getOptions(options)
24016    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
24017
24018    var triggers = this.options.trigger.split(' ')
24019
24020    for (var i = triggers.length; i--;) {
24021      var trigger = triggers[i]
24022
24023      if (trigger == 'click') {
24024        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
24025      } else if (trigger != 'manual') {
24026        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
24027        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
24028
24029        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
24030        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
24031      }
24032    }
24033
24034    this.options.selector ?
24035      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
24036      this.fixTitle()
24037  }
24038
24039  Tooltip.prototype.getDefaults = function () {
24040    return Tooltip.DEFAULTS
24041  }
24042
24043  Tooltip.prototype.getOptions = function (options) {
24044    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
24045
24046    if (options.delay && typeof options.delay == 'number') {
24047      options.delay = {
24048        show: options.delay,
24049        hide: options.delay
24050      }
24051    }
24052
24053    return options
24054  }
24055
24056  Tooltip.prototype.getDelegateOptions = function () {
24057    var options  = {}
24058    var defaults = this.getDefaults()
24059
24060    this._options && $.each(this._options, function (key, value) {
24061      if (defaults[key] != value) options[key] = value
24062    })
24063
24064    return options
24065  }
24066
24067  Tooltip.prototype.enter = function (obj) {
24068    var self = obj instanceof this.constructor ?
24069      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
24070
24071    clearTimeout(self.timeout)
24072
24073    self.hoverState = 'in'
24074
24075    if (!self.options.delay || !self.options.delay.show) return self.show()
24076
24077    self.timeout = setTimeout(function () {
24078      if (self.hoverState == 'in') self.show()
24079    }, self.options.delay.show)
24080  }
24081
24082  Tooltip.prototype.leave = function (obj) {
24083    var self = obj instanceof this.constructor ?
24084      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
24085
24086    clearTimeout(self.timeout)
24087
24088    self.hoverState = 'out'
24089
24090    if (!self.options.delay || !self.options.delay.hide) return self.hide()
24091
24092    self.timeout = setTimeout(function () {
24093      if (self.hoverState == 'out') self.hide()
24094    }, self.options.delay.hide)
24095  }
24096
24097  Tooltip.prototype.show = function () {
24098    var e = $.Event('show.bs.' + this.type)
24099
24100    if (this.hasContent() && this.enabled) {
24101      this.$element.trigger(e)
24102
24103      if (e.isDefaultPrevented()) return
24104      var that = this;
24105
24106      var $tip = this.tip()
24107
24108      this.setContent()
24109
24110      if (this.options.animation) $tip.addClass('fade')
24111
24112      var placement = typeof this.options.placement == 'function' ?
24113        this.options.placement.call(this, $tip[0], this.$element[0]) :
24114        this.options.placement
24115
24116      var autoToken = /\s?auto?\s?/i
24117      var autoPlace = autoToken.test(placement)
24118      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
24119
24120      $tip
24121        .detach()
24122        .css({ top: 0, left: 0, display: 'block' })
24123        .addClass(placement)
24124
24125      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
24126
24127      var pos          = this.getPosition()
24128      var actualWidth  = $tip[0].offsetWidth
24129      var actualHeight = $tip[0].offsetHeight
24130
24131      if (autoPlace) {
24132        var orgPlacement = placement
24133        var $parent      = this.$element.parent()
24134        var parentDim    = this.getPosition($parent)
24135
24136        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
24137                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
24138                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
24139                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
24140                    placement
24141
24142        $tip
24143          .removeClass(orgPlacement)
24144          .addClass(placement)
24145      }
24146
24147      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
24148
24149      this.applyPlacement(calculatedOffset, placement)
24150      this.hoverState = null
24151
24152      var complete = function() {
24153        that.$element.trigger('shown.bs.' + that.type)
24154      }
24155
24156      $.support.transition && this.$tip.hasClass('fade') ?
24157        $tip
24158          .one($.support.transition.end, complete)
24159          .emulateTransitionEnd(150) :
24160        complete()
24161    }
24162  }
24163
24164  Tooltip.prototype.applyPlacement = function (offset, placement) {
24165    var $tip   = this.tip()
24166    var width  = $tip[0].offsetWidth
24167    var height = $tip[0].offsetHeight
24168
24169    // manually read margins because getBoundingClientRect includes difference
24170    var marginTop = parseInt($tip.css('margin-top'), 10)
24171    var marginLeft = parseInt($tip.css('margin-left'), 10)
24172
24173    // we must check for NaN for ie 8/9
24174    if (isNaN(marginTop))  marginTop  = 0
24175    if (isNaN(marginLeft)) marginLeft = 0
24176
24177    offset.top  = offset.top  + marginTop
24178    offset.left = offset.left + marginLeft
24179
24180    // $.fn.offset doesn't round pixel values
24181    // so we use setOff
24181set directly with our own function B-0
24182    $.offset.setOffset($tip[0], $.extend({
24183      using: function (props) {
24184        $tip.css({
24185          top: Math.round(props.top),
24186          left: Math.round(props.left)
24187        })
24188      }
24189    }, offset), 0)
24190
24191    $tip.addClass('in')
24192
24193    // check to see if placing tip in new offset caused the tip to resize itself
24194    var actualWidth  = $tip[0].offsetWidth
24195    var actualHeight = $tip[0].offsetHeight
24196
24197    if (placement == 'top' && actualHeight != height) {
24198      offset.top = offset.top + height - actualHeight
24199    }
24200
24201    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
24202
24203    if (delta.left) offset.left += delta.left
24204    else offset.top += delta.top
24205
24206    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
24207    var arrowPosition       = delta.left ? 'left'        : 'top'
24208    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
24209
24210    $tip.offset(offset)
24211    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
24212  }
24213
24214  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
24215    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
24216  }
24217
24218  Tooltip.prototype.setContent = function () {
24219    var $tip  = this.tip()
24220    var title = this.getTitle()
24221
24222    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
24223    $tip.removeClass('fade in top bottom left right')
24224  }
24225
24226  Tooltip.prototype.hide = function () {
24227    var that = this
24228    var $tip = this.tip()
24229    var e    = $.Event('hide.bs.' + this.type)
24230
24231    function complete() {
24232      if (that.hoverState != 'in') $tip.detach()
24233      that.$element.trigger('hidden.bs.' + that.type)
24234    }
24235
24236    this.$element.trigger(e)
24237
24238    if (e.isDefaultPrevented()) return
24239
24240    $tip.removeClass('in')
24241
24242    $.support.transition && this.$tip.hasClass('fade') ?
24243      $tip
24244        .one($.support.transition.end, complete)
24245        .emulateTransitionEnd(150) :
24246      complete()
24247
24248    this.hoverState = null
24249
24250    return this
24251  }
24252
24253  Tooltip.prototype.fixTitle = function () {
24254    var $e = this.$element
24255    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
24256      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
24257    }
24258  }
24259
24260  Tooltip.prototype.hasContent = function () {
24261    return this.getTitle()
24262  }
24263
24264  Tooltip.prototype.getPosition = function ($element) {
24265    $element   = $element || this.$element
24266    var el     = $element[0]
24267    var isBody = el.tagName == 'BODY'
24268    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
24269      scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
24270      width:  isBody ? $(window).width()  : $element.outerWidth(),
24271      height: isBody ? $(window).height() : $element.outerHeight()
24272    }, isBody ? {top: 0, left: 0} : $element.offset())
24273  }
24274
24275  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
24276    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
24277           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
24278           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
24279        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
24280
24281  }
24282
24283  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
24284    var delta = { top: 0, left: 0 }
24285    if (!this.$viewport) return delta
24286
24287    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
24288    var viewportDimensions = this.getPosition(this.$viewport)
24289
24290    if (/right|left/.test(placement)) {
24291      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
24292      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
24293      if (topEdgeOffset < viewportDimensions.top) { // top overflow
24294        delta.top = viewportDimensions.top - topEdgeOffset
24295      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
24296        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
24296EdgeOffset
24297      }
24298    } else {
24299      var leftEdgeOffset  = pos.left - viewportPadding
24300      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
24301      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
24302        delta.left = viewportDimensions.left - leftEdgeOffset
24303      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
24304        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
24305      }
24306    }
24307
24308    return delta
24309  }
24310
24311  Tooltip.prototype.getTitle = function () {
24312    var title
24313    var $e = this.$element
24314    var o  = this.options
24315
24316    title = $e.attr('data-original-title')
24317      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
24318
24319    return title
24320  }
24321
24322  Tooltip.prototype.tip = function () {
24323    return this.$tip = this.$tip || $(this.options.template)
24324  }
24325
24326  Tooltip.prototype.arrow = function () {
24327    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
24328  }
24329
24330  Tooltip.prototype.validate = function () {
24331    if (!this.$element[0].parentNode) {
24332      this.hide()
24333      this.$element = null
24334      this.options  = null
24335    }
24336  }
24337
24338  Tooltip.prototype.enable = function () {
24339    this.enabled = true
24340  }
24341
24342  Tooltip.prototype.disable = function () {
24343    this.enabled = false
24344  }
24345
24346  Tooltip.prototype.toggleEnabled = function () {
24347    this.enabled = !this.enabled
24348  }
24349
24350  Tooltip.prototype.toggle = function (e) {
24351    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
24352    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
24353  }
24354
24355  Tooltip.prototype.destroy = function () {
24356    clearTimeout(this.timeout)
24357    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
24358  }
24359
24360
24361  // TOOLTIP PLUGIN DEFINITION
24362  // =========================
24363
24364  var old = $.fn.tooltip
24365
24366  $.fn.tooltip = function (option) {
24367    return this.each(function () {
24368      var $this   = $(this)
24369      var data    = $this.data('bs.tooltip')
24370      var options = typeof option == 'object' && option
24371
24372      if (!data && option == 'destroy') return
24373      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
24374      if (typeof option == 'string') data[option]()
24375    })
24376  }
24377
24378  $.fn.tooltip.Constructor = Tooltip
24379
24380
24381  // TOOLTIP NO CONFLICT
24382  // ===================
24383
24384  $.fn.tooltip.noConflict = function () {
24385    $.fn.tooltip = old
24386    return this
24387  }
24388
24389}(jQuery);
24390
24391/* ========================================================================
24392 * Bootstrap: transition.js v3.1.1
24393 * http://getbootstrap.com/javascript/#transitions
24394 * ========================================================================
24395 * Copyright 2011-2014 Twitter, Inc.
24396 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
24397 * ======================================================================== */
24398
24399
24400+function ($) {
24401  'use strict';
24402
24403  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
24404  // ============================================================
24405
24406  function transitionEnd() {
24407    var el = document.createElement('bootstrap')
24408
24409    var transEndEventNames = {
24410      WebkitTransition : 'webkitTransitionEnd',
24411      MozTransition    : 'transitionend',
24412      OTransition      : 'oTransitionEnd otransitionend',
24413      transition       : 'transitionend'
24414    }
24415
24416    for (var name in transEndEventNames) {
24417      if (el.style[name] !== undefined) {
24418        return { end: transEndEventNames[name] }
24419      }
24420    }
24421
24422    return false // explicit for ie8 (  ._.)
24423  }
24424
24425  // http://blog.alexmaccaw.com/css-transitions
24426  $.fn.emulateTransitionEnd = function (duration) {
24427    var called = false, $el = this
24428    $(this).one($.support.transition.end, function () { called = true })
24429    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
24430    setTimeout(callback, duration)
24431    return this
24432  }
24433
24434  $(function () {
24435    $.support.transition = transitionEnd()
24436  })
24437
24438}(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.