PageSourceSearch

https://pfa-auto.fr/wp-content/themes/uncode/library/js/plugins.js?ver=1411309471

js pfa-auto.fr collected 2026-10-02 03:33:50 UTC 780,958 bytes, 22,823 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/*!
293 * Isotope PACKAGED v2.2.2
294 *
295 * Licensed GPLv3 for open source use
296 * or Isotope Commercial License for commercial use
297 *
298 * http://isotope.metafizzy.co
299 * Copyright 2015 Metafizzy
300 */
301
302/**
303 * Bridget makes jQuery widgets
304 * v1.1.0
305 * MIT license
306 */
307
308( function( window ) {
309
310
311
312// -------------------------- utils -------------------------- //
313
314var slice = Array.prototype.slice;
315
316function noop() {}
317
318// -------------------------- definition -------------------------- //
319
320function defineBridget( $ ) {
321
322// bail if no jQuery
323if ( !$ ) {
324  return;
325}
326
327// -------------------------- addOptionMethod -------------------------- //
328
329/**
330 * adds option method -> $().plugin('option', {...})
331 * @param {Function} PluginClass - constructor class
332 */
333function addOptionMethod( PluginClass ) {
334  // don't overwrite original option method
335  if ( PluginClass.prototype.option ) {
336    return;
337  }
338
339  // option setter
340  PluginClass.prototype.option = function( opts ) {
341    // bail out if not an object
342    if ( !$.isPlainObject( opts ) ){
343      return;
344    }
345    this.options = $.extend( true, this.options, opts );
346  };
347}
348
349// -------------------------- plugin bridge -------------------------- //
350
351// helper function for logging errors
352// $.error breaks jQuery chaining
353var logError = typeof console === 'undefined' ? noop :
354  function( message ) {
355    console.error( message );
356  };
357
358/**
359 * jQuery plugin bridge, access methods like $elem.plugin('method')
360 * @param {String} namespace - plugin name
361 * @param {Function} PluginClass - constructor class
362 */
363function bridge( namespace, PluginClass ) {
364  // add to jQuery fn namespace
365  $.fn[ namespace ] = function( options ) {
366    if ( typeof options === 'string' ) {
367      // call plugin method when first argument is a string
368      // get arguments for method
369      var args = slice.call( arguments, 1 );
370
371      for ( var i=0, len = this.length; i < len; i++ ) {
372        var elem = this[i];
373        var instance = $.data( elem, namespace );
374        if ( !instance ) {
375          logError( "cannot call methods on " + namespace + " prior to initialization; " +
376            "attempted to call '" + options + "'" );
377          continue;
378        }
379        if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
380          logError( "no such method '" + options + "' for " + namespace + " instance" );
381          continue;
382        }
383
384        // trigger method with arguments
385        var returnValue = instance[ options ].apply( instance, args );
386
387        // break look and return first value if provided
388        if ( returnValue !== undefined ) {
389          return returnValue;
390        }
391      }
392      // return this if no return value
393      return this;
394    } else {
395      return this.each( function() {
396        var instance = $.data( this, namespace );
397        if ( instance ) {
398          // apply options & init
399          instance.option( options );
400          instance._init();
401        } else {
402          // initialize new instance
403          instance = new PluginClass( this, options );
404          $.data( this, namespace, instance );
405        }
406      });
407    }
408  };
409
410}
411
412// -------------------------- bridget -------------------------- //
413
414/**
415 * converts a Prototypical class into a proper jQuery plugin
416 *   the class must have a ._init method
417 * @param {String} namespace - plugin name, used in $().pluginName
418 * @param {Function} PluginClass - constructor class
419 */
420$.bridget = function( namespace, PluginClass ) {
421  addOptionMethod( PluginClass );
422  bridge( namespace, PluginClass );
423};
424
425return $.bridget;
426
427}
428
429// transport
430if ( typeof define === 'function' && define.amd ) {
431  // AMD
432  define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
433} else if ( typeof exports === 'object' ) {
434  defineBridget( require('jquery') );
435} else {
436  // get jquery from browser global
437  defineBridget( window.jQuery );
438}
439
440})( window );
441
442/*!
443 * eventie v1.0.6
444 * event binding helper
445 *   eventie.bind( elem, 'click', myFn )
446 *   eventie.unbind( elem, 'click', myFn )
447 * MIT license
448 */
449
450/*jshint browser: true, undef: true, unused: true */
451/*global define: false, module: false */
452
453( function( window ) {
454
455
456
457var docElem = document.documentElement;
458
459var bind = function() {};
460
461function getIEEvent( obj ) {
462  var event = window.event;
463  // add event.target
464  event.target = event.target || event.srcElement || obj;
465  return event;
466}
467
468if ( docElem.addEventListener ) {
469  bind = function( obj, type, fn ) {
470    obj.addEventListener( type, fn, false );
471  };
472} else if ( docElem.attachEvent ) {
473  bind = function( obj, type, fn ) {
474    obj[ type + fn ] = fn.handleEvent ?
475      function() {
476        var event = getIEEvent( obj );
477        fn.handleEvent.call( fn, event );
478      } :
479      function() {
480        var event = getIEEvent( obj );
481        fn.call( obj, event );
482      };
483    obj.attachEvent( "on" + type, obj[ type + fn ] );
484  };
485}
486
487var unbind = function() {};
488
489if ( docElem.removeEventListener ) {
490  unbind = function( obj, type, fn ) {
491    obj.removeEventListener( type, fn, false );
492  };
493} else if ( docElem.detachEvent ) {
494  unbind = function( obj, type, fn ) {
495    obj.detachEvent( "on" + type, obj[ type + fn ] );
496    try {
497      delete obj[ type + fn ];
498    } catch ( err ) {
499      // can't delete window object properties
500      obj[ type + fn ] = undefined;
501    }
502  };
503}
504
505var eventie = {
506  bind: bind,
507  unbind: unbind
508};
509
510// ----- module definition ----- //
511
512if ( typeof define === 'function' && define.amd ) {
513  // AMD
514  define( 'eventie/eventie',eventie );
515} else if ( typeof exports === 'object' ) {
516  // CommonJS
517  module.exports = eventie;
518} else {
519  // browser global
520  window.eventie = eventie;
521}
522
523})( window );
524
525/*!
526 * EventEmitter v4.2.11 - git.io/ee
527 * Unlicense - http://unlicense.org/
528 * Oliver Caldwell - http://oli.me.uk/
529 * @preserve
530 */
531
532;(function () {
533    'use strict';
534
535    /**
536     * Class for managing events.
537     * Can be extended to provide event functionality in other classes.
538     *
539     * @class EventEmitter Manages event registering and emitting.
540     */
541    function EventEmitter() {}
542
543    // Shortcuts to improve speed and size
544    var proto = EventEmitter.prototype;
545    var exports = this;
546    var originalGlobalValue = exports.EventEmitter;
547
548    /**
549     * Finds the index of the listener for the event in its storage array.
550     *
551     * @param {Function[]} listeners Array of listeners to search through.
552     * @param {Function} listener Method to look for.
553     * @return {Number} Index of the specified listener, -1 if not found
554     * @api private
555     */
556    function indexOfListener(listeners, listener) {
557        var i = listeners.length;
558        while (i--) {
559            if (listeners[i].listener === listener) {
560                return i;
561            }
562        }
563
564        return -1;
565    }
566
567    /**
568     * Alias a method while keeping the context correct, to allow for over
vendor: 16,384 bytes, lines 568-971
568writing of target method.
569     *
570     * @param {String} name The name of the target method.
571     * @return {Function} The aliased method
572     * @api private
573     */
574    function alias(name) {
575        return function aliasClosure() {
576            return this[name].apply(this, arguments);
577        };
578    }
579
580    /**
581     * Returns the listener array for the specified event.
582     * Will initialise the event object and listener arrays if required.
583     * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
584     * Each property in the object response is an array of listener functions.
585     *
586     * @param {String|RegExp} evt Name of the event to return the listeners from.
587     * @return {Function[]|Object} All listener functions for the event.
588     */
589    proto.getListeners = function getListeners(evt) {
590        var events = this._getEvents();
591        var response;
592        var key;
593
594        // Return a concatenated array of all matching events if
595        // the selector is a regular expression.
596        if (evt instanceof RegExp) {
597            response = {};
598            for (key in events) {
599                if (events.hasOwnProperty(key) && evt.test(key)) {
600                    response[key] = events[key];
601                }
602            }
603        }
604        else {
605            response = events[evt] || (events[evt] = []);
606        }
607
608        return response;
609    };
610
611    /**
612     * Takes a list of listener objects and flattens it into a list of listener functions.
613     *
614     * @param {Object[]} listeners Raw listener objects.
615     * @return {Function[]} Just the listener functions.
616     */
617    proto.flattenListeners = function flattenListeners(listeners) {
618        var flatListeners = [];
619        var i;
620
621        for (i = 0; i < listeners.length; i += 1) {
622            flatListeners.push(listeners[i].listener);
623        }
624
625        return flatListeners;
626    };
627
628    /**
629     * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
630     *
631     * @param {String|RegExp} evt Name of the event to return the listeners from.
632     * @return {Object} All listener functions for an event in an object.
633     */
634    proto.getListenersAsObject = function getListenersAsObject(evt) {
635        var listeners = this.getListeners(evt);
636        var response;
637
638        if (listeners instanceof Array) {
639            response = {};
640            response[evt] = listeners;
641        }
642
643        return response || listeners;
644    };
645
646    /**
647     * Adds a listener function to the specified event.
648     * The listener will not be added if it is a duplicate.
649     * If the listener returns true then it will be removed after it is called.
650     * If you pass a regular expression as the event name then the listener will be added to all events that match it.
651     *
652     * @param {String|RegExp} evt Name of the event to attach the listener to.
653     * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
654     * @return {Object} Current instance of EventEmitter for chaining.
655     */
656    proto.addListener = function addListener(evt, listener) {
657        var listeners = this.getListenersAsObject(evt);
658        var listenerIsWrapped = typeof listener === 'object';
659        var key;
660
661        for (key in listeners) {
662            if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
663                listeners[key].push(listenerIsWrapped ? listener : {
664                    listener: listener,
665                    once: false
666                });
667            }
668        }
669
670        return this;
671    };
672
673    /**
674     * Alias of addListener
675     */
676    proto.on = alias('addListener');
677
678    /**
679     * Semi-alias of addListener. It will add a listener that will be
680     * automatically removed after its first execution.
681     *
682     * @param {String|RegExp} evt Name of the event to attach the listener to.
683     * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
684     * @return {Object} Current instance of EventEmitter for chaining.
685     */
686    proto.addOnceListener = function addOnceListener(evt, listener) {
687        return this.addListener(evt, {
688            listener: listener,
689            once: true
690        });
691    };
692
693    /**
694     * Alias of addOnceListener.
695     */
696    proto.once = alias('addOnceListener');
697
698    /**
699     * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
700     * You need to tell it what event names should be matched by a regex.
701     *
702     * @param {String} evt Name of the event to create.
703     * @return {Object} Current instance of EventEmitter for chaining.
704     */
705    proto.defineEvent = function defineEvent(evt) {
706        this.getListeners(evt);
707        return this;
708    };
709
710    /**
711     * Uses defineEvent to define multiple events.
712     *
713     * @param {String[]} evts An array of event names to define.
714     * @return {Object} Current instance of EventEmitter for chaining.
715     */
716    proto.defineEvents = function defineEvents(evts) {
717        for (var i = 0; i < evts.length; i += 1) {
718            this.defineEvent(evts[i]);
719        }
720        return this;
721    };
722
723    /**
724     * Removes a listener function from the specified event.
725     * When passed a regular expression as the event name, it will remove the listener from all events that match it.
726     *
727     * @param {String|RegExp} evt Name of the event to remove the listener from.
728     * @param {Function} listener Method to remove from the event.
729     * @return {Object} Current instance of EventEmitter for chaining.
730     */
731    proto.removeListener = function removeListener(evt, listener) {
732        var listeners = this.getListenersAsObject(evt);
733        var index;
734        var key;
735
736        for (key in listeners) {
737            if (listeners.hasOwnProperty(key)) {
738                index = indexOfListener(listeners[key], listener);
739
740                if (index !== -1) {
741                    listeners[key].splice(index, 1);
742                }
743            }
744        }
745
746        return this;
747    };
748
749    /**
750     * Alias of removeListener
751     */
752    proto.off = alias('removeListener');
753
754    /**
755     * Adds listeners in bulk using the manipulateListeners method.
756     * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
757     * You can also pass it a regular expression to add the array of listeners to all events that match it.
758     * Yeah, this function does quite a bit. That's probably a bad thing.
759     *
760     * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
761     * @param {Function[]} [listeners] An optional array of listener functions to add.
762     * @return {Object} Current instance of EventEmitter for chaining.
763     */
764    proto.addListeners = function addListeners(evt, listeners) {
765        // Pass through to manipulateListeners
766        return this.manipulateListeners(false, evt, listeners);
767    };
768
769    /**
770     * Removes listeners in bulk using the manipulateListeners method.
771     * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
772     * You can also pass it an event name and an array of listeners to be removed.
773     * You can also pass it a regular expression to remove the listeners from all events that match it.
774     *
775     * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
776     * @param {Function[]} [listeners] An optional array of listener functions to remove.
777     * @return {Object} Current instance of EventEmitter for chaining.
778     */
779    proto.removeListeners = function removeListeners(evt, listeners) {
780        // Pass through to manipulateListeners
781        return this.manipulateListeners(true, evt, listeners);
782    };
783
784    /**
785     * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
786     * The first argument will determine if the listeners are removed (true) or added (false).
787     * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
788     * You can also pass it an event name and an array of listeners to be added/removed.
789     * You can also pass it a regular expression to manipulate the listeners of all events that match it.
790     *
791     * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
792     * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
793     * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
794     * @return {Object} Current instance of EventEmitter for chaining.
795     */
796    proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
797        var i;
798        var value;
799        var single = remove ? this.removeListener : this.addListener;
800        var multiple = remove ? this.removeListeners : this.addListeners;
801
802        // If evt is an object then pass each of its properties to this method
803        if (typeof evt === 'object' && !(evt instanceof RegExp)) {
804            for (i in evt) {
805                if (evt.hasOwnProperty(i) && (value = evt[i])) {
806                    // Pass the single listener straight through to the singular method
807                    if (typeof value === 'function') {
808                        single.call(this, i, value);
809                    }
810                    else {
811                        // Otherwise pass back to the multiple function
812                        multiple.call(this, i, value);
813                    }
814                }
815            }
816        }
817        else {
818            // So evt must be a string
819            // And listeners must be an array of listeners
820            // Loop over it and pass each one to the multiple method
821            i = listeners.length;
822            while (i--) {
823                single.call(this, evt, listeners[i]);
824            }
825        }
826
827        return this;
828    };
829
830    /**
831     * Removes all listeners from a specified event.
832     * If you do not specify an event then all listeners will be removed.
833     * That means every event will be emptied.
834     * You can also pass a regex to remove all events that match it.
835     *
836     * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
837     * @return {Object} Current instance of EventEmitter for chaining.
838     */
839    proto.removeEvent = function removeEvent(evt) {
840        var type = typeof evt;
841        var events = this._getEvents();
842        var key;
843
844        // Remove different things depending on the state of evt
845        if (type === 'string') {
846            // Remove all listeners for the specified event
847            delete events[evt];
848        }
849        else if (evt instanceof RegExp) {
850            // Remove all events matching the regex.
851            for (key in events) {
852                if (events.hasOwnProperty(key) && evt.test(key)) {
853                    delete events[key];
854                }
855            }
856        }
857        else {
858            // Remove all listeners in all events
859            delete this._events;
860        }
861
862        return this;
863    };
864
865    /**
866     * Alias of removeEvent.
867     *
868     * Added to mirror the node API.
869     */
870    proto.removeAllListeners = alias('removeEvent');
871
872    /**
873     * Emits an event of your choice.
874     * When emitted, every listener attached to that event will be executed.
875     * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
876     * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
877     * So they will not arrive within the array on the other side, they will be separate.
878     * You can also pass a regular expression to emit to all events that match it.
879     *
880     * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
881     * @param {Array} [args] Optional array of arguments to be passed to each listener.
882     * @return {Object} Current instance of EventEmitter for chaining.
883     */
884    proto.emitEvent = function emitEvent(evt, args) {
885        var listeners = this.getListenersAsObject(evt);
886        var listener;
887        var i;
888        var key;
889        var response;
890
891        for (key in listeners) {
892            if (listeners.hasOwnProperty(key)) {
893                i = listeners[key].length;
894
895                while (i--) {
896                    // If the listener returns true then it shall be removed from the event
897                    // The function is executed either with a basic call or an apply if there is an args array
898                    listener = listeners[key][i];
899
900                    if (listener.once === true) {
901                        this.removeListener(evt, listener.listener);
902                    }
903
904                    response = listener.listener.apply(this, args || []);
905
906                    if (response === this._getOnceReturnValue()) {
907                        this.removeListener(evt, listener.listener);
908                    }
909                }
910            }
911        }
912
913        return this;
914    };
915
916    /**
917     * Alias of emitEvent
918     */
919    proto.trigger = alias('emitEvent');
920
921    /**
922     * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
923     * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
924     *
925     * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
926     * @param {...*} Optional additional arguments to be passed to each listener.
927     * @return {Object} Current instance of EventEmitter for chaining.
928     */
929    proto.emit = function emit(evt) {
930        var args = Array.prototype.slice.call(arguments, 1);
931        return this.emitEvent(evt, args);
932    };
933
934    /**
935     * Sets the current value to check against when executing listeners. If a
936     * listeners return value matches the one set here then it will be removed
937     * after execution. This value defaults to true.
938     *
939     * @param {*} value The new value to check for when executing listeners.
940     * @return {Object} Current instance of EventEmitter for chaining.
941     */
942    proto.setOnceReturnValue = function setOnceReturnValue(value) {
943        this._onceReturnValue = value;
944        return this;
945    };
946
947    /**
948     * Fetches the current value to check against when executing listeners. If
949     * the listeners return value matches this one then it should be removed
950     * automatically. It will return true by default.
951     *
952     * @return {*|Boolean} The current value to check for or the default, true.
953     * @api private
954     */
955    proto._getOnceReturnValue = function _getOnceReturnValue() {
956        if (this.hasOwnProperty('_onceReturnValue')) {
957            return this._onceReturnValue;
958        }
959        else {
960            return true;
961        }
962    };
963
964    /**
965     * Fetches the events object and creates one if required.
966     *
967     * @return {Object} The events storage object.
968     * @api private
969     */
970    proto._getEvents = function _getEvents() {
971        return this._events || (this
971._events = {});
972    };
973
974    /**
975     * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
976     *
977     * @return {Function} Non conflicting EventEmitter class.
978     */
979    EventEmitter.noConflict = function noConflict() {
980        exports.EventEmitter = originalGlobalValue;
981        return EventEmitter;
982    };
983
984    // Expose the class either via AMD, CommonJS or the global object
985    if (typeof define === 'function' && define.amd) {
986        define('eventEmitter/EventEmitter',[],function () {
987            return EventEmitter;
988        });
989    }
990    else if (typeof module === 'object' && module.exports){
991        module.exports = EventEmitter;
992    }
993    else {
994        exports.EventEmitter = EventEmitter;
995    }
996}.call(this));
997
998/*!
999 * getStyleProperty v1.0.4
1000 * original by kangax
1001 * http://perfectionkills.com/feature-testing-css-properties/
1002 * MIT license
1003 */
1004
1005/*jshint browser: true, strict: true, undef: true */
1006/*global define: false, exports: false, module: false */
1007
1008( function( window ) {
1009
1010
1011
1012var prefixes = 'Webkit Moz ms Ms O'.split(' ');
1013var docElemStyle = document.documentElement.style;
1014
1015function getStyleProperty( propName ) {
1016  if ( !propName ) {
1017    return;
1018  }
1019
1020  // test standard property first
1021  if ( typeof docElemStyle[ propName ] === 'string' ) {
1022    return propName;
1023  }
1024
1025  // capitalize
1026  propName = propName.charAt(0).toUpperCase() + propName.slice(1);
1027
1028  // test vendor specific properties
1029  var prefixed;
1030  for ( var i=0, len = prefixes.length; i < len; i++ ) {
1031    prefixed = prefixes[i] + propName;
1032    if ( typeof docElemStyle[ prefixed ] === 'string' ) {
1033      return prefixed;
1034    }
1035  }
1036}
1037
1038// transport
1039if ( typeof define === 'function' && define.amd ) {
1040  // AMD
1041  define( 'get-style-property/get-style-property',[],function() {
1042    return getStyleProperty;
1043  });
1044} else if ( typeof exports === 'object' ) {
1045  // CommonJS for Component
1046  module.exports = getStyleProperty;
1047} else {
1048  // browser global
1049  window.getStyleProperty = getStyleProperty;
1050}
1051
1052})( window );
1053
1054/*!
1055 * getSize v1.2.2
1056 * measure size of elements
1057 * MIT license
1058 */
1059
1060/*jshint browser: true, strict: true, undef: true, unused: true */
1061/*global define: false, exports: false, require: false, module: false, console: false */
1062
1063( function( window, undefined ) {
1064
1065
1066
1067// -------------------------- helpers -------------------------- //
1068
1069// get a number from a string, not a percentage
1070function getStyleSize( value ) {
1071  var num = parseFloat( value );
1072  // not a percent like '100%', and a number
1073  var isValid = value.indexOf('%') === -1 && !isNaN( num );
1074  return isValid && num;
1075}
1076
1077function noop() {}
1078
1079var logError = typeof console === 'undefined' ? noop :
1080  function( message ) {
1081    console.error( message );
1082  };
1083
1084// -------------------------- measurements -------------------------- //
1085
1086var measurements = [
1087  'paddingLeft',
1088  'paddingRight',
1089  'paddingTop',
1090  'paddingBottom',
1091  'marginLeft',
1092  'marginRight',
1093  'marginTop',
1094  'marginBottom',
1095  'borderLeftWidth',
1096  'borderRightWidth',
1097  'borderTopWidth',
1098  'borderBottomWidth'
1099];
1100
1101function getZeroSize() {
1102  var size = {
1103    width: 0,
1104    height: 0,
1105    innerWidth: 0,
1106    innerHeight: 0,
1107    outerWidth: 0,
1108    outerHeight: 0
1109  };
1110  for ( var i=0, len = measurements.length; i < len; i++ ) {
1111    var measurement = measurements[i];
1112    size[ measurement ] = 0;
1113  }
1114  return size;
1115}
1116
1117
1118
1119function defineGetSize( getStyleProperty ) {
1120
1121// -------------------------- setup -------------------------- //
1122
1123var isSetup = false;
1124
1125var getStyle, boxSizingProp, isBoxSizeOuter;
1126
1127/**
1128 * setup vars and functions
1129 * do it on initial getSize(), rather than on script load
1130 * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
1131 */
1132function setup() {
1133  // setup once
1134  if ( isSetup ) {
1135    return;
1136  }
1137  isSetup = true;
1138
1139  var getComputedStyle = window.getComputedStyle;
1140  getStyle = ( function() {
1141    var getStyleFn = getComputedStyle ?
1142      function( elem ) {
1143        return getComputedStyle( elem, null );
1144      } :
1145      function( elem ) {
1146        return elem.currentStyle;
1147      };
1148
1149      return function getStyle( elem ) {
1150        var style = getStyleFn( elem );
1151        if ( !style ) {
1152          logError( 'Style returned ' + style +
1153            '. Are you running this code in a hidden iframe on Firefox? ' +
1154            'See http://bit.ly/getsizebug1' );
1155        }
1156        return style;
1157      };
1158  })();
1159
1160  // -------------------------- box sizing -------------------------- //
1161
1162  boxSizingProp = getStyleProperty('boxSizing');
1163
1164  /**
1165   * WebKit measures the outer-width on style.width on border-box elems
1166   * IE & Firefox measures the inner-width
1167   */
1168  if ( boxSizingProp ) {
1169    var div = document.createElement('div');
1170    div.style.width = '200px';
1171    div.style.padding = '1px 2px 3px 4px';
1172    div.style.borderStyle = 'solid';
1173    div.style.borderWidth = '1px 2px 3px 4px';
1174    div.style[ boxSizingProp ] = 'border-box';
1175
1176    var body = document.body || document.documentElement;
1177    body.appendChild( div );
1178    var style = getStyle( div );
1179
1180    isBoxSizeOuter = getStyleSize( style.width ) === 200;
1181    body.removeChild( div );
1182  }
1183
1184}
1185
1186// -------------------------- getSize -------------------------- //
1187
1188function getSize( elem ) {
1189  setup();
1190
1191  // use querySeletor if elem is string
1192  if ( typeof elem === 'string' ) {
1193    elem = document.querySelector( elem );
1194  }
1195
1196  // do not proceed on non-objects
1197  if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
1198    return;
1199  }
1200
1201  var style = getStyle( elem );
1202
1203  // if hidden, everything is 0
1204  if ( style.display === 'none' ) {
1205    return getZeroSize();
1206  }
1207
1208  var size = {};
1209  size.width = elem.offsetWidth;
1210  size.height = elem.offsetHeight;
1211
1212  var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
1213    style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
1214
1215  // get all measurements
1216  for ( var i=0, len = measurements.length; i < len; i++ ) {
1217    var measurement = measurements[i];
1218    var value = style[ measurement ];
1219    value = mungeNonPixel( elem, value );
1220    var num = parseFloat( value );
1221    // any 'auto', 'medium' value will be 0
1222    size[ measurement ] = !isNaN( num ) ? num : 0;
1223  }
1224
1225  var paddingWidth = size.paddingLeft + size.paddingRight;
1226  var paddingHeight = size.paddingTop + size.paddingBottom;
1227  var marginWidth = size.marginLeft + size.marginRight;
1228  var marginHeight = size.marginTop + size.marginBottom;
1229  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
1230  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
1231
1232  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
1233
1234  // overwrite width and height if we can get it from style
1235  var styleWidth = getStyleSize( style.width );
1236  if ( styleWidth !== false ) {
1237    size.width = styleWidth +
1238      // add padding and border unless it's already including it
1239      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
1240  }
1241
1242  var styleHeight = getStyleSize( style.height );
1243  if ( styleHeight !== false ) {
1244    size.height = styleHeight +
1245      // add padding and border unless it's already including it
1246      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
1247  }
1248
1249  size.innerWidth = size.width - ( paddingWidth + borderWidth );
1250  size.innerHeight = size.height - ( paddingHeight + borderHeight );
1251
1252  size.outerWidth = size.width + marginWidth;
1253  size.outerHeight = size.height + marginHeight;
1254
1255  return size;
1256}
1257
1258// IE8 returns percent values, not pixels
1259// taken from jQuery's curCSS
1260function mungeNonPixel( elem, value ) {
1261  // IE8 and has percent value
1262  if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
1263    return value;
1264  }
1265  var style = elem.style;
1266  // Remember the original values
1267  var left = style.left;
1268  var rs = elem.runtimeStyle;
1269  var rsLeft = rs && rs.left;
1270
1271  // Put in the new values to get a computed value out
1272  if ( rsLeft ) {
1273    rs.left = elem.currentStyle.left;
1274  }
1275  style.left = value;
1276  value = style.pixelLeft;
1277
1278  // Revert the changed values
1279  style.left = left;
1280  if ( rsLeft ) {
1281    rs.left = rsLeft;
1282  }
1283
1284  return value;
1285}
1286
1287return getSize;
1288
1289}
1290
1291// transport
1292if ( typeof define === 'function' && define.amd ) {
1293  // AMD for RequireJS
1294  define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
1295} else if ( typeof exports === 'object' ) {
1296  // CommonJS for Component
1297  module.exports = defineGetSize( require('desandro-get-style-property') );
1298} else {
1299  // browser global
1300  window.getSize = defineGetSize( window.getStyleProperty );
1301}
1302
1303})( window );
1304
1305/*!
1306 * docReady v1.0.4
1307 * Cross browser DOMContentLoaded event emitter
1308 * MIT license
1309 */
1310
1311/*jshint browser: true, strict: true, undef: true, unused: true*/
1312/*global define: false, require: false, module: false */
1313
1314( function( window ) {
1315
1316
1317
1318var document = window.document;
1319// collection of functions to be triggered on ready
1320var queue = [];
1321
1322function docReady( fn ) {
1323  // throw out non-functions
1324  if ( typeof fn !== 'function' ) {
1325    return;
1326  }
1327
1328  if ( docReady.isReady ) {
1329    // ready now, hit it
1330    fn();
1331  } else {
1332    // queue function when ready
1333    queue.push( fn );
1334  }
1335}
1336
1337docReady.isReady = false;
1338
1339// triggered on various doc ready events
1340function onReady( event ) {
1341  // bail if already triggered or IE8 document is not ready just yet
1342  var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
1343  if ( docReady.isReady || isIE8NotReady ) {
1344    return;
1345  }
1346
1347  trigger();
1348}
1349
1350function trigger() {
1351  docReady.isReady = true;
1352  // process queue
1353  for ( var i=0, len = queue.length; i < len; i++ ) {
1354    var fn = queue[i];
1355    fn();
1356  }
1357}
1358
1359function defineDocReady( eventie ) {
1360  // trigger ready if page is ready
1361  if ( document.readyState === 'complete' ) {
1362    trigger();
1363  } else {
1364    // listen for events
1365    eventie.bind( document, 'DOMContentLoaded', onReady );
1366    eventie.bind( document, 'readystatechange', onReady );
1367    eventie.bind( window, 'load', onReady );
1368  }
1369
1370  return docReady;
1371}
1372
1373// transport
1374if ( typeof define === 'function' && define.amd ) {
1375  // AMD
1376  define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
1377} else if ( typeof exports === 'object' ) {
1378  module.exports = defineDocReady( require('eventie') );
1379} else {
1380  // browser global
1381  window.docReady = defineDocReady( window.eventie );
1382}
1383
1384})( window );
1385
1386/**
1387 * matchesSelector v1.0.3
1388 * matchesSelector( element, '.selector' )
1389 * MIT license
1390 */
1391
1392/*jshint browser: true, strict: true, undef: true, unused: true */
1393/*global define: false, module: false */
1394
1395( function( ElemProto ) {
1396
1397  'use strict';
1398
1399  var matchesMethod = ( function() {
1400    // check for the standard method name first
1401    if ( ElemProto.matches ) {
1402      return 'matches';
1403    }
1404    // check un-prefixed
1405    if ( ElemProto.matchesSelector ) {
1406      return 'matchesSelector';
1407    }
1408    // check vendor prefixes
1409    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1410
1411    for ( var i=0, len = prefixes.length; i < len; i++ ) {
1412      var prefix = prefixes[i];
1413      var method = prefix + 'MatchesSelector';
1414      if ( ElemProto[ method ] ) {
1415        return method;
1416      }
1417    }
1418  })();
1419
1420  // ----- match ----- //
1421
1422  function match( elem, selector ) {
1423    return elem[ matchesMethod ]( selector );
1424  }
1425
1426  // ----- appendToFragment ----- //
1427
1428  function checkParent( elem ) {
1429    // not needed if already has parent
1430    if ( elem.parentNode ) {
1431      return;
1432    }
1433    var fragment = document.createDocumentFragment();
1434    fragment.appendChild( elem );
1435  }
1436
1437  // ----- query ----- //
1438
1439  // fall back to using QSA
1440  // thx @jonathantneal https://gist.github.com/3062955
1441  function query( elem, selector ) {
1442    // append to fragment if no parent
1443    checkParent( elem );
1444
1445    // match elem with all selected elems of parent
1446    var elems = elem.parentNode.querySelectorAll( selector );
1447    for ( var i=0, len = elems.length; i < len; i++ ) {
1448      // return true if match
1449      if ( elems[i] === elem ) {
1450        return true;
1451      }
1452    }
1453    // otherwise return false
1454    return false;
1455  }
1456
1457  // ----- matchChild ----- //
1458
1459  function matchChild( elem, selector ) {
1460    checkParent( elem );
1461    return match( elem, selector );
1462  }
1463
1464  // ----- matchesSelector ----- //
1465
1466  var matchesSelector;
1467
1468  if ( matchesMethod ) {
1469    // IE9 supports matchesSelector, but doesn't work on orphaned elems
1470    // check for that
1471    var div = document.createElement('div');
1472    var supportsOrphans = match( div, 'div' );
1473    matchesSelector = supportsOrphans ? match : matchChild;
1474  } else {
1475    matchesSelector = query;
1476  }
1477
1478  // transport
1479  if ( typeof define === 'function' && define.amd ) {
1480    // AMD
1481    define( 'matches-selector/matches-selector',[],function() {
1482      return matchesSelector;
1483    });
1484  } else if ( typeof exports === 'object' ) {
1485    module.exports = matchesSelector;
1486  }
1487  else {
1488    // browser global
1489    window.matchesSelector = matchesSelector;
1490  }
1491
1492})( Element.prototype );
1493
1494/**
1495 * Fizzy UI utils v1.0.1
1496 * MIT license
1497 */
1498
1499/*jshint browser: true, undef: true, unused: true, strict: true */
1500
1501( function( window, factory ) {
1502  /*global define: false, module: false, require: false */
1503  'use strict';
1504  // universal module definition
1505
1506  if ( typeof define == 'function' && define.amd ) {
1507    // AMD
1508    define( 'fizzy-ui-utils/utils',[
1509      'doc-ready/doc-ready',
1510      'matches-selector/matches-selector'
1511    ], function( docReady, matchesSelector ) {
1512      return factory( window, docReady, matchesSelector );
1513    });
1514  } else if ( typeof exports == 'object' ) {
1515    // CommonJS
1516    module.exports = factory(
1517      window,
1518      require('doc-ready'),
1519      require('desandro-matches-selector')
1520    );
1521  } else {
1522    // browser global
1523    window.fizzyUIUtils = factory(
1524      window,
1525      window.docReady,
1526      window.matchesSelector
1527    );
1528  }
1529
1530}( window, function factory( window, docReady, matchesSelector ) {
1531
1532
1533
1534var utils = {};
1535
1536// ----- extend ----- //
1537
1538// extends objects
1539utils.extend = function( a, b ) {
1540  for ( var prop in b ) {
1541    a[ prop ] = b[ prop ];
1542  }
1543  return a;
1544};
1545
1546// ----- modulo ----- //
1547
1548utils.modulo = function( num, div ) {
1549  return ( ( num % div ) + div ) % div;
1550};
1551
1552// ----- isArray ----- //
1553  
1554var objToString = Object.prototype.toString;
1555utils.isArray = function( obj ) {
1556  return objToString.call( obj ) == '[object Array]';
1557};
1558
1559// ----- makeArray ----- //
1560
1561// turn element or nodeList into an array
1562utils.makeArray = function( obj ) {
1563  var ary = [];
1564  if ( utils.isArray( obj ) ) {
1565    // use object if already an array
1566    ary = obj;
1567  } else if ( obj && typeof obj.length == 'number' ) {
1568    // convert nodeList to array
1569    for ( var i=0, len = obj.length; i < len; i++ ) {
1570      ary.push( obj[i] );
1571    }
1572  } else {
1573    // array of single index
1574    ary.push( obj );
1575  }
1576  return ary;
1577};
1578
1579// ----- indexOf ----- //
1580
1581// index of helper cause IE8
1582utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
1583    return ary.indexOf( obj );
1584  } : function( ary, obj ) {
1585    for ( var i=0, len = ary.length; i < len; i++ ) {
1586      if ( ary[i] === obj ) {
1587        return i;
1588      }
1589    }
1590    return -1;
1591  };
1592
1593// ----- removeFrom ----- //
1594
1595utils.removeFrom = function( ary, obj ) {
1596  var index = utils.indexOf( ary, obj );
1597  if ( index != -1 ) {
1598    ary.splice( index, 1 );
1599  }
1600};
1601
1602// ----- isElement ----- //
1603
1604// http://stackoverflow.com/a/384380/182183
1605utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
1606  function isElementDOM2( obj ) {
1607    return obj instanceof HTMLElement;
1608  } :
1609  function isElementQuirky( obj ) {
1610    return obj && typeof obj == 'object' &&
1611      obj.nodeType == 1 && typeof obj.nodeName == 'string';
1612  };
1613
1614// ----- setText ----- //
1615
1616utils.setText = ( function() {
1617  var setTextProperty;
1618  function setText( elem, text ) {
1619    // only check setTextProperty once
1620    setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
1621    elem[ setTextProperty ] = text;
1622  }
1623  return setText;
1624})();
1625
1626// ----- getParent ----- //
1627
1628utils.getParent = function( elem, selector ) {
1629  while ( elem != document.body ) {
1630    elem = elem.parentNode;
1631    if ( matchesSelector( elem, selector ) ) {
1632      return elem;
1633    }
1634  }
1635};
1636
1637// ----- getQueryElement ----- //
1638
1639// use element as selector string
1640utils.getQueryElement = function( elem ) {
1641  if ( typeof elem == 'string' ) {
1642    return document.querySelector( elem );
1643  }
1644  return elem;
1645};
1646
1647// ----- handleEvent ----- //
1648
1649// enable .ontype to trigger from .addEventListener( elem, 'type' )
1650utils.handleEvent = function( event ) {
1651  var method = 'on' + event.type;
1652  if ( this[ method ] ) {
1653    this[ method ]( event );
1654  }
1655};
1656
1657// ----- filterFindElements ----- //
1658
1659utils.filterFindElements = function( elems, selector ) {
1660  // make array of elems
1661  elems = utils.makeArray( elems );
1662  var ffElems = [];
1663
1664  for ( var i=0, len = elems.length; i < len; i++ ) {
1665    var elem = elems[i];
1666    // check that elem is an actual element
1667    if ( !utils.isElement( elem ) ) {
1668      continue;
1669    }
1670    // filter & find items if we have a selector
1671    if ( selector ) {
1672      // filter siblings
1673      if ( matchesSelector( elem, selector ) ) {
1674        ffElems.push( elem );
1675      }
1676      // find children
1677      var childElems = elem.querySelectorAll( selector );
1678      // concat childElems to filterFound array
1679      for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
1680        ffElems.push( childElems[j] );
1681      }
1682    } else {
1683      ffElems.push( elem );
1684    }
1685  }
1686
1687  return ffElems;
1688};
1689
1690// ----- debounceMethod ----- //
1691
1692utils.debounceMethod = function( _class, methodName, threshold ) {
1693  // original method
1694  var method = _class.prototype[ methodName ];
1695  var timeoutName = methodName + 'Timeout';
1696
1697  _class.prototype[ methodName ] = function() {
1698    var timeout = this[ timeoutName ];
1699    if ( timeout ) {
1700      clearTimeout( timeout );
1701    }
1702    var args = arguments;
1703
1704    var _this = this;
1705    this[ timeoutName ] = setTimeout( function() {
1706      method.apply( _this, args );
1707      delete _this[ timeoutName ];
1708    }, threshold || 100 );
1709  };
1710};
1711
1712// ----- htmlInit ----- //
1713
1714// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1715utils.toDashed = function( str ) {
1716  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1717    return $1 + '-' + $2;
1718  }).toLowerCase();
1719};
1720
1721var console = window.console;
1722/**
1723 * allow user to initialize classes via .js-namespace class
1724 * htmlInit( Widget, 'widgetName' )
1725 * options are parsed from data-namespace-option attribute
1726 */
1727utils.htmlInit = function( WidgetClass, namespace ) {
1728  docReady( function() {
1729    var dashedNamespace = utils.toDashed( namespace );
1730    var elems = document.querySelectorAll( '.js-' + dashedNamespace );
1731    var dataAttr = 'data-' + dashedNamespace + '-options';
1732
1733    for ( var i=0, len = elems.length; i < len; i++ ) {
1734      var elem = elems[i];
1735      var attr = elem.getAttribute( dataAttr );
1736      var options;
1737      try {
1738        options = attr && JSON.parse( attr );
1739      } catch ( error ) {
1740        // log error, do not initialize
1741        if ( console ) {
1742          console.error( 'Error parsing ' + dataAttr + ' on ' +
1743            elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
1744            error );
1745        }
1746        continue;
1747      }
1748      // initialize
1749      var instance = new WidgetClass( elem, options );
1750      // make available via $().data('layoutname')
1751      var jQuery = window.jQuery;
1752      if ( jQuery ) {
1753        jQuery.data( elem, namespace, instance );
1754      }
1755    }
1756  });
1757};
1758
1759// -----  ----- //
1760
1761return utils;
1762
1763}));
1764
1765/**
1766 * Outlayer Item
1767 */
1768
1769( function( window, factory ) {
1770  'use strict';
1771  // universal module definition
1772  if ( typeof define === 'function' && define.amd ) {
1773    // AMD
1774    define( 'outlayer/item',[
1775        'eventEmitter/EventEmitter',
1776        'get-size/get-size',
1777        'get-style-property/get-style-property',
1778        'fizzy-ui-utils/utils'
1779      ],
1780      function( EventEmitter, getSize, getStyleProperty, utils ) {
1781        return factory( window, EventEmitter, getSize, getStyleProperty, utils );
1782      }
1783    );
1784  } else if (typeof exports === 'object') {
1785    // CommonJS
1786    module.exports = factory(
1787      window,
1788      require('wolfy87-eventemitter'),
1789      require('get-size'),
1790      require('desandro-get-style-property'),
1791      require('fizzy-ui-utils')
1792    );
1793  } else {
1794    // browser global
1795    window.Outlayer = {};
1796    window.Outlayer.Item = factory(
1797      window,
1798      window.EventEmitter,
1799      window.getSize,
1800      window.getStyleProperty,
1801      window.fizzyUIUtils
1802    );
1803  }
1804
1805}( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) {
1806'use strict';
1807
1808// ----- helpers ----- //
1809
1810var getComputedStyle = window.getComputedStyle;
1811var getStyle = getComputedStyle ?
1812  function( elem ) {
1813    return getComputedStyle( elem, null );
1814  } :
1815  function( elem ) {
1816    return elem.currentStyle;
1817  };
1818
1819
1820function isEmptyObj( obj ) {
1821  for ( var prop in obj ) {
1822    return false;
1823  }
1824  prop = null;
1825  return true;
1826}
1827
1828// -------------------------- CSS3 support -------------------------- //
1829
1830var transitionProperty = getStyleProperty('transition');
1831var transformProperty = getStyleProperty('transform');
1832var supportsCSS3 = transitionProperty && transformProperty;
1833var is3d = !!getStyleProperty('perspective');
1834
1835var transitionEndEvent = {
1836  WebkitTransition: 'webkitTransitionEnd',
1837  MozTransition: 'transitionend',
1838  OTransition: 'otransitionend',
1839  transition: 'transitionend'
1840}[ transitionProperty ];
1841
1842// properties that could have vendor prefix
1843var prefixableProperties = [
1844  'transform',
1845  'transition',
1846  'transitionDuration',
1847  'transitionProperty'
1848];
1849
1850// cache all vendor properties
1851var vendorProperties = ( function() {
1852  var cache = {};
1853  for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
1854    var prop = prefixableProperties[i];
1855    var supportedProp = getStyleProperty( prop );
1856    if ( supportedProp && supportedProp !== prop ) {
1857      cache[ prop ] = supportedProp;
1858    }
1859  }
1860  return cache;
1861})();
1862
1863// -------------------------- Item -------------------------- //
1864
1865function Item( element, layout ) {
1866  if ( !element ) {
1867    return;
1868  }
1869
1870  this.element = element;
1871  // parent layout class, i.e. Masonry, Isotope, or Packery
1872  this.layout = layout;
1873  this.position = {
1874    x: 0,
1875    y: 0
1876  };
1877
1878  this._create();
1879}
1880
1881// inherit EventEmitter
1882utils.extend( Item.prototype, EventEmitter.prototype );
1883
1884Item.prototype._create = function() {
1885  // transition objects
1886  this._transn = {
1887    ingProperties: {},
1888    clean: {},
1889    onEnd: {}
1890  };
1891
1892  this.css({
1893    position: 'absolute'
1894  });
1895};
1896
1897// trigger specified handler for event type
1898Item.prototype.handleEvent = function( event ) {
1899  var method = 'on' + event.type;
1900  if ( this[ method ] ) {
1901    this[ method ]( event );
1902  }
1903};
1904
1905Item.prototype.getSize = function() {
1906  this.size = getSize( this.element );
1907};
1908
1909/**
1910 * apply CSS styles to element
1911 * @param {Object} style
1912 */
1913Item.prototype.css = function( style ) {
1914  var elemStyle = this.element.style;
1915
1916  for ( var prop in style ) {
1917    // use vendor property if available
1918    var supportedProp = vendorProperties[ prop ] || prop;
1919    elemStyle[ supportedProp ] = style[ prop ];
1920  }
1921};
1922
1923 // measure position, and sets it
1924Item.prototype.getPosition = function() {
1925  var style = getStyle( this.element );
1926  var layoutOptions = this.layout.options;
1927  var isOriginLeft = layoutOptions.isOriginLeft;
1928  var isOriginTop = layoutOptions.isOriginTop;
1929  var xValue = style[ isOriginLeft ? 'left' : 'right' ];
1930  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
1931  // convert percent to pixels
1932  var layoutSize = this.layout.size;
1933  var x = xValue.indexOf('%') != -1 ?
1934    ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 );
1935  var y = yValue.indexOf('%') != -1 ?
1936    ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 );
1937
1938  // clean up 'auto' or other non-integer values
1939  x = isNaN( x ) ? 0 : x;
1940  y = isNaN( y ) ? 0 : y;
1941  // remove padding from measurement
1942  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1943  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1944
1945  this.position.x = x;
1946  this.position.y = y;
1947};
1948
1949// set settled position, apply padding
1950Item.prototype.layoutPosition = function() {
1951  var layoutSize = this.layout.size;
1952  var layoutOptions = this.layout.options;
1953  var style = {};
1954
1955  // x
1956  var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight';
1957  var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right';
1958  var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left';
1959
1960  var x = this.position.x + layoutSize[ xPadding ];
1961  // set in percentage or pixels
1962  style[ xProperty ] = this.getXValue( x );
1963  // reset other property
1964  style[ xResetProperty ] = '';
1965
1966  // y
1967  var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom';
1968  var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom';
1969  var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top';
1970
1971  var y = this.position.y + layoutSize[ yPadding ];
1972  // set in percentage or pixels
1973  style[ yProperty ] = this.getYValue( y );
1974  // reset other property
1975  style[ yResetProperty ] = '';
1976
1977  this.css( style );
1978  this.emitEvent( 'layout', [ this ] );
1979};
1980
1981Item.prototype.getXValue = function( x ) {
1982  var layoutOptions = this.layout.options;
1983  return layoutOptions.percentPosition && !layoutOptions.isHorizontal ?
1984    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
1985};
1986
1987Item.prototype.getYValue = function( y ) {
1988  var layoutOptions = this.layout.options;
1989  return layoutOptions.percentPosition && layoutOptions.isHorizontal ?
1990    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
1991};
1992
1993
1994Item.prototype._transitionTo = function( x, y ) {
1995  this.getPosition();
1996  // get current x & y from top/left
1997  var curX = this.position.x;
1998  var curY = this.position.y;
1999
2000  var compareX = parseInt( x, 10 );
2001  var compareY = parseInt( y, 10 );
2002  var didNotMove = compareX === this.position.x && compareY === this.position.y;
2003
2004  // save end position
2005  this.setPosition( x, y );
2006
2007  // if did not move and not transitioning, just go to layout
2008  if ( didNotMove && !this.isTransitioning ) {
2009    this.layoutPosition();
2010    return;
2011  }
2012
2013  var transX = x - curX;
2014  var transY = y - curY;
2015  var transitionStyle = {};
2016  transitionStyle.transform = this.getTranslate( transX, transY );
2017
2018  this.transition({
2019    to: transitionStyle,
2020    onTransitionEnd: {
2021      transform: this.layoutPosition
2022    },
2023    isCleaning: true
2024  });
2025};
2026
2027Item.prototype.getTranslate = function( x, y ) {
2028  // flip cooridinates if origin on right or bottom
2029  var layoutOptions = this.layout.options;
2030  x = layoutOptions.isOriginLeft ? x : -x;
2031  y = layoutOptions.isOriginTop ? y : -y;
2032
2033  if ( is3d ) {
2034    return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
2035  }
2036
2037  return 'translate(' + x + 'px, ' + y + 'px)';
2038};
2039
2040// non transition + transform support
2041Item.prototype.goTo = function( x, y ) {
2042  this.setPosition( x, y );
2043  this.layoutPosition();
2044};
2045
2046// use transition and transforms if supported
2047Item.prototype.moveTo = supportsCSS3 ?
2048  Item.prototype._transitionTo : Item.prototype.goTo;
2049
2050Item.prototype.setPosition = function( x, y ) {
2051  this.position.x = parseInt( x, 10 );
2052  this.position.y = parseInt( y, 10 );
2053};
2054
2055// ----- transition ----- //
2056
2057/**
2058 * @param {Object} style - CSS
2059 * @param {Function} onTransitionEnd
2060 */
2061
2062// non transition, just trigger callback
2063Item.prototype._nonTransition = function( args ) {
2064  this.css( args.to );
2065  if ( args.isCleaning ) {
2066    this._removeStyles( args.to );
2067  }
2068  for ( var prop in args.onTransitionEnd ) {
2069    args.onTransitionEnd[ prop ].call( this );
2070  }
2071};
2072
2073/**
2074 * proper transition
2075 * @param {Object} args - arguments
2076 *   @param {Object} to - style to transition to
2077 *   @param {Object} from - style to start transition from
2078 *   @param {Boolean} isCleaning - removes transition styles after transition
2079 *   @param {Function} onTransitionEnd - callback
2080 */
2081Item.prototype._transition = function( args ) {
2082  // redirect to nonTransition if no transition duration
2083  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
2084    this._nonTransition( args );
2085    return;
2086  }
2087
2088  var _transition = this._transn;
2089  // keep track of onTransitionEnd callback by css property
2090  for ( var prop in args.onTransitionEnd ) {
2091    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
2092  }
2093  // keep track of properties that are transitioning
2094  for ( prop in args.to ) {
2095    _transition.ingProperties[ prop ] = true;
2096    // keep track of properties to clean up when transition is done
2097    if ( args.isCleaning ) {
2098      _transition.clean[ prop ] = true;
2099    }
2100  }
2101
2102  // set from styles
2103  if ( args.from ) {
2104    this.css( args.from );
2105    // force redraw. http://blog.alexmaccaw.com/css-transitions
2106    var h = this.element.offsetHeight;
2107    // hack for JSHint to hush about unused var
2108    h = null;
2109  }
2110  // enable transition
2111  this.enableTransition( args.to );
2112  // set styles that are transitioning
2113  this.css( args.to );
2114
2115  this.isTransitioning = true;
2116
2117};
2118
2119// dash before all cap letters, including first for
2120// WebkitTransform => -webkit-transform
2121function toDashedAll( str ) {
2122  return str.replace( /([A-Z])/g, function( $1 ) {
2123    return '-' + $1.toLowerCase();
2124  });
2125}
2126
2127var transitionProps = 'opacity,' +
vendor: 11,190 bytes, lines 2128-2574
2128  toDashedAll( vendorProperties.transform || 'transform' );
2129
2130Item.prototype.enableTransition = function(/* style */) {
2131  // HACK changing transitionProperty during a transition
2132  // will cause transition to jump
2133  if ( this.isTransitioning ) {
2134    return;
2135  }
2136
2137  // make `transition: foo, bar, baz` from style object
2138  // HACK un-comment this when enableTransition can work
2139  // while a transition is happening
2140  // var transitionValues = [];
2141  // for ( var prop in style ) {
2142  //   // dash-ify camelCased properties like WebkitTransition
2143  //   prop = vendorProperties[ prop ] || prop;
2144  //   transitionValues.push( toDashedAll( prop ) );
2145  // }
2146  // enable transition styles
2147  this.css({
2148    transitionProperty: transitionProps,
2149    transitionDuration: this.layout.options.transitionDuration
2150  });
2151  // listen for transition end event
2152  this.element.addEventListener( transitionEndEvent, this, false );
2153};
2154
2155Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
2156
2157// ----- events ----- //
2158
2159Item.prototype.onwebkitTransitionEnd = function( event ) {
2160  this.ontransitionend( event );
2161};
2162
2163Item.prototype.onotransitionend = function( event ) {
2164  this.ontransitionend( event );
2165};
2166
2167// properties that I munge to make my life easier
2168var dashedVendorProperties = {
2169  '-webkit-transform': 'transform',
2170  '-moz-transform': 'transform',
2171  '-o-transform': 'transform'
2172};
2173
2174Item.prototype.ontransitionend = function( event ) {
2175  // disregard bubbled events from children
2176  if ( event.target !== this.element ) {
2177    return;
2178  }
2179  var _transition = this._transn;
2180  // get property name of transitioned property, convert to prefix-free
2181  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
2182
2183  // remove property that has completed transitioning
2184  delete _transition.ingProperties[ propertyName ];
2185  // check if any properties are still transitioning
2186  if ( isEmptyObj( _transition.ingProperties ) ) {
2187    // all properties have completed transitioning
2188    this.disableTransition();
2189  }
2190  // clean style
2191  if ( propertyName in _transition.clean ) {
2192    // clean up style
2193    this.element.style[ event.propertyName ] = '';
2194    delete _transition.clean[ propertyName ];
2195  }
2196  // trigger onTransitionEnd callback
2197  if ( propertyName in _transition.onEnd ) {
2198    var onTransitionEnd = _transition.onEnd[ propertyName ];
2199    onTransitionEnd.call( this );
2200    delete _transition.onEnd[ propertyName ];
2201  }
2202
2203  this.emitEvent( 'transitionEnd', [ this ] );
2204};
2205
2206Item.prototype.disableTransition = function() {
2207  this.removeTransitionStyles();
2208  this.element.removeEventListener( transitionEndEvent, this, false );
2209  this.isTransitioning = false;
2210};
2211
2212/**
2213 * removes style property from element
2214 * @param {Object} style
2215**/
2216Item.prototype._removeStyles = function( style ) {
2217  // clean up transition styles
2218  var cleanStyle = {};
2219  for ( var prop in style ) {
2220    cleanStyle[ prop ] = '';
2221  }
2222  this.css( cleanStyle );
2223};
2224
2225var cleanTransitionStyle = {
2226  transitionProperty: '',
2227  transitionDuration: ''
2228};
2229
2230Item.prototype.removeTransitionStyles = function() {
2231  // remove transition
2232  this.css( cleanTransitionStyle );
2233};
2234
2235// ----- show/hide/remove ----- //
2236
2237// remove element from DOM
2238Item.prototype.removeElem = function() {
2239  this.element.parentNode.removeChild( this.element );
2240  // remove display: none
2241  this.css({ display: '' });
2242  this.emitEvent( 'remove', [ this ] );
2243};
2244
2245Item.prototype.remove = function() {
2246  // just remove element if no transition support or no transition
2247  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
2248    this.removeElem();
2249    return;
2250  }
2251
2252  // start transition
2253  var _this = this;
2254  this.once( 'transitionEnd', function() {
2255    _this.removeElem();
2256  });
2257  this.hide();
2258};
2259
2260Item.prototype.reveal = function() {
2261  delete this.isHidden;
2262  // remove display: none
2263  this.css({ display: '' });
2264
2265  var options = this.layout.options;
2266
2267  var onTransitionEnd = {};
2268  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
2269  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
2270
2271  this.transition({
2272    from: options.hiddenStyle,
2273    to: options.visibleStyle,
2274    isCleaning: true,
2275    onTransitionEnd: onTransitionEnd
2276  });
2277};
2278
2279Item.prototype.onRevealTransitionEnd = function() {
2280  // check if still visible
2281  // during transition, item may have been hidden
2282  if ( !this.isHidden ) {
2283    this.emitEvent('reveal');
2284  }
2285};
2286
2287/**
2288 * get style property use for hide/reveal transition end
2289 * @param {String} styleProperty - hiddenStyle/visibleStyle
2290 * @returns {String}
2291 */
2292Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) {
2293  var optionStyle = this.layout.options[ styleProperty ];
2294  // use opacity
2295  if ( optionStyle.opacity ) {
2296    return 'opacity';
2297  }
2298  // get first property
2299  for ( var prop in optionStyle ) {
2300    return prop;
2301  }
2302};
2303
2304Item.prototype.hide = function() {
2305  // set flag
2306  this.isHidden = true;
2307  // remove display: none
2308  this.css({ display: '' });
2309
2310  var options = this.layout.options;
2311
2312  var onTransitionEnd = {};
2313  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
2314  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
2315
2316  this.transition({
2317    from: options.visibleStyle,
2318    to: options.hiddenStyle,
2319    // keep hidden stuff hidden
2320    isCleaning: true,
2321    onTransitionEnd: onTransitionEnd
2322  });
2323};
2324
2325Item.prototype.onHideTransitionEnd = function() {
2326  // check if still hidden
2327  // during transition, item may have been un-hidden
2328  if ( this.isHidden ) {
2329    this.css({ display: 'none' });
2330    this.emitEvent('hide');
2331  }
2332};
2333
2334Item.prototype.destroy = function() {
2335  this.css({
2336    position: '',
2337    left: '',
2338    right: '',
2339    top: '',
2340    bottom: '',
2341    transition: '',
2342    transform: ''
2343  });
2344};
2345
2346return Item;
2347
2348}));
2349
2350/*!
2351 * Outlayer v1.4.2
2352 * the brains and guts of a layout library
2353 * MIT license
2354 */
2355
2356( function( window, factory ) {
2357  'use strict';
2358  // universal module definition
2359
2360  if ( typeof define == 'function' && define.amd ) {
2361    // AMD
2362    define( 'outlayer/outlayer',[
2363        'eventie/eventie',
2364        'eventEmitter/EventEmitter',
2365        'get-size/get-size',
2366        'fizzy-ui-utils/utils',
2367        './item'
2368      ],
2369      function( eventie, EventEmitter, getSize, utils, Item ) {
2370        return factory( window, eventie, EventEmitter, getSize, utils, Item);
2371      }
2372    );
2373  } else if ( typeof exports == 'object' ) {
2374    // CommonJS
2375    module.exports = factory(
2376      window,
2377      require('eventie'),
2378      require('wolfy87-eventemitter'),
2379      require('get-size'),
2380      require('fizzy-ui-utils'),
2381      require('./item')
2382    );
2383  } else {
2384    // browser global
2385    window.Outlayer = factory(
2386      window,
2387      window.eventie,
2388      window.EventEmitter,
2389      window.getSize,
2390      window.fizzyUIUtils,
2391      window.Outlayer.Item
2392    );
2393  }
2394
2395}( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) {
2396'use strict';
2397
2398// ----- vars ----- //
2399
2400var console = window.console;
2401var jQuery = window.jQuery;
2402var noop = function() {};
2403
2404// -------------------------- Outlayer -------------------------- //
2405
2406// globally unique identifiers
2407var GUID = 0;
2408// internal store of all Outlayer intances
2409var instances = {};
2410
2411
2412/**
2413 * @param {Element, String} element
2414 * @param {Object} options
2415 * @constructor
2416 */
2417function Outlayer( element, options ) {
2418  var queryElement = utils.getQueryElement( element );
2419  if ( !queryElement ) {
2420    if ( console ) {
2421      console.error( 'Bad element for ' + this.constructor.namespace +
2422        ': ' + ( queryElement || element ) );
2423    }
2424    return;
2425  }
2426  this.element = queryElement;
2427  // add jQuery
2428  if ( jQuery ) {
2429    this.$element = jQuery( this.element );
2430  }
2431
2432  // options
2433  this.options = utils.extend( {}, this.constructor.defaults );
2434  this.option( options );
2435
2436  // add id for Outlayer.getFromElement
2437  var id = ++GUID;
2438  this.element.outlayerGUID = id; // expando
2439  instances[ id ] = this; // associate via id
2440
2441  // kick it off
2442  this._create();
2443
2444  if ( this.options.isInitLayout ) {
2445    this.layout();
2446  }
2447}
2448
2449// settings are for internal use only
2450Outlayer.namespace = 'outlayer';
2451Outlayer.Item = Item;
2452
2453// default options
2454Outlayer.defaults = {
2455  containerStyle: {
2456    position: 'relative'
2457  },
2458  isInitLayout: true,
2459  isOriginLeft: true,
2460  isOriginTop: true,
2461  isResizeBound: true,
2462  isResizingContainer: true,
2463  // item options
2464  transitionDuration: '0.4s',
2465  hiddenStyle: {
2466    opacity: 0,
2467    transform: 'scale(0.001)'
2468  },
2469  visibleStyle: {
2470    opacity: 1,
2471    transform: 'scale(1)'
2472  }
2473};
2474
2475// inherit EventEmitter
2476utils.extend( Outlayer.prototype, EventEmitter.prototype );
2477
2478/**
2479 * set options
2480 * @param {Object} opts
2481 */
2482Outlayer.prototype.option = function( opts ) {
2483  utils.extend( this.options, opts );
2484};
2485
2486Outlayer.prototype._create = function() {
2487  // get items from children
2488  this.reloadItems();
2489  // elements that affect layout, but are not laid out
2490  this.stamps = [];
2491  this.stamp( this.options.stamp );
2492  // set container style
2493  utils.extend( this.element.style, this.options.containerStyle );
2494
2495  // bind resize method
2496  if ( this.options.isResizeBound ) {
2497    this.bindResize();
2498  }
2499};
2500
2501// goes through all children again and gets bricks in proper order
2502Outlayer.prototype.reloadItems = function() {
2503  // collection of item elements
2504  this.items = this._itemize( this.element.children );
2505};
2506
2507
2508/**
2509 * turn elements into Outlayer.Items to be used in layout
2510 * @param {Array or NodeList or HTMLElement} elems
2511 * @returns {Array} items - collection of new Outlayer Items
2512 */
2513Outlayer.prototype._itemize = function( elems ) {
2514
2515  var itemElems = this._filterFindItemElements( elems );
2516  var Item = this.constructor.Item;
2517
2518  // create new Outlayer Items for collection
2519  var items = [];
2520  for ( var i=0, len = itemElems.length; i < len; i++ ) {
2521    var elem = itemElems[i];
2522    var item = new Item( elem, this );
2523    items.push( item );
2524  }
2525
2526  return items;
2527};
2528
2529/**
2530 * get item elements to be used in layout
2531 * @param {Array or NodeList or HTMLElement} elems
2532 * @returns {Array} items - item elements
2533 */
2534Outlayer.prototype._filterFindItemElements = function( elems ) {
2535  return utils.filterFindElements( elems, this.options.itemSelector );
2536};
2537
2538/**
2539 * getter method for getting item elements
2540 * @returns {Array} elems - collection of item elements
2541 */
2542Outlayer.prototype.getItemElements = function() {
2543  var elems = [];
2544  for ( var i=0, len = this.items.length; i < len; i++ ) {
2545    elems.push( this.items[i].element );
2546  }
2547  return elems;
2548};
2549
2550// ----- init & layout ----- //
2551
2552/**
2553 * lays out all items
2554 */
2555Outlayer.prototype.layout = function() {
2556  this._resetLayout();
2557  this._manageStamps();
2558
2559  // don't animate first layout
2560  var isInstant = this.options.isLayoutInstant !== undefined ?
2561    this.options.isLayoutInstant : !this._isLayoutInited;
2562  this.layoutItems( this.items, isInstant );
2563
2564  // flag for initalized
2565  this._isLayoutInited = true;
2566};
2567
2568// _init is alias for layout
2569Outlayer.prototype._init = Outlayer.prototype.layout;
2570
2571/**
2572 * logic before any new layout
2573 */
2574Outlayer.prototype._resetLayout = function() {
2575  this.getSize();
2576};
2577
2578
2579Outlayer.prototype.getSize = function() {
2580  this.size = getSize( this.element );
2581};
2582
2583/**
2584 * get measurement from option, for columnWidth, rowHeight, gutter
2585 * if option is String -> get element from selector string, & get size of element
2586 * if option is Element -> get size of element
2587 * else use option as a number
2588 *
2589 * @param {String} measurement
2590 * @param {String} size - width or height
2591 * @private
2592 */
2593Outlayer.prototype._getMeasurement = function( measurement, size ) {
2594  var option = this.options[ measurement ];
2595  var elem;
2596  if ( !option ) {
2597    // default to 0
2598    this[ measurement ] = 0;
2599  } else {
2600    // use option as an element
2601    if ( typeof option === 'string' ) {
2602      elem = this.element.querySelector( option );
2603    } else if ( utils.isElement( option ) ) {
2604      elem = option;
2605    }
2606    // use size of element, if element
2607    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
2608  }
2609};
2610
2611/**
2612 * layout a collection of item elements
2613 * @api public
2614 */
2615Outlayer.prototype.layoutItems = function( items, isInstant ) {
2616  items = this._getItemsForLayout( items );
2617
2618  this._layoutItems( items, isInstant );
2619
2620  this._postLayout();
2621};
2622
2623/**
2624 * get the items to be laid out
2625 * you may want to skip over some items
2626 * @param {Array} items
2627 * @returns {Array} items
2628 */
2629Outlayer.prototype._getItemsForLayout = function( items ) {
2630  var layoutItems = [];
2631  for ( var i=0, len = items.length; i < len; i++ ) {
2632    var item = items[i];
2633    if ( !item.isIgnored ) {
2634      layoutItems.push( item );
2635    }
2636  }
2637  return layoutItems;
2638};
2639
2640/**
2641 * layout items
2642 * @param {Array} items
2643 * @param {Boolean} isInstant
2644 */
2645Outlayer.prototype._layoutItems = function( items, isInstant ) {
2646  this._emitCompleteOnItems( 'layout', items );
2647
2648  if ( !items || !items.length ) {
2649    // no items, emit event with empty array
2650    return;
2651  }
2652
2653  var queue = [];
2654
2655  for ( var i=0, len = items.length; i < len; i++ ) {
2656    var item = items[i];
2657    // get x/y object from method
2658    var position = this._getItemLayoutPosition( item );
2659    // enqueue
2660    position.item = item;
2661    position.isInstant = isInstant || item.isLayoutInstant;
2662    queue.push( position );
2663  }
2664
2665  this._processLayoutQueue( queue );
2666};
2667
2668/**
2669 * get item layout position
2670 * @param {Outlayer.Item} item
2671 * @returns {Object} x and y position
2672 */
2673Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
2674  return {
2675    x: 0,
2676    y: 0
2677  };
2678};
2679
2680/**
2681 * iterate over array and position each item
2682 * Reason being - separating this logic prevents 'layout invalidation'
2683 * thx @paul_irish
2684 * @param {Array} queue
2685 */
2686Outlayer.prototype._processLayoutQueue = function( queue ) {
2687  for ( var i=0, len = queue.length; i < len; i++ ) {
2688    var obj = queue[i];
2689    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
2690  }
2691};
2692
2693/**
2694 * Sets position of item in DOM
2695 * @param {Outlayer.Item} item
2696 * @param {Number} x - horizontal position
2697 * @param {Number} y - vertical position
2698 * @param {Boolean} isInstant - disables transitions
2699 */
2700Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
2701  if ( isInstant ) {
2702    // if not transition, just set CSS
2703    item.goTo( x, y );
2704  } else {
2705    item.moveTo( x, y );
2706  }
2707};
2708
2709/**
2710 * Any logic you want to do after each layout,
2711 * i.e. size the container
2712 */
2713Outlayer.prototype._postLayout = function() {
2714  this.resizeContainer();
2715};
2716
2717Outlayer.prototype.resizeContainer = function() {
2718  if ( !this.options.isResizingContainer ) {
2719    return;
2720  }
2721  var size = this._getContainerSize();
2722  if ( size ) {
2723    this._setContainerMeasure( size.width, true );
2724    this._setContainerMeasure( size.height, false );
2725  }
2726};
2727
2728/**
2729 * Sets width or height of container if returned
2730 * @returns {Object} size
2731 *   @param {Number} width
2732 *   @param {Number} height
2733 */
2734Outlayer.prototype._getContainerSize = noop;
2735
2736/**
2737 * @param {Number} measure - size of width or height
2738 * @param {Boolean} isWidth
2739 */
2740Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
2741  if ( measure === undefined ) {
2742    return;
2743  }
2744
2745  var elemSize = this.size;
2746  // add padding and border width if border box
2747  if ( elemSize.isBorderBox ) {
2748    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2749      elemSize.borderLeftWidth + elemSize.borderRightWidth :
2750      elemSize.paddingBottom + elemSize.paddingTop +
2751      elemSize.borderTopWidth + elemSize.borderBottomWidth;
2752  }
2753
2754  measure = Math.max( measure, 0 );
2755  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2756};
2757
2758/**
2759 * emit eventComplete on a collection of items events
2760 * @param {String} eventName
2761 * @param {Array} items - Outlayer.Items
2762 */
2763Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) {
2764  var _this = this;
2765  function onComplete() {
2766    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
2767  }
2768
2769  var count = items.length;
2770  if ( !items || !count ) {
2771    onComplete();
2772    return;
2773  }
2774
2775  var doneCount = 0;
2776  function tick() {
2777    doneCount++;
2778    if ( doneCount === count ) {
2779      onComplete();
2780    }
2781  }
2782
2783  // bind callback
2784  for ( var i=0, len = items.length; i < len; i++ ) {
2785    var item = items[i];
2786    item.once( eventName, tick );
2787  }
2788};
2789
2790/**
2791 * emits events via eventEmitter and jQuery events
2792 * @param {String} type - name of event
2793 * @param {Event} event - original event
2794 * @param {Array} args - extra arguments
2795 */
2796Outlayer.prototype.dispatchEvent = function( type, event, args ) {
2797  // add original event to arguments
2798  var emitArgs = event ? [ event ].concat( args ) : args;
2799  this.emitEvent( type, emitArgs );
2800
2801  if ( jQuery ) {
2802    // set this.$element
2803    this.$element = this.$element || jQuery( this.element );
2804    if ( event ) {
2805      // create jQuery event
2806      var $event = jQuery.Event( event );
2807      $event.type = type;
2808      this.$element.trigger( $event, args );
2809    } else {
2810      // just trigger with type if no event available
2811      this.$element.trigger( type, args );
2812    }
2813  }
2814};
2815
2816// -------------------------- ignore & stamps -------------------------- //
2817
2818
2819/**
2820 * keep item in collection, but do not lay it out
2821 * ignored items do not get skipped in layout
2822 * @param {Element} elem
2823 */
2824Outlayer.prototype.ignore = function( elem ) {
2825  var item = this.getItem( elem );
2826  if ( item ) {
2827    item.isIgnored = true;
2828  }
2829};
2830
2831/**
2832 * return item to layout collection
2833 * @param {Element} elem
2834 */
2835Outlayer.prototype.unignore = function( elem ) {
2836  var item = this.getItem( elem );
2837  if ( item ) {
2838    delete item.isIgnored;
2839  }
2840};
2841
2842/**
2843 * adds elements to stamps
2844 * @param {NodeList, Array, Element, or String} elems
2845 */
2846Outlayer.prototype.stamp = function( elems ) {
2847  elems = this._find( elems );
2848  if ( !elems ) {
2849    return;
2850  }
2851
2852  this.stamps = this.stamps.concat( elems );
2853  // ignore
2854  for ( var i=0, len = elems.length; i < len; i++ ) {
2855    var elem = elems[i];
2856    this.ignore( elem );
2857  }
2858};
2859
2860/**
2861 * removes elements to stamps
2862 * @param {NodeList, Array, or Element} elems
2863 */
2864Outlayer.prototype.unstamp = function( elems ) {
2865  elems = this._find( elems );
2866  if ( !elems ){
2867    return;
2868  }
2869
2870  for ( var i=0, len = elems.length; i < len; i++ ) {
2871    var elem = elems[i];
2872    // filter out removed stamp elements
2873    utils.removeFrom( this.stamps, elem );
2874    this.unignore( elem );
2875  }
2876
2877};
2878
2879/**
2880 * finds child elements
2881 * @param {NodeList, Array, Element, or String} elems
2882 * @returns {Array} elems
2883 */
2884Outlayer.prototype._find = function( elems ) {
2885  if ( !elems ) {
2886    return;
2887  }
2888  // if string, use argument as selector string
2889  if ( typeof elems === 'string' ) {
2890    elems = this.element.querySelectorAll( elems );
2891  }
2892  elems = utils.makeArray( elems );
2893  return elems;
2894};
2895
2896Outlayer.prototype._manageStamps = function() {
2897  if ( !this.stamps || !this.stamps.length ) {
2898    return;
2899  }
2900
2901  this._getBoundingRect();
2902
2903  for ( var i=0, len = this.stamps.length; i < len; i++ ) {
2904    var stamp = this.stamps[i];
2905    this._manageStamp( stamp );
2906  }
2907};
2908
2909// update boundingLeft / Top
2910Outlayer.prototype._getBoundingRect = function() {
2911  // get bounding rect for container element
2912  var boundingRect = this.element.getBoundingClientRect();
2913  var size = this.size;
2914  this._boundingRect = {
2915    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2916    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2917    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2918    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2919  };
2920};
2921
2922/**
2923 * @param {Element} stamp
2924**/
2925Outlayer.prototype._manageStamp = noop;
2926
2927/**
2928 * get x/y position of element relative to container element
2929 * @param {Element} elem
2930 * @returns {Object} offset - has left, top, right, bottom
2931 */
2932Outlayer.prototype._getElementOffset = function( elem ) {
2933  var boundingRect = elem.getBoundingClientRect();
2934  var thisRect = this._boundingRect;
2935  var size = getSize( elem );
2936  var offset = {
2937    left: boundingRect.left - thisRect.left - size.marginLeft,
2938    top: boundingRect.top - thisRect.top - size.marginTop,
2939    right: thisRect.right - boundingRect.right - size.marginRight,
2940    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2941  };
2942  return offset;
2943};
2944
2945// -------------------------- resize -------------------------- //
2946
2947// enable event handlers for listeners
2948// i.e. resize -> onresize
2949Outlayer.prototype.handleEvent = function( event ) {
2950  var method = 'on' + event.type;
2951  if ( this[ method ] ) {
2952    this[ method ]( event );
2953  }
2954};
2955
2956/**
2957 * Bind layout to window resizing
2958 */
2959Outlayer.prototype.bindResize = function() {
2960  // bind just one listener
2961  if ( this.isResizeBound ) {
2962    return;
2963  }
2964  eventie.bind( window, 'resize', this );
2965  this.isResizeBound = true;
2966};
2967
2968/**
2969 * Unbind layout to window resizing
2970 */
2971Outlayer.prototype.unbindResize = function() {
2972  if ( this.isResizeBound ) {
2973    eventie.unbind( window, 'resize', this );
2974  }
2975  this.isResizeBound = false;
2976};
2977
2978// original debounce by John Hann
2979// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
2980
2981// this fires every resize
2982Outlayer.prototype.onresize = function() {
2983  if ( this.resizeTimeout ) {
2984    clearTimeout( this.resizeTimeout );
2985  }
2986
2987  var _this = this;
2988  function delayed() {
2989    _this.resize();
2990    delete _this.resizeTimeout;
2991  }
2992
2993  this.resizeTimeout = setTimeout( delayed, 100 );
2994};
2995
2996// debounced, layout on resize
2997Outlayer.prototype.resize = function() {
2998  // don't trigger if size did not change
2999  // or if resize was unbound. See #9
3000  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
3001    return;
3002  }
3003
3004  this.layout();
3005};
3006
3007/**
3008 * check if layout is needed post layout
3009 * @returns Boolean
3010 */
3011Outlayer.prototype.needsResizeLayout = function() {
3012  var size = getSize( this.element );
3013  // check that this.size and size are there
3014  // IE8 triggers resize on body size change, so they might not be
3015  var hasSizes = this.size && size;
3016  return hasSizes && size.innerWidth !== this.size.innerWidth;
3017};
3018
3019// -------------------------- methods -------------------------- //
3020
3021/**
3022 * add items to Outlayer instance
3023 * @param {Array or NodeList or Element} elems
3024 * @returns {Array} items - Outlayer.Items
3025**/
3026Outlayer.prototype.addItems = function( elems ) {
3027  var items = this._itemize( elems );
3028  // add items to collection
3029  if ( items.length ) {
3030    this.items = this.items.concat( items );
3031  }
3032  return items;
3033};
3034
3035/**
3036 * Layout newly-appended item elements
3037 * @param {Array or NodeList or Element} elems
3038 */
3039Outlayer.prototype.appended = function( elems ) {
3040  var items = this.addItems( elems );
3041  if ( !items.length ) {
3042    return;
3043  }
3044  // layout and reveal just the new items
3045  this.layoutItems( items, true );
3046  this.reveal( items );
3047};
3048
3049/**
3050 * Layout prepended elements
3051 * @param {Array or NodeList or Element} elems
3052 */
3053Outlayer.prototype.prepended = function( elems ) {
3054  var items = this._itemize( elems );
3055  if ( !items.length ) {
3056    return;
3057  }
3058  // add items to beginning of collection
3059  var previousItems = this.items.slice(0);
3060  this.items = items.concat( previousItems );
3061  // start new layout
3062  this._resetLayout();
3063  this._manageStamps();
3064  // layout new stuff without transition
3065  this.layoutItems( items, true );
3066  this.reveal( items );
3067  // layout previous items
3068  this.layoutItems( previousItems );
3069};
3070
3071/**
3072 * reveal a collection of items
3073 * @param {Array of Outlayer.Items} items
3074 */
3075Outlayer.prototype.reveal = function( items ) {
3076  this._emitCompleteOnItems( 'reveal', items );
3077
3078  var len = items && items.length;
3079  for ( var i=0; len && i < len; i++ ) {
3080    var item = items[i];
3081    item.reveal();
3082  }
3083};
3084
3085/**
3086 * hide a collection of items
3087 * @param {Array of Outlayer.Items} items
3088 */
3089Outlayer.prototype.hide = function( items ) {
3090  this._emitCompleteOnItems( 'hide', items );
3091
3092  var len = items && items.length;
3093  for ( var i=0; len && i < len; i++ ) {
3094    var item = items[i];
3095    item.hide();
3096  }
3097};
3098
3099/**
3100 * reveal item elements
3101 * @param {Array}, {Element}, {NodeList} items
3102 */
3103Outlayer.prototype.revealItemElements = function( elems ) {
3104  var items = this.getItems( elems );
3105  this.reveal( items );
3106};
3107
3108/**
3109 * hide item elements
3110 * @param {Array}, {Element}, {NodeList} items
3111 */
3112Outlayer.prototype.hideItemElements = function( elems ) {
3113  var items = this.getItems( elems );
3114  this.hide( items );
3115};
3116
3117/**
3118 * get Outlayer.Item, given an Element
3119 * @param {Element} elem
3120 * @param {Function} callback
3121 * @returns {Outlayer.Item} item
3122 */
3123Outlayer.prototype.getItem = function( elem ) {
3124  // loop through items to get the one that matches
3125  for ( var i=0, len = this.items.length; i < len; i++ ) {
3126    var item = this.items[i];
3127    if ( item.element === elem ) {
3128      // return item
3129      return item;
3130    }
3131  }
3132};
3133
3134/**
3135 * get collection of Outlayer.Items, given Elements
3136 * @param {Array} elems
3137 * @returns {Array} items - Outlayer.Items
3138 */
3139Outlayer.prototype.getItems = function( elems ) {
3140  elems = utils.makeArray( elems );
3141  var items = [];
3142  for ( var i=0, len = elems.length; i < len; i++ ) {
3143    var elem = elems[i];
3144    var item = this.getItem( elem );
3145    if ( item ) {
3146      items.push( item );
3147    }
3148  }
3149
3150  return items;
3151};
3152
3153/**
3154 * remove element(s) from instance and DOM
3155 * @param {Array or NodeList or Element} elems
3156 */
3157Outlayer.prototype.remove = function( elems ) {
3158  var removeItems = this.getItems( elems );
3159
3160  this._emitCompleteOnItems( 'remove', removeItems );
3161
3162  // bail if no items to remove
3163  if ( !removeItems || !removeItems.length ) {
3164    return;
3165  }
3166
3167  for ( var i=0, len = removeItems.length; i < len; i++ ) {
3168    var item = removeItems[i];
3169    item.remove();
3170    // remove item from collection
3171    utils.removeFrom( this.items, item );
3172  }
3173};
3174
3175// ----- destroy ----- //
3176
3177// remove and disable Outlayer instance
3178Outlayer.prototype.destroy = function() {
3179  // clean up dynamic styles
3180  var style = this.element.style;
3181  style.height = '';
3182  style.position = '';
3183  style.width = '';
3184  // destroy items
3185  for ( var i=0, len = this.items.length; i < len; i++ ) {
3186    var item = this.items[i];
3187    item.destroy();
3188  }
3189
3190  this.unbindResize();
3191
3192  var id = this.element.outlayerGUID;
3193  delete instances[ id ]; // remove reference to instance by id
3194  delete this.element.outlayerGUID;
3195  // remove data for jQuery
3196  if ( jQuery ) {
3197    jQuery.removeData( this.element, this.constructor.namespace );
3198  }
3199
3200};
3201
3202// -------------------------- data -------------------------- //
3203
3204/**
3205 * get Outlayer instance from element
3206 * @param {Element} elem
3207 * @returns {Outlayer}
3208 */
3209Outlayer.data = function( elem ) {
3210  elem = utils.getQueryElement( elem );
3211  var id = elem && elem.outlayerGUID;
3212  return id && instances[ id ];
3213};
3214
3215
3216// -------------------------- create Outlayer class -------------------------- //
3217
3218/**
3219 * create a layout class
3220 * @param {String} namespace
3221 */
3222Outlayer.create = function( namespace, options ) {
3223  // sub-class Outlayer
3224  function Layout() {
3225    Outlayer.apply( this, arguments );
3226  }
3227  // inherit Outlayer prototype, use Object.create if there
3228  if ( Object.create ) {
3229    Layout.prototype = Object.create( Outlayer.prototype );
3230  } else {
3231    utils.extend( Layout.prototype, Outlayer.prototype );
3232  }
3233  // set contructor, used for namespace and Item
3234  Layout.prototype.constructor = Layout;
3235
3236  Layout.defaults = utils.extend( {}, Outlayer.defaults );
3237  // apply new options
3238  utils.extend( Layout.defaults, options );
3239  // keep prototype.settings for backwards compatibility (Packery v1.2.0)
3240  Layout.prototype.settings = {};
3241
3242  Layout.namespace = namespace;
3243
3244  Layout.data = Outlayer.data;
3245
3246  // sub-class Item
3247  Layout.Item = function LayoutItem() {
3248    Item.apply( this, arguments );
3249  };
3250
3251  Layout.Item.prototype = new Item();
3252
3253  // -------------------------- declarative -------------------------- //
3254
3255  utils.htmlInit( Layout, namespace );
3256
3257  // -------------------------- jQuery bridge -------------------------- //
3258
3259  // make into jQuery plugin
3260  if ( jQuery && jQuery.bridget ) {
3261    jQuery.bridget( namespace, Layout );
3262  }
3263
3264  return Layout;
3265};
3266
3267// ----- fin ----- //
3268
3269// back in global
3270Outlayer.Item = Item;
3271
3272return Outlayer;
3273
3274}));
3275
3276
3277/**
3278 * Isotope Item
3279**/
3280
3281( function( window, factory ) {
3282'use strict';
3283  // universal module definition
3284  if ( typeof define == 'function' && define.amd ) {
3285    // AMD
3286    define( 'isotope/js/item',[
3287        'outlayer/outlayer'
3288      ],
3289      factory );
3290  } else if ( typeof exports == 'object' ) {
3291    // CommonJS
3292    module.exports = factory(
3293      require('outlayer')
3294    );
3295  } else {
3296    // browser global
3297    window.Isotope = window.Isotope || {};
3298    window.Isotope.Item = factory(
3299      window.Outlayer
3300    );
3301  }
3302
3303}( window, function factory( Outlayer ) {
3304'use strict';
3305
3306// -------------------------- Item -------------------------- //
3307
3308// sub-class Outlayer Item
3309function Item() {
3310  Outlayer.Item.apply( this, arguments );
3311}
3312
3313Item.prototype = new Outlayer.Item();
3314
3315Item.prototype._create = function() {
3316  // assign id, used for original-order sorting
3317  this.id = this.layout.itemGUID++;
3318  Outlayer.Item.prototype._create.call( this );
3319  this.sortData = {};
3320};
3321
3322Item.prototype.updateSortData = function() {
3323  if ( this.isIgnored ) {
3324    return;
3325  }
3326  // default sorters
3327  this.sortData.id = this.id;
3328  // for backward compatibility
3329  this.sortData['original-order'] = this.id;
3330  this.sortData.random = Math.random();
3331  // go thru getSortData obj and apply the sorters
3332  var getSortData = this.layout.options.getSortData;
3333  var sorters = this.layout._sorters;
3334  for ( var key in getSortData ) {
3335    var sorter = sorters[ key ];
3336    this.sortData[ key ] = sorter( this.element, this );
3337  }
3338};
3339
3340var _destroy = Item.prototype.destroy;
3341Item.prototype.destroy = function() {
3342  // call super
3343  _destroy.apply( this, arguments );
3344  // reset display, #741
3345  this.css({
3346    display: ''
3347  });
3348};
3349
3350return Item;
3351
3352}));
3353
3354/**
3355 * Isotope LayoutMode
3356 */
3357
3358( function( window, factory ) {
3359  'use strict';
3360  // universal module definition
3361
3362  if ( typeof define == 'function' && define.amd ) {
3363    // AMD
3364    define( 'isotope/js/layout-mode',[
3365        'get-size/get-size',
3366        'outlayer/outlayer'
3367      ],
3368      factory );
3369  } else if ( typeof exports == 'object' ) {
3370    // CommonJS
3371    module.exports = factory(
3372      require('get-size'),
3373      require('outlayer')
3374    );
3375  } else {
3376    // browser global
3377    window.Isotope = window.Isotope || {};
3378    window.Isotope.LayoutMode = factory(
3379      window.getSize,
3380      window.Outlayer
3381    );
3382  }
3383
3384}( window, function factory( getSize, Outlayer ) {
3385  'use strict';
3386
3387  // layout mode class
3388  function LayoutMode( isotope ) {
3389    this.isotope = isotope;
3390    // link properties
3391    if ( isotope ) {
3392      this.options = isotope.options[ this.namespace ];
3393      this.element = isotope.element;
3394      this.items = isotope.filteredItems;
3395      this.size = isotope.size;
3396    }
3397  }
3398
3399  /**
3400   * some methods should just defer to default Outlayer method
3401   * and reference the Isotope instance as `this`
3402  **/
3403  ( function() {
3404    var facadeMethods = [
3405      '_resetLayout',
3406      '_getItemLayoutPosition',
3407      '_manageStamp',
3408      '_getContainerSize',
3409      '_getElementOffset',
3410      'needsResizeLayout'
3411    ];
3412
3413    for ( var i=0, len = facadeMethods.length; i < len; i++ ) {
3414      var methodName = facadeMethods[i];
3415      LayoutMode.prototype[ methodName ] = getOutlayerMethod( methodName );
3416    }
3417
3418    function getOutlayerMethod( methodName ) {
3419      return function() {
3420        return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
3421      };
3422    }
3423  })();
3424
3425  // -----  ----- //
3426
3427  // for horizontal layout modes, check vertical size
3428  LayoutMode.prototype.needsVerticalResizeLayout = function() {
vendor: 20,029 bytes, lines 3429-4164
3429    // don't trigger if size did not change
3430    var size = getSize( this.isotope.element );
3431    // check that this.size and size are there
3432    // IE8 triggers resize on body size change, so they might not be
3433    var hasSizes = this.isotope.size && size;
3434    return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
3435  };
3436
3437  // ----- measurements ----- //
3438
3439  LayoutMode.prototype._getMeasurement = function() {
3440    this.isotope._getMeasurement.apply( this, arguments );
3441  };
3442
3443  LayoutMode.prototype.getColumnWidth = function() {
3444    this.getSegmentSize( 'column', 'Width' );
3445  };
3446
3447  LayoutMode.prototype.getRowHeight = function() {
3448    this.getSegmentSize( 'row', 'Height' );
3449  };
3450
3451  /**
3452   * get columnWidth or rowHeight
3453   * segment: 'column' or 'row'
3454   * size 'Width' or 'Height'
3455  **/
3456  LayoutMode.prototype.getSegmentSize = function( segment, size ) {
3457    var segmentName = segment + size;
3458    var outerSize = 'outer' + size;
3459    // columnWidth / outerWidth // rowHeight / outerHeight
3460    this._getMeasurement( segmentName, outerSize );
3461    // got rowHeight or columnWidth, we can chill
3462    if ( this[ segmentName ] ) {
3463      return;
3464    }
3465    // fall back to item of first element
3466    var firstItemSize = this.getFirstItemSize();
3467    this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
3468      // or size of container
3469      this.isotope.size[ 'inner' + size ];
3470  };
3471
3472  LayoutMode.prototype.getFirstItemSize = function() {
3473    var firstItem = this.isotope.filteredItems[0];
3474    return firstItem && firstItem.element && getSize( firstItem.element );
3475  };
3476
3477  // ----- methods that should reference isotope ----- //
3478
3479  LayoutMode.prototype.layout = function() {
3480    this.isotope.layout.apply( this.isotope, arguments );
3481  };
3482
3483  LayoutMode.prototype.getSize = function() {
3484    this.isotope.getSize();
3485    this.size = this.isotope.size;
3486  };
3487
3488  // -------------------------- create -------------------------- //
3489
3490  LayoutMode.modes = {};
3491
3492  LayoutMode.create = function( namespace, options ) {
3493
3494    function Mode() {
3495      LayoutMode.apply( this, arguments );
3496    }
3497
3498    Mode.prototype = new LayoutMode();
3499
3500    // default options
3501    if ( options ) {
3502      Mode.options = options;
3503    }
3504
3505    Mode.prototype.namespace = namespace;
3506    // register in Isotope
3507    LayoutMode.modes[ namespace ] = Mode;
3508
3509    return Mode;
3510  };
3511
3512  return LayoutMode;
3513
3514}));
3515
3516/*!
3517 * Masonry v3.3.1
3518 * Cascading grid layout library
3519 * http://masonry.desandro.com
3520 * MIT License
3521 * by David DeSandro
3522 */
3523
3524( function( window, factory ) {
3525  'use strict';
3526  // universal module definition
3527  if ( typeof define === 'function' && define.amd ) {
3528    // AMD
3529    define( 'masonry/masonry',[
3530        'outlayer/outlayer',
3531        'get-size/get-size',
3532        'fizzy-ui-utils/utils'
3533      ],
3534      factory );
3535  } else if ( typeof exports === 'object' ) {
3536    // CommonJS
3537    module.exports = factory(
3538      require('outlayer'),
3539      require('get-size'),
3540      require('fizzy-ui-utils')
3541    );
3542  } else {
3543    // browser global
3544    window.Masonry = factory(
3545      window.Outlayer,
3546      window.getSize,
3547      window.fizzyUIUtils
3548    );
3549  }
3550
3551}( window, function factory( Outlayer, getSize, utils ) {
3552
3553
3554
3555// -------------------------- masonryDefinition -------------------------- //
3556
3557  // create an Outlayer layout class
3558  var Masonry = Outlayer.create('masonry');
3559
3560  Masonry.prototype._resetLayout = function() {
3561    this.getSize();
3562    this._getMeasurement( 'columnWidth', 'outerWidth' );
3563    this._getMeasurement( 'gutter', 'outerWidth' );
3564    this.measureColumns();
3565
3566    // reset column Y
3567    var i = this.cols;
3568    this.colYs = [];
3569    while (i--) {
3570      this.colYs.push( 0 );
3571    }
3572
3573    this.maxY = 0;
3574  };
3575
3576  Masonry.prototype.measureColumns = function() {
3577    this.getContainerWidth();
3578    // if columnWidth is 0, default to outerWidth of first item
3579    if ( !this.columnWidth ) {
3580      var firstItem = this.items[0];
3581      var firstItemElem = firstItem && firstItem.element;
3582      // columnWidth fall back to item of first element
3583      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
3584        // if first elem has no width, default to size of container
3585        this.containerWidth;
3586    }
3587
3588    var columnWidth = this.columnWidth += this.gutter;
3589
3590    // calculate columns
3591    var containerWidth = this.containerWidth + this.gutter;
3592    var cols = containerWidth / columnWidth;
3593    // fix rounding errors, typically with gutters
3594    var excess = columnWidth - containerWidth % columnWidth;
3595    // if overshoot is less than a pixel, round up, otherwise floor it
3596    var mathMethod = excess && excess < 1 ? 'round' : 'floor';
3597    cols = Math[ mathMethod ]( cols );
3598    this.cols = Math.max( cols, 1 );
3599  };
3600
3601  Masonry.prototype.getContainerWidth = function() {
3602    // container is parent if fit width
3603    var container = this.options.isFitWidth ? this.element.parentNode : this.element;
3604    // check that this.size and size are there
3605    // IE8 triggers resize on body size change, so they might not be
3606    var size = getSize( container );
3607    this.containerWidth = size && size.innerWidth;
3608  };
3609
3610  Masonry.prototype._getItemLayoutPosition = function( item ) {
3611    item.getSize();
3612    // how many columns does this brick span
3613    var remainder = item.size.outerWidth % this.columnWidth;
3614    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
3615    // round if off by 1 pixel, otherwise use ceil
3616    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
3617    colSpan = Math.min( colSpan, this.cols );
3618
3619    var colGroup = this._getColGroup( colSpan );
3620    // get the minimum Y value from the columns
3621    var minimumY = Math.min.apply( Math, colGroup );
3622    var shortColIndex = utils.indexOf( colGroup, minimumY );
3623
3624    // position the brick
3625    var position = {
3626      x: this.columnWidth * shortColIndex,
3627      y: minimumY
3628    };
3629
3630    // apply setHeight to necessary columns
3631    var setHeight = minimumY + item.size.outerHeight;
3632    var setSpan = this.cols + 1 - colGroup.length;
3633    for ( var i = 0; i < setSpan; i++ ) {
3634      this.colYs[ shortColIndex + i ] = setHeight;
3635    }
3636
3637    return position;
3638  };
3639
3640  /**
3641   * @param {Number} colSpan - number of columns the element spans
3642   * @returns {Array} colGroup
3643   */
3644  Masonry.prototype._getColGroup = function( colSpan ) {
3645    if ( colSpan < 2 ) {
3646      // if brick spans only one column, use all the column Ys
3647      return this.colYs;
3648    }
3649
3650    var colGroup = [];
3651    // how many different places could this brick fit horizontally
3652    var groupCount = this.cols + 1 - colSpan;
3653    // for each group potential horizontal position
3654    for ( var i = 0; i < groupCount; i++ ) {
3655      // make an array of colY values for that one group
3656      var groupColYs = this.colYs.slice( i, i + colSpan );
3657      // and get the max value of the array
3658      colGroup[i] = Math.max.apply( Math, groupColYs );
3659    }
3660    return colGroup;
3661  };
3662
3663  Masonry.prototype._manageStamp = function( stamp ) {
3664    var stampSize = getSize( stamp );
3665    var offset = this._getElementOffset( stamp );
3666    // get the columns that this stamp affects
3667    var firstX = this.options.isOriginLeft ? offset.left : offset.right;
3668    var lastX = firstX + stampSize.outerWidth;
3669    var firstCol = Math.floor( firstX / this.columnWidth );
3670    firstCol = Math.max( 0, firstCol );
3671    var lastCol = Math.floor( lastX / this.columnWidth );
3672    // lastCol should not go over if multiple of columnWidth #425
3673    lastCol -= lastX % this.columnWidth ? 0 : 1;
3674    lastCol = Math.min( this.cols - 1, lastCol );
3675    // set colYs to bottom of the stamp
3676    var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) +
3677      stampSize.outerHeight;
3678    for ( var i = firstCol; i <= lastCol; i++ ) {
3679      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
3680    }
3681  };
3682
3683  Masonry.prototype._getContainerSize = function() {
3684    this.maxY = Math.max.apply( Math, this.colYs );
3685    var size = {
3686      height: this.maxY
3687    };
3688
3689    if ( this.options.isFitWidth ) {
3690      size.width = this._getContainerFitWidth();
3691    }
3692
3693    return size;
3694  };
3695
3696  Masonry.prototype._getContainerFitWidth = function() {
3697    var unusedCols = 0;
3698    // count unused columns
3699    var i = this.cols;
3700    while ( --i ) {
3701      if ( this.colYs[i] !== 0 ) {
3702        break;
3703      }
3704      unusedCols++;
3705    }
3706    // fit container to columns that have been used
3707    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
3708  };
3709
3710  Masonry.prototype.needsResizeLayout = function() {
3711    var previousWidth = this.containerWidth;
3712    this.getContainerWidth();
3713    return previousWidth !== this.containerWidth;
3714  };
3715
3716  return Masonry;
3717
3718}));
3719
3720/*!
3721 * Masonry layout mode
3722 * sub-classes Masonry
3723 * http://masonry.desandro.com
3724 */
3725
3726( function( window, factory ) {
3727  'use strict';
3728  // universal module definition
3729  if ( typeof define == 'function' && define.amd ) {
3730    // AMD
3731    define( 'isotope/js/layout-modes/masonry',[
3732        '../layout-mode',
3733        'masonry/masonry'
3734      ],
3735      factory );
3736  } else if ( typeof exports == 'object' ) {
3737    // CommonJS
3738    module.exports = factory(
3739      require('../layout-mode'),
3740      require('masonry-layout')
3741    );
3742  } else {
3743    // browser global
3744    factory(
3745      window.Isotope.LayoutMode,
3746      window.Masonry
3747    );
3748  }
3749
3750}( window, function factory( LayoutMode, Masonry ) {
3751'use strict';
3752
3753// -------------------------- helpers -------------------------- //
3754
3755// extend objects
3756function extend( a, b ) {
3757  for ( var prop in b ) {
3758    a[ prop ] = b[ prop ];
3759  }
3760  return a;
3761}
3762
3763// -------------------------- masonryDefinition -------------------------- //
3764
3765  // create an Outlayer layout class
3766  var MasonryMode = LayoutMode.create('masonry');
3767
3768  // save on to these methods
3769  var _getElementOffset = MasonryMode.prototype._getElementOffset;
3770  var layout = MasonryMode.prototype.layout;
3771  var _getMeasurement = MasonryMode.prototype._getMeasurement;
3772
3773  // sub-class Masonry
3774  extend( MasonryMode.prototype, Masonry.prototype );
3775
3776  // set back, as it was overwritten by Masonry
3777  MasonryMode.prototype._getElementOffset = _getElementOffset;
3778  MasonryMode.prototype.layout = layout;
3779  MasonryMode.prototype._getMeasurement = _getMeasurement;
3780
3781  var measureColumns = MasonryMode.prototype.measureColumns;
3782  MasonryMode.prototype.measureColumns = function() {
3783    // set items, used if measuring first item
3784    this.items = this.isotope.filteredItems;
3785    measureColumns.call( this );
3786  };
3787
3788  // HACK copy over isOriginLeft/Top options
3789  var _manageStamp = MasonryMode.prototype._manageStamp;
3790  MasonryMode.prototype._manageStamp = function() {
3791    this.options.isOriginLeft = this.isotope.options.isOriginLeft;
3792    this.options.isOriginTop = this.isotope.options.isOriginTop;
3793    _manageStamp.apply( this, arguments );
3794  };
3795
3796  return MasonryMode;
3797
3798}));
3799
3800/**
3801 * fitRows layout mode
3802 */
3803
3804( function( window, factory ) {
3805  'use strict';
3806  // universal module definition
3807  if ( typeof define == 'function' && define.amd ) {
3808    // AMD
3809    define( 'isotope/js/layout-modes/fit-rows',[
3810        '../layout-mode'
3811      ],
3812      factory );
3813  } else if ( typeof exports == 'object' ) {
3814    // CommonJS
3815    module.exports = factory(
3816      require('../layout-mode')
3817    );
3818  } else {
3819    // browser global
3820    factory(
3821      window.Isotope.LayoutMode
3822    );
3823  }
3824
3825}( window, function factory( LayoutMode ) {
3826'use strict';
3827
3828var FitRows = LayoutMode.create('fitRows');
3829
3830FitRows.prototype._resetLayout = function() {
3831  this.x = 0;
3832  this.y = 0;
3833  this.maxY = 0;
3834  this._getMeasurement( 'gutter', 'outerWidth' );
3835};
3836
3837FitRows.prototype._getItemLayoutPosition = function( item ) {
3838  item.getSize();
3839
3840  var itemWidth = item.size.outerWidth + this.gutter;
3841  // if this element cannot fit in the current row
3842  var containerWidth = this.isotope.size.innerWidth + this.gutter;
3843  if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
3844    this.x = 0;
3845    this.y = this.maxY;
3846  }
3847
3848  var position = {
3849    x: this.x,
3850    y: this.y
3851  };
3852
3853  this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
3854  this.x += itemWidth;
3855
3856  return position;
3857};
3858
3859FitRows.prototype._getContainerSize = function() {
3860  return { height: this.maxY };
3861};
3862
3863return FitRows;
3864
3865}));
3866
3867/**
3868 * vertical layout mode
3869 */
3870
3871( function( window, factory ) {
3872  'use strict';
3873  // universal module definition
3874  if ( typeof define == 'function' && define.amd ) {
3875    // AMD
3876    define( 'isotope/js/layout-modes/vertical',[
3877        '../layout-mode'
3878      ],
3879      factory );
3880  } else if ( typeof exports == 'object' ) {
3881    // CommonJS
3882    module.exports = factory(
3883      require('../layout-mode')
3884    );
3885  } else {
3886    // browser global
3887    factory(
3888      window.Isotope.LayoutMode
3889    );
3890  }
3891
3892}( window, function factory( LayoutMode ) {
3893'use strict';
3894
3895var Vertical = LayoutMode.create( 'vertical', {
3896  horizontalAlignment: 0
3897});
3898
3899Vertical.prototype._resetLayout = function() {
3900  this.y = 0;
3901};
3902
3903Vertical.prototype._getItemLayoutPosition = function( item ) {
3904  item.getSize();
3905  var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
3906    this.options.horizontalAlignment;
3907  var y = this.y;
3908  this.y += item.size.outerHeight;
3909  return { x: x, y: y };
3910};
3911
3912Vertical.prototype._getContainerSize = function() {
3913  return { height: this.y };
3914};
3915
3916return Vertical;
3917
3918}));
3919
3920/*!
3921 * Isotope v2.2.2
3922 *
3923 * Licensed GPLv3 for open source use
3924 * or Isotope Commercial License for commercial use
3925 *
3926 * http://isotope.metafizzy.co
3927 * Copyright 2015 Metafizzy
3928 */
3929
3930( function( window, factory ) {
3931  'use strict';
3932  // universal module definition
3933
3934  if ( typeof define == 'function' && define.amd ) {
3935    // AMD
3936    define( [
3937        'outlayer/outlayer',
3938        'get-size/get-size',
3939        'matches-selector/matches-selector',
3940        'fizzy-ui-utils/utils',
3941        'isotope/js/item',
3942        'isotope/js/layout-mode',
3943        // include default layout modes
3944        'isotope/js/layout-modes/masonry',
3945        'isotope/js/layout-modes/fit-rows',
3946        'isotope/js/layout-modes/vertical'
3947      ],
3948      function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
3949        return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
3950      });
3951  } else if ( typeof exports == 'object' ) {
3952    // CommonJS
3953    module.exports = factory(
3954      window,
3955      require('outlayer'),
3956      require('get-size'),
3957      require('desandro-matches-selector'),
3958      require('fizzy-ui-utils'),
3959      require('./item'),
3960      require('./layout-mode'),
3961      // include default layout modes
3962      require('./layout-modes/masonry'),
3963      require('./layout-modes/fit-rows'),
3964      require('./layout-modes/vertical')
3965    );
3966  } else {
3967    // browser global
3968    window.Isotope = factory(
3969      window,
3970      window.Outlayer,
3971      window.getSize,
3972      window.matchesSelector,
3973      window.fizzyUIUtils,
3974      window.Isotope.Item,
3975      window.Isotope.LayoutMode
3976    );
3977  }
3978
3979}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
3980  Item, LayoutMode ) {
3981
3982
3983
3984// -------------------------- vars -------------------------- //
3985
3986var jQuery = window.jQuery;
3987
3988// -------------------------- helpers -------------------------- //
3989
3990var trim = String.prototype.trim ?
3991  function( str ) {
3992    return str.trim();
3993  } :
3994  function( str ) {
3995    return str.replace( /^\s+|\s+$/g, '' );
3996  };
3997
3998var docElem = document.documentElement;
3999
4000var getText = docElem.textContent ?
4001  function( elem ) {
4002    return elem.textContent;
4003  } :
4004  function( elem ) {
4005    return elem.innerText;
4006  };
4007
4008// -------------------------- isotopeDefinition -------------------------- //
4009
4010  // create an Outlayer layout class
4011  var Isotope = Outlayer.create( 'isotope', {
4012    layoutMode: "masonry",
4013    isJQueryFiltering: true,
4014    sortAscending: true
4015  });
4016
4017  Isotope.Item = Item;
4018  Isotope.LayoutMode = LayoutMode;
4019
4020  Isotope.prototype._create = function() {
4021    this.itemGUID = 0;
4022    // functions that sort items
4023    this._sorters = {};
4024    this._getSorters();
4025    // call super
4026    Outlayer.prototype._create.call( this );
4027
4028    // create layout modes
4029    this.modes = {};
4030    // start filteredItems with all items
4031    this.filteredItems = this.items;
4032    // keep of track of sortBys
4033    this.sortHistory = [ 'original-order' ];
4034    // create from registered layout modes
4035    for ( var name in LayoutMode.modes ) {
4036      this._initLayoutMode( name );
4037    }
4038  };
4039
4040  Isotope.prototype.reloadItems = function() {
4041    // reset item ID counter
4042    this.itemGUID = 0;
4043    // call super
4044    Outlayer.prototype.reloadItems.call( this );
4045  };
4046
4047  Isotope.prototype._itemize = function() {
4048    var items = Outlayer.prototype._itemize.apply( this, arguments );
4049    // assign ID for original-order
4050    for ( var i=0, len = items.length; i < len; i++ ) {
4051      var item = items[i];
4052      item.id = this.itemGUID++;
4053    }
4054    this._updateItemsSortData( items );
4055    return items;
4056  };
4057
4058
4059  // -------------------------- layout -------------------------- //
4060
4061  Isotope.prototype._initLayoutMode = function( name ) {
4062    var Mode = LayoutMode.modes[ name ];
4063    // set mode options
4064    // HACK extend initial options, back-fill in default options
4065    var initialOpts = this.options[ name ] || {};
4066    this.options[ name ] = Mode.options ?
4067      utils.extend( Mode.options, initialOpts ) : initialOpts;
4068    // init layout mode instance
4069    this.modes[ name ] = new Mode( this );
4070  };
4071
4072
4073  Isotope.prototype.layout = function() {
4074    // if first time doing layout, do all magic
4075    if ( !this._isLayoutInited && this.options.isInitLayout ) {
4076      this.arrange();
4077      return;
4078    }
4079    this._layout();
4080  };
4081
4082  // private method to be used in layout() & magic()
4083  Isotope.prototype._layout = function() {
4084    // don't animate first layout
4085    var isInstant = this._getIsInstant();
4086    // layout flow
4087    this._resetLayout();
4088    this._manageStamps();
4089    this.layoutItems( this.filteredItems, isInstant );
4090
4091    // flag for initalized
4092    this._isLayoutInited = true;
4093  };
4094
4095  // filter + sort + layout
4096  Isotope.prototype.arrange = function( opts ) {
4097    // set any options pass
4098    this.option( opts );
4099    this._getIsInstant();
4100    // filter, sort, and layout
4101
4102    // filter
4103    var filtered = this._filter( this.items );
4104    this.filteredItems = filtered.matches;
4105
4106    var _this = this;
4107    function hideReveal() {
4108      _this.reveal( filtered.needReveal );
4109      _this.hide( filtered.needHide );
4110    }
4111
4112    this._bindArrangeComplete();
4113
4114    if ( this._isInstant ) {
4115      this._noTransition( hideReveal );
4116    } else {
4117      hideReveal();
4118    }
4119
4120    this._sort();
4121    this._layout();
4122  };
4123  // alias to _init for main plugin method
4124  Isotope.prototype._init = Isotope.prototype.arrange;
4125
4126  // HACK
4127  // Don't animate/transition first layout
4128  // Or don't animate/transition other layouts
4129  Isotope.prototype._getIsInstant = function() {
4130    var isInstant = this.options.isLayoutInstant !== undefined ?
4131      this.options.isLayoutInstant : !this._isLayoutInited;
4132    this._isInstant = isInstant;
4133    return isInstant;
4134  };
4135
4136  // listen for layoutComplete, hideComplete and revealComplete
4137  // to trigger arrangeComplete
4138  Isotope.prototype._bindArrangeComplete = function() {
4139    // listen for 3 events to trigger arrangeComplete
4140    var isLayoutComplete, isHideComplete, isRevealComplete;
4141    var _this = this;
4142    function arrangeParallelCallback() {
4143      if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
4144        _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
4145      }
4146    }
4147    this.once( 'layoutComplete', function() {
4148      isLayoutComplete = true;
4149      arrangeParallelCallback();
4150    });
4151    this.once( 'hideComplete', function() {
4152      isHideComplete = true;
4153      arrangeParallelCallback();
4154    });
4155    this.once( 'revealComplete', function() {
4156      isRevealComplete = true;
4157      arrangeParallelCallback();
4158    });
4159  };
4160
4161  // -------------------------- filter -------------------------- //
4162
4163  Isotope.prototype._filter = function( items ) {
4164    var filter = this.options.filter;
4165    filter = filter || '*';
4166    var matches = [];
4167    var hiddenMatched = [];
4168    var visibleUnmatched = [];
4169
4170    var test = this._getFilterTest( filter );
4171
4172    // test each item
4173    for ( var i=0, len = items.length; i < len; i++ ) {
4174      var item = items[i];
4175      if ( item.isIgnored ) {
4176        continue;
4177      }
4178      // add item to either matched or unmatched group
4179      var isMatched = test( item );
4180      // item.isFilterMatched = isMatched;
4181      // add to matches if its a match
4182      if ( isMatched ) {
4183        matches.push( item );
4184      }
4185      // add to additional group if item needs to be hidden or revealed
4186      if ( isMatched && item.isHidden ) {
4187        hiddenMatched.push( item );
4188      } else if ( !isMatched && !item.isHidden ) {
4189        visibleUnmatched.push( item );
4190      }
4191    }
4192
4193    // return collections of items to be manipulated
4194    return {
4195      matches: matches,
4196      needReveal: hiddenMatched,
4197      needHide: visibleUnmatched
4198    };
4199  };
4200
4201  // get a jQuery, function, or a matchesSelector test given the filter
4202  Isotope.prototype._getFilterTest = function( filter ) {
4203    if ( jQuery && this.options.isJQueryFiltering ) {
4204      // use jQuery
4205      return function( item ) {
4206        return jQuery( item.element ).is( filter );
4207      };
4208    }
4209    if ( typeof filter == 'function' ) {
4210      // use filter as function
4211      return function( item ) {
4212        return filter( item.element );
4213      };
4214    }
4215    // default, use filter as selector string
4216    return function( item ) {
4217      return matchesSelector( item.element, filter );
4218    };
4219  };
4220
4221  // -------------------------- sorting -------------------------- //
4222
4223  /**
4224   * @params {Array} elems
4225   * @public
4226   */
4227  Isotope.prototype.updateSortData = function( elems ) {
4228    // get items
4229    var items;
4230    if ( elems ) {
4231      elems = utils.makeArray( elems );
4232      items = this.getItems( elems );
4233    } else {
4234      // update all items if no elems provided
4235      items = this.items;
4236    }
4237
4238    this._getSorters();
4239    this._updateItemsSortData( items );
4240  };
4241
4242  Isotope.prototype._getSorters = function() {
4243    var getSortData = this.options.getSortData;
4244    for ( var key in getSortData ) {
4245      var sorter = getSortData[ key ];
4246      this._sorters[ key ] = mungeSorter( sorter );
4247    }
4248  };
4249
4250  /**
4251   * @params {Array} items - of Isotope.Items
4252   * @private
4253   */
4254  Isotope.prototype._updateItemsSortData = function( items ) {
4255    // do not update if no items
4256    var len = items && items.length;
4257
4258    for ( var i=0; len && i < len; i++ ) {
4259      var item = items[i];
4260      item.updateSortData();
4261    }
4262  };
4263
4264  // ----- munge sorter ----- //
4265
4266  // encapsulate this, as we just need mungeSorter
4267  // other functions in here are just for munging
4268  var mungeSorter = ( function() {
4269    // add a magic layer to sorters for convienent shorthands
4270    // `.foo-bar` will use the text of .foo-bar querySelector
4271    // `[foo-bar]` will use attribute
4272    // you can also add parser
4273    // `.foo-bar parseInt` will parse that as a number
4274    function mungeSorter( sorter ) {
4275      // if not a string, return function or whatever it is
4276      if ( typeof sorter != 'string' ) {
4277        return sorter;
4278      }
4279      // parse the sorter string
4280      var args = trim( sorter ).split(' ');
4281      var query = args[0];
4282      // check if query looks like [an-attribute]
4283      var attrMatch = query.match( /^\[(.+)\]$/ );
4284      var attr = attrMatch && attrMatch[1];
4285      var getValue = getValueGetter( attr, query );
4286      // use second argument as a parser
4287      var parser = Isotope.sortDataParsers[ args[1] ];
4288      // parse the value, if there was a parser
4289      sorter = parser ? function( elem ) {
4290        return elem && parser( getValue( elem ) );
4291      } :
4292      // otherwise just return value
4293      function( elem ) {
4294        return elem && getValue( elem );
4295      };
4296
4297      return sorter;
4298    }
4299
4300    // get an attribute getter, or get text of the querySelector
4301    function getValueGetter( attr, query ) {
4302      var getValue;
4303      // if query looks like [foo-bar], get attribute
4304      if ( attr ) {
4305        getValue = function( elem ) {
4306          return elem.getAttribute( attr );
4307        };
4308      } else {
4309        // otherwise, assume its a querySelector, and get its text
4310        getValue = function( elem ) {
4311          var child = elem.querySelector( query );
4312          return child && getText( child );
4313        };
4314      }
4315      return getValue;
4316    }
4317
4318    return mungeSorter;
4319  })();
4320
4321  // parsers used in getSortData shortcut strings
4322  Isotope.sortDataParsers = {
4323    'parseInt': function( val ) {
4324      return parseInt( val, 10 );
4325    },
4326    'parseFloat': function( val ) {
4327      return parseFloat( val );
4328    }
4329  };
4330
4331  // ----- sort method ----- //
4332
4333  // sort filteredItem order
4334  Isotope.prototype._sort = function() {
4335    var sortByOpt = this.options.sortBy;
4336    if ( !sortByOpt ) {
4337      return;
4338    }
4339    // concat all sortBy and sortHistory
4340    var sortBys = [].concat.apply( sortByOpt, this.sortHistory );
4341    // sort magic
4342    var itemSorter = getItemSorter( sortBys, this.options.sortAscending );
4343    this.filteredItems.sort( itemSorter );
4344    // keep track of sortBy History
4345    if ( sortByOpt != this.sortHistory[0] ) {
4346      // add to front, oldest goes in last
4347      this.sortHistory.unshift( sortByOpt );
4348    }
4349  };
4350
4351  // returns a function used for sorting
4352  function getItemSorter( sortBys, sortAsc ) {
4353    return function sorter( itemA, itemB ) {
4354      // cycle through all sortKeys
4355      for ( var i = 0, len = sortBys.length; i < len; i++ ) {
4356        var sortBy = sortBys[i];
4357        var a = itemA.sortData[ sortBy ];
4358        var b = itemB.sortData[ sortBy ];
4359        if ( a > b || a < b ) {
4360          // if sortAsc is an object, use the value given the sortBy key
4361          var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
4362          var direction = isAscending ? 1 : -1;
4363          return ( a > b ? 1 : -1 ) * direction;
4364        }
4365      }
4366      return 0;
4367    };
4368  }
4369
4370  // -------------------------- methods -------------------------- //
4371
4372  // get layout mode
4373  Isotope.prototype._mode = function() {
4374    var layoutMode = this.options.layoutMode;
4375    var mode = this.modes[ layoutMode ];
4376    if ( !mode ) {
4377      // TODO console.error
4378      throw new Error( 'No layout mode: ' + layoutMode );
4379    }
4380    // HACK sync mode's options
4381    // any options set after init for layout mode need to be synced
4382    mode.options = this.options[ layoutMode ];
4383    return mode;
4384  };
4385
4386  Isotope.prototype._resetLayout = function() {
4387    // trigger original reset layout
4388    Outlayer.prototype._resetLayout.call( this );
4389    this._mode()._resetLayout();
4390  };
4391
4392  Isotope.prototype._getItemLayoutPosition = function( item  ) {
4393    return this._mode()._getItemLayoutPosition( item );
4394  };
4395
4396  Isotope.prototype._manageStamp = function( stamp ) {
4397    this._mode()._manageStamp( stamp );
4398  };
4399
4400  Isotope.prototype._getContainerSize = function() {
4401    return this._mode()._getContainerSize();
4402  };
4403
4404  Isotope.prototype.needsResizeLayout = function() {
4405    return this._mode().needsResizeLayout();
4406  };
4407
4408  // -------------------------- adding & removing -------------------------- //
4409
4410  // HEADS UP overwrites default Outlayer appended
4411  Isotope.prototype.appended = function( elems ) {
4412    var items = this.addItems( elems );
4413    if ( !items.length ) {
4414      return;
4415    }
4416    // filter, layout, reveal new items
4417    var filteredItems = this._filterRevealAdded( items );
4418    // add to filteredItems
4419    this.filteredItems = this.filteredItems.concat( filteredItems );
4420  };
4421
4422  // HEADS UP overwrites default Outlayer prepended
4423  Isotope.prototype.prepended = function( elems ) {
4424    var items = this._itemize( elems );
4425    if ( !items.length ) {
4426      return;
4427    }
4428    // start new layout
4429    this._resetLayout();
4430    this._manageStamps();
4431    // filter, layout, reveal new items
4432    var filteredItems = this._filterRevealAdded( items );
4433    // layout previous items
4434    this.layoutItems( this.filteredItems );
4435    // add to items and filteredItems
4436    this.filteredItems = filteredItems.concat( this.filteredItems );
4437    this.items = items.concat( this.items );
4438  };
4439
4440  Isotope.prototype._filterRevealAdded = function( items ) {
4441    var filtered = this._filter( items );
4442    this.hide( filtered.needHide );
4443    // reveal all new items
4444    this.reveal( filtered.matches );
4445    // layout new items, no transition
4446    this.layoutItems( filtered.matches, true );
4447    return filtered.matches;
4448  };
4449
4450  /**
4451   * Filter, sort, and layout newly-appended item elements
4452   * @param {Array or NodeList or Element} elems
4453   */
4454  Isotope.prototype.insert = function( elems ) {
4455    var items = this.addItems( elems );
4456    if ( !items.length ) {
4457      return;
4458    }
4459    // append item elements
4460    var i, item;
4461    var len = items.length;
4462    for ( i=0; i < len; i++ ) {
4463      item = items[i];
4464      this.element.appendChild( item.element );
4465    }
4466    // filter new stuff
4467    var filteredInsertItems = this._filter( items ).matches;
4468    // set flag
4469    for ( i=0; i < len; i++ ) {
4470      items[i].isLayoutInstant = true;
4471    }
4472    this.arrange();
4473    // reset flag
4474    for ( i=0; i < len; i++ ) {
4475      delete items[i].isLayoutInstant;
4476    }
4477    this.reveal( filteredInsertItems );
4478  };
4479
4480  var _remove = Isotope.prototype.remove;
4481  Isotope.prototype.remove = function( elems ) {
4482    elems = utils.makeArray( elems );
4483    var removeItems = this.getItems( elems );
4484    // do regular thing
4485    _remove.call( this, elems );
4486    // bail if no items to remove
4487    var len = removeItems && removeItems.length;
4488    if ( !len ) {
4489      return;
4490    }
4491    // remove elems from filteredItems
4492    for ( var i=0; i < len; i++ ) {
4493      var item = removeItems[i];
4494      // remove item from collection
4495      utils.removeFrom( this.filteredItems, item );
4496    }
4497  };
4498
4499  Isotope.prototype.shuffle = function() {
4500    // update random sortData
4501    for ( var i=0, len = this.items.length; i < len; i++ ) {
4502      var item = this.items[i];
4503      item.sortData.random = Math.random();
4504    }
4505    this.options.sortBy = 'random';
4506    this._sort();
4507    this._layout();
4508  };
4509
4510  /**
4511   * trigger fn without transition
4512   * kind of hacky to have this in the first place
4513   * @param {Function} fn
4514   * @returns ret
4515   * @private
4516   */
4517  Isotope.prototype._noTransition = function( fn ) {
4518    // save transitionDuration before disabling
4519    var transitionDuration = this.options.transitionDuration;
4520    // disable transition
4521    this.options.transitionDuration = 0;
4522    // do it
4523    var returnValue = fn.call( this );
4524    // re-enable transition for reveal
4525    this.options.transitionDuration = transitionDuration;
4526    return returnValue;
4527  };
4528
4529  // ----- helper methods ----- //
4530
4531  /**
4532   * getter method for getting filtered item elements
4533   * @returns {Array} elems - collection of item elements
4534   */
4535  Isotope.prototype.getFilteredItemElements = function() {
4536    var elems = [];
4537    for ( var i=0, len = this.filteredItems.length; i < len; i++ ) {
4538      elems.push( this.filteredItems[i].element );
4539    }
4540    return elems;
4541  };
4542
4543  // -----  ----- //
4544
4545  return Isotope;
4546
4547}));
4548
4549
4550/*!
4551 * Packery layout mode PACKAGED v2.0.1
4552 * sub-classes Packery
4553 */
4554
4555!function(a,b){"function"==typeof define&&define.amd?define("packery/js/rect",b):"object"==typeof module&&module.exports?module.exports=b():(a.Packery=a.Packery||{},a.Packery.Rect=b())}(window,function(){function a(b){for(var c in a.defaults)this[c]=a.defaults[c];for(c in b)this[c]=b[c]}a.defaults={x:0,y:0,width:0,height:0};var b=a.prototype;return b.contains=function(a){var b=a.width||0,c=a.height||0;return this.x<=a.x&&this.y<=a.y&&this.x+this.width>=a.x+b&&this.y+this.height>=a.y+c},b.overlaps=function(a){var b=this.x+this.width,c=this.y+this.height,d=a.x+a.width,e=a.y+a.height;return this.x<d&&b>a.x&&this.y<e&&c>a.y},b.getMaximalFreeRects=function(b){if(!this.overlaps(b))return!1;var c,d=[],e=this.x+this.width,f=this.y+this.height,g=b.x+b.width,h=b.y+b.height;return this.y<b.y&&(c=new a({x:this.x,y:this.y,width:this.width,height:b.y-this.y}),d.push(c)),e>g&&(c=new a({x:g,y:this.y,width:e-g,height:this.height}),d.push(c)),f>h&&(c=new a({x:this.x,y:h,width:this.width,height:f-h}),d.push(c)),this.x<b.x&&(c=new a({x:this.x,y:this.y,width:b.x-this.x,height:this.height}),d.push(c)),d},b.canFit=function(a){return this.width>=a.width&&this.height>=a.height},a}),function(a,b){if("function"==typeof define&&define.amd)define("packery/js/packer",["./rect"],b);else if("object"==typeof module&&module.exports)module.exports=b(require("./rect"));else{var c=a.Packery=a.Packery||{};c.Packer=b(c.Rect)}}(window,function(a){function b(a,b,c){this.width=a||0,this.height=b||0,this.sortDirection=c||"downwardLeftToRight",this.reset()}var c=b.prototype;c.reset=function(){this.spaces=[];var b=new a({x:0,y:0,width:this.width,height:this.height});this.spaces.push(b),this.sorter=d[this.sortDirection]||d.downwardLeftToRight},c.pack=function(a){for(var b=0;b<this.spaces.length;b++){var c=this.spaces[b];if(c.canFit(a)){this.placeInSpace(a,c);break}}},c.columnPack=function(a){for(var b=0;b<this.spaces.length;b++){var c=this.spaces[b],d=c.x<=a.x&&c.x+c.width>=a.x+a.width&&c.height>=a.height-.01;if(d){a.y=c.y,this.placed(a);break}}},c.rowPack=function(a){for(var b=0;b<this.spaces.length;b++){var c=this.spaces[b],d=c.y<=a.y&&c.y+c.height>=a.y+a.height&&c.width>=a.width-.01;if(d){a.x=c.x,this.placed(a);break}}},c.placeInSpace=function(a,b){a.x=b.x,a.y=b.y,this.placed(a)},c.placed=function(a){for(var b=[],c=0;c<this.spaces.length;c++){var d=this.spaces[c],e=d.getMaximalFreeRects(a);
vendor: 8,438 bytes, line 4555
4555e?b.push.apply(b,e):b.push(d)}this.spaces=b,this.mergeSortSpaces()},c.mergeSortSpaces=function(){b.mergeRects(this.spaces),this.spaces.sort(this.sorter)},c.addSpace=function(a){this.spaces.push(a),this.mergeSortSpaces()},b.mergeRects=function(a){var b=0,c=a[b];a:for(;c;){for(var d=0,e=a[b+d];e;){if(e==c)d++;else{if(e.contains(c)){a.splice(b,1),c=a[b];continue a}c.contains(e)?a.splice(b+d,1):d++}e=a[b+d]}b++,c=a[b]}return a};var d={downwardLeftToRight:function(a,b){return a.y-b.y||a.x-b.x},rightwardTopToBottom:function(a,b){return a.x-b.x||a.y-b.y}};return b}),function(a,b){"function"==typeof define&&define.amd?define("packery/js/item",["outlayer/outlayer","./rect"],b):"object"==typeof module&&module.exports?module.exports=b(require("outlayer"),require("./rect")):a.Packery.Item=b(a.Outlayer,a.Packery.Rect)}(window,function(a,b){var c=document.documentElement.style,d="string"==typeof c.transform?"transform":"WebkitTransform",e=function(){a.Item.apply(this,arguments)},f=e.prototype=Object.create(a.Item.prototype),g=f._create;f._create=function(){g.call(this),this.rect=new b};var h=f.moveTo;return f.moveTo=function(a,b){var c=Math.abs(this.position.x-a),d=Math.abs(this.position.y-b),e=this.layout.dragItemCount&&!this.isPlacing&&!this.isTransitioning&&1>c&&1>d;return e?void this.goTo(a,b):void h.apply(this,arguments)},f.enablePlacing=function(){this.removeTransitionStyles(),this.isTransitioning&&d&&(this.element.style[d]="none"),this.isTransitioning=!1,this.getSize(),this.layout._setRectSize(this.element,this.rect),this.isPlacing=!0},f.disablePlacing=function(){this.isPlacing=!1},f.removeElem=function(){this.element.parentNode.removeChild(this.element),this.layout.packer.addSpace(this.rect),this.emitEvent("remove",[this])},f.showDropPlaceholder=function(){var a=this.dropPlaceholder;a||(a=this.dropPlaceholder=document.createElement("div"),a.className="packery-drop-placeholder",a.style.position="absolute"),a.style.width=this.size.width+"px",a.style.height=this.size.height+"px",this.positionDropPlaceholder(),this.layout.element.appendChild(a)},f.positionDropPlaceholder=function(){this.dropPlaceholder.style[d]="translate("+this.rect.x+"px, "+this.rect.y+"px)"},f.hideDropPlaceholder=function(){this.layout.element.removeChild(this.dropPlaceholder)},e}),function(a,b){"function"==typeof define&&define.amd?define("packery/js/packery",["get-size/get-size","outlayer/outlayer","./rect","./packer","./item"],b):"object"==typeof module&&module.exports?module.exports=b(require("get-size"),require("outlayer"),require("./rect"),require("./packer"),require("./item")):a.Packery=b(a.getSize,a.Outlayer,a.Packery.Rect,a.Packery.Packer,a.Packery.Item)}(window,function(a,b,c,d,e){function f(a,b){return a.position.y-b.position.y||a.position.x-b.position.x}function g(a,b){return a.position.x-b.position.x||a.position.y-b.position.y}function h(a,b){var c=b.x-a.x,d=b.y-a.y;return Math.sqrt(c*c+d*d)}c.prototype.canFit=function(a){return this.width>=a.width-1&&this.height>=a.height-1};var i=b.create("packery");i.Item=e;var j=i.prototype;j._create=function(){b.prototype._create.call(this),this.packer=new d,this.shiftPacker=new d,this.isEnabled=!0,this.dragItemCount=0;var a=this;this.handleDraggabilly={dragStart:function(){a.itemDragStart(this.element)},dragMove:function(){a.itemDragMove(this.element,this.position.x,this.position.y)},dragEnd:function(){a.itemDragEnd(this.element)}},this.handleUIDraggable={start:function(b,c){c&&a.itemDragStart(b.currentTarget)},drag:function(b,c){c&&a.itemDragMove(b.currentTarget,c.position.left,c.position.top)},stop:function(b,c){c&&a.itemDragEnd(b.currentTarget)}}},j._resetLayout=function(){this.getSize(),this._getMeasurements();var a,b,c;this._getOption("horizontal")?(a=1/0,b=this.size.innerHeight+this.gutter,c="rightwardTopToBottom"):(a=this.size.innerWidth+this.gutter,b=1/0,c="downwardLeftToRight"),this.packer.width=this.shiftPacker.width=a,this.packer.height=this.shiftPacker.height=b,this.packer.sortDirection=this.shiftPacker.sortDirection=c,this.packer.reset(),this.maxY=0,this.maxX=0},j._getMeasurements=function(){this._getMeasurement("columnWidth","width"),this._getMeasurement("rowHeight","height"),this._getMeasurement("gutter","width")},j._getItemLayoutPosition=function(a){if(this._setRectSize(a.element,a.rect),this.isShifting||this.dragItemCount>0){var b=this._getPackMethod();this.packer[b](a.rect)}else this.packer.pack(a.rect);return this._setMaxXY(a.rect),a.rect},j.shiftLayout=function(){this.isShifting=!0,this.layout(),delete this.isShifting},j._getPackMethod=function(){return this._getOption("horizontal")?"rowPack":"columnPack"},j._setMaxXY=function(a){this.maxX=Math.max(a.x+a.width,this.maxX),this.maxY=Math.max(a.y+a.height,this.maxY)},j._setRectSize=function(b,c){var d=a(b),e=d.outerWidth,f=d.outerHeight;(e||f)&&(e=this._applyGridGutter(e,this.columnWidth),f=this._applyGridGutter(f,this.rowHeight)),c.width=Math.min(e,this.packer.width),c.height=Math.min(f,this.packer.height)},j._applyGridGutter=function(a,b){if(!b)return a+this.gutter;b+=this.gutter;var c=a%b,d=c&&1>c?"round":"ceil";return a=Math[d](a/b)*b},j._getContainerSize=function(){return this._getOption("horizontal")?{width:this.maxX-this.gutter}:{height:this.maxY-this.gutter}},j._manageStamp=function(a){var b,d=this.getItem(a);if(d&&d.isPlacing)b=d.rect;else{var e=this._getElementOffset(a);b=new c({x:this._getOption("originLeft")?e.left:e.right,y:this._getOption("originTop")?e.top:e.bottom})}this._setRectSize(a,b),this.packer.placed(b),this._setMaxXY(b)},j.sortItemsByPosition=function(){var a=this._getOption("horizontal")?g:f;this.items.sort(a)},j.fit=function(a,b,c){var d=this.getItem(a);d&&(this.stamp(d.element),d.enablePlacing(),this.updateShiftTargets(d),b=void 0===b?d.rect.x:b,c=void 0===c?d.rect.y:c,this.shift(d,b,c),this._bindFitEvents(d),d.moveTo(d.rect.x,d.rect.y),this.shiftLayout(),this.unstamp(d.element),this.sortItemsByPosition(),d.disablePlacing())},j._bindFitEvents=function(a){function b(){d++,2==d&&c.dispatchEvent("fitComplete",null,[a])}var c=this,d=0;a.once("layout",b),this.once("layoutComplete",b)},j.resize=function(){this.isResizeBound&&this.needsResizeLayout()&&(this.options.shiftPercentResize?this.resizeShiftPercentLayout():this.layout())},j.needsResizeLayout=function(){var b=a(this.element),c=this._getOption("horizontal")?"innerHeight":"innerWidth";return b[c]!=this.size[c]},j.resizeShiftPercentLayout=function(){var b=this._getItemsForLayout(this.items),c=this._getOption("horizontal"),d=c?"y":"x",e=c?"height":"width",f=c?"rowHeight":"columnWidth",g=c?"innerHeight":"innerWidth",h=this[f];if(h=h&&h+this.gutter){this._getMeasurements();var i=this[f]+this.gutter;b.forEach(function(a){var b=Math.round(a.rect[d]/h);a.rect[d]=b*i})}else{var j=a(this.element)[g]+this.gutter,k=this.packer[e];b.forEach(function(a){a.rect[d]=a.rect[d]/k*j})}this.shiftLayout()},j.itemDragStart=function(a){if(this.isEnabled){this.stamp(a);var b=this.getItem(a);b&&(b.enablePlacing(),b.showDropPlaceholder(),this.dragItemCount++,this.updateShiftTargets(b))}},j.updateShiftTargets=function(a){this.shiftPacker.reset(),this._getBoundingRect();var b=this._getOption("originLeft"),d=this._getOption("originTop");this.stamps.forEach(function(a){var e=this.getItem(a);if(!e||!e.isPlacing){var f=this._getElementOffset(a),g=new c({x:b?f.left:f.right,y:d?f.top:f.bottom});this._setRectSize(a,g),this.shiftPacker.placed(g)}},this);var e=this._getOption("horizontal"),f=e?"rowHeight":"columnWidth",g=e?"height":"width";this.shiftTargetKeys=[],this.shiftTargets=[];var h,i=this[f];if(i=i&&i+this.gutter){var j=Math.ceil(a.rect[g]/i),k=Math.floor((this.shiftPacker[g]+this.gutter)/i);h=(k-j)*i;for(var l=0;k>l;l++)this._addShiftTarget(l*i,0,h)}else h=this.shiftPacker[g]+this.gutter-a.rect[g],this._addShiftTarget(0,0,h);var m=this._getItemsForLayout(this.items),n=this._getPackMethod();m.forEach(function(a){var b=a.rect;this._setRectSize(a.element,b),this.shiftPacker[n](b),this._addShiftTarget(b.x,b.y,h);var c=e?b.x+b.width:b.x,d=e?b.y:b.y+b.height;if(this._addShiftTarget(c,d,h),i)for(var f=Math.round(b[g]/i),j=1;f>j;j++){var k=e?c:b.x+i*j,l=e?b.y+i*j:d;this._addShiftTarget(k,l,h)}},this)},j._addShiftTarget=function(a,b,c){var d=this._getOption("horizontal")?b:a;if(!(0!==d&&d>c)){var e=a+","+b,f=-1!=this.shiftTargetKeys.indexOf(e);f||(this.shiftTargetKeys.push(e),this.shiftTargets.push({x:a,y:b}))}},j.shift=function(a,b,c){var d,e=1/0,f={x:b,y:c};
4555this.shiftTargets.forEach(function(a){var b=h(a,f);e>b&&(d=a,e=b)}),a.rect.x=d.x,a.rect.y=d.y};var k=120;j.itemDragMove=function(a,b,c){function d(){f.shift(e,b,c),e.positionDropPlaceholder(),f.layout()}var e=this.isEnabled&&this.getItem(a);if(e){b-=this.size.paddingLeft,c-=this.size.paddingTop;var f=this,g=new Date;this._itemDragTime&&g-this._itemDragTime<k?(clearTimeout(this.dragTimeout),this.dragTimeout=setTimeout(d,k)):(d(),this._itemDragTime=g)}},j.itemDragEnd=function(a){function b(){d++,2==d&&(c.element.classList.remove("is-positioning-post-drag"),c.hideDropPlaceholder(),e.dispatchEvent("dragItemPositioned",null,[c]))}var c=this.isEnabled&&this.getItem(a);if(c){clearTimeout(this.dragTimeout),c.element.classList.add("is-positioning-post-drag");var d=0,e=this;c.once("layout",b),this.once("layoutComplete",b),c.moveTo(c.rect.x,c.rect.y),this.layout(),this.dragItemCount=Math.max(0,this.dragItemCount-1),this.sortItemsByPosition(),c.disablePlacing(),this.unstamp(c.element)}},j.bindDraggabillyEvents=function(a){this._bindDraggabillyEvents(a,"on")},j.unbindDraggabillyEvents=function(a){this._bindDraggabillyEvents(a,"off")},j._bindDraggabillyEvents=function(a,b){var c=this.handleDraggabilly;a[b]("dragStart",c.dragStart),a[b]("dragMove",c.dragMove),a[b]("dragEnd",c.dragEnd)},j.bindUIDraggableEvents=function(a){this._bindUIDraggableEvents(a,"on")},j.unbindUIDraggableEvents=function(a){this._bindUIDraggableEvents(a,"off")},j._bindUIDraggableEvents=function(a,b){var c=this.handleUIDraggable;a[b]("dragstart",c.start)[b]("drag",c.drag)[b]("dragstop",c.stop)};var l=j.destroy;return j.destroy=function(){l.apply(this,arguments),this.isEnabled=!1},i.Rect=c,i.Packer=d,i}),function(a,b){"function"==typeof define&&define.amd?define(["isotope-layout/js/layout-mode","packery/js/packery"],b):"object"==typeof module&&module.exports?module.exports=b(require("isotope-layout/js/layout-mode"),require("packery")):b(a.Isotope.LayoutMode,a.Packery)}(window,function(a,b){var c=a.create("packery"),d=c.prototype,e={_getElementOffset:!0,_getMeasurement:!0};for(var f in b.prototype)e[f]||(d[f]=b.prototype[f]);var g=d._resetLayout;d._resetLayout=function(){this.packer=this.packer||new b.Packer,this.shiftPacker=this.shiftPacker||new b.Packer,g.apply(this,arguments)};var h=d._getItemLayoutPosition;d._getItemLayoutPosition=function(a){return a.rect=a.rect||new b.Rect,h.call(this,a)};var i=d.needsResizeLayout;d.needsResizeLayout=function(){return this._getOption("horizontal")?this.needsVerticalResizeLayout():i.call(this)};var j=d._getOption;return d._getOption=function(a){return"horizontal"==a?void 0!==this.options.isHorizontal?this.options.isHorizontal:this.options.horizontal:j.apply(this.isotope,arguments)},c});
4556
4557/*!
4558 * cellsByRows layout mode for Isotope
4559 * v1.1.3
4560 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html
4561 */
4562
4563/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */
4564
4565( function( window, factory ) {
4566  // universal module definition
4567  /* jshint strict: false */ /*globals define, module, require */
4568  if ( typeof define === 'function' && define.amd ) {
4569    // AMD
4570    define( [
4571        'isotope/js/layout-mode'
4572      ],
4573      factory );
4574  } else if ( typeof exports === 'object' ) {
4575    // CommonJS
4576    module.exports = factory(
4577      require('isotope-layout/js/layout-mode')
4578    );
4579  } else {
4580    // browser global
4581    factory(
4582      window.Isotope.LayoutMode
4583    );
4584  }
4585
4586}( window, function factory( LayoutMode ) {
4587  'use strict';
4588
4589  var CellsByRow = LayoutMode.create( 'cellsByRow' );
4590  var proto = CellsByRow.prototype;
4591
4592  proto._resetLayout = function() {
4593    // reset properties
4594    this.itemIndex = 0;
4595    // measurements
4596    this.getColumnWidth();
4597    this.getRowHeight();
4598    // set cols
4599    this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth );
4600    this.cols = Math.max( this.cols, 1 );
4601  };
4602
4603  proto._getItemLayoutPosition = function( item ) {
4604    item.getSize();
4605    var col = this.itemIndex % this.cols;
4606    var row = Math.floor( this.itemIndex / this.cols );
4607    // center item within cell
4608    var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2;
4609    var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2;
4610    this.itemIndex++;
4611    return { x: x, y: y };
4612  };
4613
4614  proto._getContainerSize = function() {
4615    return {
4616      height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight
4617    };
4618  };
4619
4620  return CellsByRow;
4621
4622}));
4623
4624/*!
4625   --------------------------------
4626   Infinite Scroll
4627   --------------------------------
4628   + https://github.com/paulirish/infinite-scroll
4629   + version 2.1.0
4630   + Copyright 2011/12 Paul Irish & Luke Shumard
4631   + Licensed under the MIT license
4632
4633   + Documentation: http://infinite-scroll.com/
4634*/
4635;(function(e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else{e(jQuery)}})(function(e,t){"use strict";e.infinitescroll=function(n,r,i){this.element=e(i);if(!this._create(n,r)){this.failed=true}};e.infinitescroll.defaults={loading:{finished:t,finishedMsg:"<em>Congratulations, you've reached the end of the internet.</em>",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/fDuFh
4635ohVeDeCfXkcCQqDVQcQhn+VNDOYmpSWaoqBlUSfmowjEA+iEAEGDRGztAwGCDcXEA60tXEiCrq8vREMEBLIyRLCxMWSHMzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/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
4635iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/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",msg:null,msgText:"<em>Loading the next set of posts...</em>",selector:null,speed:"fast",start:t},state:{isDuringAjax:false,isInvalidPage:false,isDestroyed:false,isDone:false,isPaused:false,isBeyondMaxPage:false,currPage:1},debug:false,behavior:t,binder:e(window),nextSelector:"div.navigation a:first",navSelector:"div.navigation",contentSelector:null,extraScrollPx:150,itemSelector:"div.post",animate:false,pathParse:t,dataType:"html",appendCallback:true,bufferPx:40,errorCallback:function(){},infid:0,pixelsFromNavToBottom:t,path:t,prefill:false,maxPage:t};e.infinitescroll.prototype={_binding:function(n){var r=this,i=r.options;i.v="2.0b2.120520";if(!!i.behavior&&this["_binding_"+i.behavior]!==t){this["_binding_"+i.behavior].call(this);return}if(n!=="bind"&&n!=="unbind"){this._debug("Binding value  "+n+" not valid");return false}if(n==="unbind"){this.options.binder.unbind("smartscroll.infscr."+r.options.infid)}else{this.options.binder[n]("smartscroll.infscr."+r.options.infid,function(){r.scroll()})}this._debug("Binding",n)},_create:function(r,i){var s=e.extend(true,{},e.infinitescroll.defaults,r);this.options=s;var o=e(window);var u=this;if(!u._validate(r)){return false}var a=e(s.nextSelector).attr("href");if(!a){this._debug("Navigation selector not found");return false}s.path=s.path||this._determinepath(a);s.contentSelector=s.contentSelector||this.element;s.loading.selector=s.loading.selector||s.contentSelector;s.loading.msg=s.loading.msg||e('<div id="infscr-loading"><img alt="Loading..." src="'+s.loading.img+'" /><div>'+s.loading.msgText+"</div></div>");(new Image).src=s.loading.img;if(s.pixelsFromNavToBottom===t){s.pixelsFromNavToBottom=e(document).height()-e(s.navSelector).offset().top;this._debug("pixelsFromNavToBottom: "+s.pixelsFromNavToBottom)}var f=this;s.loading.start=s.loading.start||function(){e(s.navSelector).hide();s.loading.msg.appendTo(s.loading.selector).show(s.loading.speed,e.proxy(function(){this.beginAjax(s)},f))};s.loading.finished=s.loading.finished||function(){if(!s.state.isBeyondMaxPage)s.loading.msg.fadeOut(s.loading.speed)};s.callback=function(n,r,u){if(!!s.behavior&&n["_callback_"+s.behavior]!==t){n["_callback_"+s.behavior].call(e(s.contentSelector)[0],r,u)}if(i){i.call(e(s.contentSelector)[0],r,s,u)}if(s.prefill){o.bind("resize.infinite-scroll",n._prefill)}};if(r.debug){if(Function.prototype.bind&&(typeof console==="object"||typeof console==="function")&&typeof console.log==="object"){["log","info","warn","error","assert","dir","clear","profile","profileEnd"].forEach(function(e){console[e]=this.call(console[e],console)},Function.prototype.bind)}}this._setup();if(s.prefill){this._prefill()}return true},_prefill:function(){function i(){return e(n.options.contentSelector).height()<=r.height()}var n=this;var r=e(window);this._prefill=function(){if(i()){n.scroll()}r.bind("resize.infinite-scroll",function(){if(i()){r.unbind("resize.infinite-scroll");n.scroll()}})};this._prefill()},_debug:function(){if(true!==this.options.debug){return}if(typeof console!=="undefined"&&typeof console.log==="function"){if(Array.prototype.slice.call(arguments).length===1&&typeof Array.prototype.slice.call(arguments)[0]==="str
4635ing"){console.log(Array.prototype.slice.call(arguments).toString())}else{console.log(Array.prototype.slice.call(arguments))}}else if(!Function.prototype.bind&&typeof console!=="undefined"&&typeof console.log==="object"){Function.prototype.call.call(console.log,console,Array.prototype.slice.call(arguments))}},_determinepath:function(n){var r=this.options;if(!!r.behavior&&this["_determinepath_"+r.behavior]!==t){return this["_determinepath_"+r.behavior].call(this,n)}if(!!r.pathParse){this._debug("pathParse manual");return r.pathParse(n,this.options.state.currPage+1)}else if(n.match(/^(.*?)\b2\b(.*?$)/)){n=n.match(/^(.*?)\b2\b(.*?$)/).slice(1)}else if(n.match(/^(.*?)2(.*?$)/)){if(n.match(/^(.*?page=)2(\/.*|$)/)){n=n.match(/^(.*?page=)2(\/.*|$)/).slice(1);return n}n=n.match(/^(.*?)2(.*?$)/).slice(1)}else{if(n.match(/^(.*?page=)1(\/.*|$)/)){n=n.match(/^(.*?page=)1(\/.*|$)/).slice(1);return n}else{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.");r.state.isInvalidPage=true}}this._debug("determinePath",n);return n},_error:function(n){var r=this.options;if(!!r.behavior&&this["_error_"+r.behavior]!==t){this["_error_"+r.behavior].call(this,n);return}if(n!=="destroy"&&n!=="end"){n="unknown"}this._debug("Error",n);if(n==="end"||r.state.isBeyondMaxPage){this._showdonemsg()}r.state.isDone=true;r.state.currPage=1;
4635r.state.isPaused=false;r.state.isBeyondMaxPage=false;this._binding("unbind")},_loadcallback:function(r,i,s){var o=this.options,u=this.options.callback,a=o.state.isDone?"done":!o.appendCallback?"no-append":"append",f;if(!!o.behavior&&this["_loadcallback_"+o.behavior]!==t){this["_loadcallback_"+o.behavior].call(this,r,i);return}switch(a){case"done":this._showdonemsg();return false;case"no-append":if(o.dataType==="html"){i="<div>"+i+"</div>";i=e(i).find(o.itemSelector)}if(i.length===0){return this._error("end")}break;case"append":var l=r.children();if(l.length===0){return this._error("end")}f=document.createDocumentFragment();while(r[0].firstChild){f.appendChild(r[0].firstChild)}this._debug("contentSelector",e(o.contentSelector)[0]);e(o.contentSelector)[0].appendChild(f);i=l.get();break}o.loading.finished.call(e(o.contentSelector)[0],o);if(o.animate){var c=e(window).scrollTop()+e(o.loading.msg).height()+o.extraScrollPx+"px";e("html,body").animate({scrollTop:c},800,function(){o.state.isDuringAjax=false})}if(!o.animate){o.state.isDuringAjax=false}u(this,i,s);if(o.prefill){this._prefill()}},_nearbottom:function(){var r=this.options,i=0+e(document).height()-r.binder.scrollTop()-e(window).height();if(!!r.behavior&&this["_nearbottom_"+r.behavior]!==t){return this["_nearbottom_"+r.behavior].call(this)}this._debug("math:",i,r.pixelsFromNavToBottom);return i-r.bufferPx<r.pixelsFromNavToBottom},_pausing:function(n){var r=this.options;if(!!r.behavior&&this["_pausing_"+r.behavior]!==t){this["_pausing_"+r.behavior].call(this,n);return}if(n!=="pause"&&n!=="resume"&&n!==null){this._debug("Invalid argument. Toggling pause value instead")}n=n&&(n==="pause"||n==="resume")?n:"toggle";
4635switch(n){case"pause":r.state.isPaused=true;break;case"resume":r.state.isPaused=false;break;case"toggle":r.state.isPaused=!r.state.isPaused;break}this._debug("Paused",r.state.isPaused);return false},_setup:function(){var n=this.options;if(!!n.behavior&&this["_setup_"+n.behavior]!==t){this["_setup_"+n.behavior].call(this);return}this._binding("bind");return false},_showdonemsg:function(){var r=this.options;if(!!r.behavior&&this["_showdonemsg_"+r.behavior]!==t){this["_showdonemsg_"+r.behavior].call(this);return}r.loading.msg.find("img").hide().parent().find("div").html(r.loading.finishedMsg).animate({opacity:1},2e3,function(){e(this).parent().fadeOut(r.loading.speed)});r.errorCallback.call(e(r.contentSelector)[0],"done")},_validate:function(n){for(var r in n){if(r.indexOf&&r.indexOf("Selector")>-1&&e(n[r]).length===0){this._debug("Your "+r+" found no elements.");return false}}return true},bind:function(){this._binding("bind")},destroy:function(){this.options.state.isDestroyed=true;this.options.loading.finished();return this._error("destroy")},pause:function(){this._pausing("pause")},resume:function(){this._pausing("resume")},beginAjax:function(r){var i=this,s=r.path,o,u,a,f;r.state.currPage++;if(r.maxPage!==t&&r.state.currPage>r.maxPage){r.state.isBeyondMaxPage=true;this.destroy();return}o=e(r.contentSelector).is("table, tbody")?e("<tbody/>"):e("<div/>");u=typeof s==="function"?s(r.state.currPage):s.join(r.state.currPage);i._debug("heading into ajax",u);a=r.dataType==="html"||r.dataType==="json"?r.dataType:"html+callback";if(r.appendCallback&&r.dataType==="html"){a+="+callback"}switch(a){case"html+callback":i._debug("Using HTML via .load() method");o.load(u+" "+r.itemSelector,t,function(t){i._loadcallback(o,t,u)});break;case"html":i._debug("Using "+a.toUpperCase()+" via $.ajax() method");e.ajax({url:u,dataType:r.dataType,complete:function(t,n){f=typeof t.isResolved!=="undefined"?t.isResolved():n==="success"||n==="notmodified";if(f){i._loadcallback(o,t.responseText,u)}else{i._error("end")}}});break;case"json":i._debug("Using "+a.toUpperCase()+" via $.ajax() method");e.ajax({dataType:"json",type:"GET",url:u,success:function(e,n,s){f=typeof s.isResolved!=="undefined"?s.isResolved():n==="success"||n==="notmodified";if(r.appendCallback){if(r.template!==t){var a=r.template(e);o.append(a);if(f){i._loadcallback(o,a)}else{i._error("end")}}else{i._debug("template must be defined.");i._error("end")}}else{if(f){i._loadcallback(o,e,u)}else{i._error("end")}}},error:function(){i._debug("JSON ajax request failed.");i._error("end")}});break}},retrieve:function(r){r=r||null;var i=this,s=i.options;if(!!s.behavior&&this["retrieve_"+s.behavior]!==t){this["retrieve_"+s.behavior].call(this,r);return}if(s.state.isDestroyed){this._debug("Instance is destroyed");return false}s.state.isDuringAjax=true;s.loading.start.call(e(s.contentSelector)[0],s)},scroll:function(){var n=this.options,r=n.state;if(!!n.behavior&&this["scroll_"+n.behavior]!==t){this["scroll_"+n.behavior].call(this);return}if(r.isDuringAjax||r.isInvalidPage||r.isDone||r.isDestroyed||r.isPaused){return}if(!this._nearbottom()){return}this.retrieve()},toggle:function(){this._pausing()},unbind:function(){this._binding("unbind")},update:function(n){if(e.isPlainObject(n)){this.options=e.extend(true,this.options,n)}}};e.fn.infinitescroll=function(n,r){var i=typeof n;switch(i){case"string":var s=Array.prototype.slice.call(arguments,1);this.each(function(){var t=e.data(this,"infinitescroll");if(!t){return false}if(!e.isFunction(t[n])||n.charAt(0)==="_"){return false}t[n].apply(t,s)});break;case"object":this.each(function(){var t=e.data(this,"infinitescroll");if(t){t.update(n)}else{t=new e.infinitescroll(n,r,this);if(!t.failed){e.data(this,"infinitescroll",t)}}});break}return this};var n=e.event,r;n.special.smartscroll={setup:function(){e(this).bind("scroll",n.special.smartscroll.handler)},teardown:function(){e(this).unbind("scroll",n.special.smartscroll.handler)},handler:function(t,n){var i=this,s=arguments;t.type="smartscroll";if(r){clearTimeout(r)}r=setTimeout(function(){e(i).trigger("smartscroll",s)},n==="execAsap"?0:100)}};e.fn.smartscroll=function(e){return e?this.bind("smartscroll",e):this.trigger("smartscroll",["execAsap"])}});
4636
4637/*!
4638Waypoints - 4.0.1
4639Copyright © 2011-2016 Caleb Troughton
4640Licensed under the MIT license.
4641https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
4642*/
4643(function() {
4644  'use strict'
4645
4646  var keyCounter = 0
4647  var allWaypoints = {}
4648
4649  /* http://imakewebthings.com/waypoints/api/waypoint */
4650  function Waypoint(options) {
4651    if (!options) {
4652      throw new Error('No options passed to Waypoint constructor')
4653    }
4654    if (!options.element) {
4655      throw new Error('No element option passed to Waypoint constructor')
4656    }
4657    if (!options.handler) {
4658      throw new Error('No handler option passed to Waypoint constructor')
4659    }
4660
4661    this.key = 'waypoint-' + keyCounter
4662    this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
4663    this.element = this.options.element
4664    this.adapter = new Waypoint.Adapter(this.element)
4665    this.callback = options.handler
4666    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
4667    this.enabled = this.options.enabled
4668    this.triggerPoint = null
4669    this.group = Waypoint.Group.findOrCreate({
4670      name: this.options.group,
4671      axis: this.axis
4672    })
4673    this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
4674
4675    if (Waypoint.offsetAliases[this.options.offset]) {
4676      this.options.offset = Waypoint.offsetAliases[this.options.offset]
4677    }
4678    this.group.add(this)
4679    this.context.add(this)
4680    allWaypoints[this.key] = this
4681    keyCounter += 1
4682  }
4683
4684  /* Private */
4685  Waypoint.prototype.queueTrigger = function(direction) {
4686    this.group.queueTrigger(this, direction)
4687  }
4688
4689  /* Private */
4690  Waypoint.prototype.trigger = function(args) {
4691    if (!this.enabled) {
4692      return
4693    }
4694    if (this.callback) {
4695      this.callback.apply(this, args)
4696    }
4697  }
4698
4699  /* Public */
4700  /* http://imakewebthings.com/waypoints/api/destroy */
4701  Waypoint.prototype.destroy = function() {
4702    this.context.remove(this)
4703    this.group.remove(this)
4704    delete allWaypoints[this.key]
4705  }
4706
4707  /* Public */
4708  /* http://imakewebthings.com/waypoints/api/disable */
4709  Waypoint.prototype.disable = function() {
4710    this.enabled = false
4711    return this
4712  }
4713
4714  /* Public */
4715  /* http://imakewebthings.com/waypoints/api/enable */
4716  Waypoint.prototype.enable = function() {
4717    this.context.refresh()
4718    this.enabled = true
4719    return this
4720  }
4721
4722  /* Public */
4723  /* http://imakewebthings.com/waypoints/api/next */
4724  Waypoint.prototype.next = function() {
4725    return this.group.next(this)
4726  }
4727
4728  /* Public */
4729  /* http://imakewebthings.com/waypoints/api/previous */
4730  Waypoint.prototype.previous = function() {
4731    return this.group.previous(this)
4732  }
4733
4734  /* Private */
4735  Waypoint.invokeAll = function(method) {
4736    var allWaypointsArray = []
4737    for (var waypointKey in allWaypoints) {
4738      allWaypointsArray.push(allWaypoints[waypointKey])
4739    }
4740    for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
4741      allWaypointsArray[i][method]()
4742    }
4743  }
4744
4745  /* Public */
4746  /* http://imakewebthings.com/waypoints/api/destroy-all */
4747  Waypoint.destroyAll = function() {
4748    Waypoint.invokeAll('destroy')
4749  }
4750
4751  /* Public */
4752  /* http://imakewebthings.com/waypoints/api/disable-all */
4753  Waypoint.disableAll = function() {
4754    Waypoint.invokeAll('disable')
4755  }
4756
4757  /* Public */
4758  /* http://imakewebthings.com/waypoints/api/enable-all */
4759  Waypoint.enableAll = function() {
4760    Waypoint.Context.refreshAll()
4761    for (var waypointKey in allWaypoints) {
4762      allWaypoints[waypointKey].enabled = true
4763    }
4764    return this
4765  }
4766
4767  /* Public */
4768  /* http://imakewebthings.com/waypoints/api/refresh-all */
4769  Waypoint.refreshAll = function() {
4770    Waypoint.Context.refreshAll()
4771  }
4772
4773  /* Public */
4774  /* http://imakewebthings.com/waypoints/api/viewport-height */
4775  Waypoint.viewportHeight = function() {
4776    return window.innerHeight || document.documentElement.clientHeight
4777  }
4778
4779  /* Public */
4780  /* http://imakewebthings.com/waypoints/api/viewport-width */
4781  Waypoint.viewportWidth = function() {
4782    return document.documentElement.clientWidth
4783  }
4784
4785  Waypoint.adapters = []
4786
4787  Waypoint.defaults = {
4788    context: window,
4789    continuous: true,
4790    enabled: true,
4791    group: 'default',
4792    horizontal: false,
4793    offset: 0
4794  }
4795
4796  Waypoint.offsetAliases = {
4797    'bottom-in-view': function() {
4798      return this.context.innerHeight() - this.adapter.outerHeight()
4799    },
4800    'right-in-view': function() {
4801      return this.context.innerWidth() - this.adapter.outerWidth()
4802    }
4803  }
4804
4805  window.Waypoint = Waypoint
4806}())
4807;(function() {
4808  'use strict'
4809
4810  function requestAnimationFrameShim(callback) {
4811    window.setTimeout(callback, 1000 / 60)
4812  }
4813
4814  var keyCounter = 0
4815  var contexts = {}
4816  var Waypoint = window.Waypoint
4817  var oldWindowLoad = window.onload
4818
4819  /* http://imakewebthings.com/waypoints/api/context */
4820  function Context(element) {
4821    this.element = element
4822    this.Adapter = Waypoint.Adapter
4823    this.adapter = new this.Adapter(element)
4824    this.key = 'waypoint-context-' + keyCounter
4825    this.didScroll = false
4826    this.didResize = false
4827    this.oldScroll = {
4828      x: this.adapter.scrollLeft(),
4829      y: this.adapter.scrollTop()
4830    }
4831    this.waypoints = {
4832      vertical: {},
4833      horizontal: {}
4834    }
4835
4836    element.waypointContextKey = this.key
4837    contexts[element.waypointContextKey] = this
4838    keyCounter += 1
4839    if (!Waypoint.windowContext) {
4840      Waypoint.windowContext = true
4841      Waypoint.windowContext = new Context(window)
4842    }
4843
4844    this.createThrottledScrollHandler()
4845    this.createThrottledResizeHandler()
4846  }
4847
4848  /* Private */
4849  Context.prototype.add = function(waypoint) {
4850    var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
4851    this.waypoints[axis][waypoint.key] = waypoint
4852    this.refresh()
4853  }
4854
4855  /* Private */
4856  Context.prototype.checkEmpty = function() {
4857    var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
4858    var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
4859    var isWindow = this.element == this.element.window
4860    if (horizontalEmpty && verticalEmpty && !isWindow) {
4861      this.adapter.off('.waypoints')
4862      delete contexts[this.key]
4863    }
4864  }
4865
4866  /* Private */
4867  Context.prototype.createThrottledResizeHandler = function() {
4868    var self = this
4869
4870    function resizeHandler() {
4871      self.handleResize()
4872      self.didResize = false
4873    }
4874
4875    this.adapter.on('resize.waypoints', function() {
4876      if (!self.didResize) {
4877        self.didResize = true
4878        Waypoint.requestAnimationFrame(resizeHandler)
4879      }
4880    })
4881  }
4882
4883  /* Private */
4884  Context.prototype.createThrottledScrollHandler = function() {
4885    var self = this
4886    function scrollHandler() {
4887      self.handleScroll()
4888      self.didScroll = false
4889    }
4890
4891    this.adapter.on('scroll.waypoints', function() {
4892      if (!self.didScroll || Waypoint.isTouch) {
4893        self.didScroll = true
4894        Waypoint.requestAnimationFrame(scrollHandler)
4895      }
4896    })
4897  }
4898
4899  /* Private */
4900  Context.prototype.handleResize = function() {
4901    Waypoint.Context.refreshAll()
4902  }
4903
4904  /* Private */
4905  Context.prototype.handleScroll = function() {
4906    var triggeredGroups = {}
4907    var axes = {
4908      horizontal: {
4909        newScroll: this.adapter.scrollLeft(),
4910        oldScroll: this.oldScroll.x,
4911        forward: 'right',
4912        backward: 'left'
4913      },
4914      vertical: {
4915        newScroll: this.adapter.scrollTop(),
4916        oldScroll: this.oldScroll.y,
4917        forward: 'down',
4918        backward: 'up'
4919      }
4920    }
4921
4922    for (var axisKey in axes) {
4923      var axis = axes[axisKey]
4924      var isForward = axis.newScroll > axis.oldScroll
4925      var direction = isForward ? axis.forward : axis.backward
4926
4927      for (var waypointKey in this.waypoints[axisKey]) {
4928        var waypoint = this.waypoints[axisKey][waypointKey]
4929        if (waypoint.triggerPoint === null) {
4930          continue
4931        }
4932        var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
4933        var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
4934        var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
4935        var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
4936        if (crossedForward || crossedBackward) {
4937          waypoint.queueTrigger(direction)
4938          triggeredGroups[waypoint.group.id] = waypoint.group
4939        }
4940      }
4941    }
4942
4943    for (var groupKey in triggeredGroups) {
4944      triggeredGroups[groupKey].flushTriggers()
4945    }
4946
4947    this.oldScroll = {
4948      x: axes.horizontal.newScroll,
4949      y: axes.vertical.newScroll
4950    }
4951  }
4952
4953  /* Private */
4954  Context.prototype.innerHeight = function() {
4955    /*eslint-disable eqeqeq */
4956    if (this.element == this.element.window) {
4957      return Waypoint.viewportHeight()
4958    }
4959    /*eslint-enable eqeqeq */
4960    return this.adapter.innerHeight()
4961  }
4962
4963  /* Private */
4964  Context.prototype.remove = function(waypoint) {
4965    delete this.waypoints[waypoint.axis][waypoint.key]
4966    this.checkEmpty()
4967  }
4968
4969  /* Private */
4970  Context.prototype.innerWidth = function() {
4971    /*eslint-disable eqeqeq */
4972    if (this.element == this.element.window) {
4973      return Waypoint.viewportWidth()
4974    }
4975    /*eslint-enable eqeqeq */
4976    return this.adapter.innerWidth()
4977  }
4978
4979  /* Public */
4980  /* http://imakewebthings.com/waypoints/api/context-destroy */
4981  Context.prototype.destroy = function() {
4982    var allWaypoints = []
4983    for (var axis in this.waypoints) {
4984      for (var waypointKey in this.waypoints[axis]) {
4985        allWaypoints.push(this.waypoints[axis][waypointKey])
4986      }
4987    }
4988    for (var i = 0, end = allWaypoints.length; i < end; i++) {
4989      allWaypoints[i].destroy()
4990    }
4991  }
4992
4993  /* Public */
4994  /* http://imakewebthings.com/waypoints/api/context-refresh */
4995  Context.prototype.refresh = function() {
4996    /*eslint-disable eqeqeq */
4997    var isWindow = this.element == this.element.window
4998    /*eslint-enable eqeqeq */
4999    var contextOffset = isWindow ? undefined : this.adapter.offset()
5000    var triggeredGroups = {}
5001    var axes
5002
5003    this.handleScroll()
5004    axes = {
5005      horizontal: {
5006        contextOffset: isWindow ? 0 : contextOffset.left,
5007        contextScroll: isWindow ? 0 : this.oldScroll.x,
5008        contextDimension: this.innerWidth(),
5009        oldScroll: this.oldScroll.x,
5010        forward: 'right',
5011        backward: 'left',
5012        offsetProp: 'left'
5013      },
5014      vertical: {
5015        contextOffset: isWindow ? 0 : contextOffset.top,
5016        contextScroll: isWindow ? 0 : this.oldScroll.y,
5017        contextDimension: this.innerHeight(),
5018        oldScroll: this.oldScroll.y,
5019        forward: 'down',
5020        backward: 'up',
5021        offsetProp: 'top'
5022      }
5023    }
5024
5025    for (var axisKey in axes) {
5026      var axis = axes[axisKey]
5027      for (var waypointKey in this.waypoints[axisKey]) {
5028        var waypoint = this.waypoints[axisKey][waypointKey]
5029        var adjustment = waypoint.options.offset
5030        var oldTriggerPoint = waypoint.triggerPoint
5031        var elementOffset = 0
5032        var freshWaypoint = oldTriggerPoint == null
5033        var contextModifier, wasBeforeScroll, nowAfterScroll
5034        var triggeredBackward, triggeredForward
5035
5036        if (waypoint.element !== waypoint.element.window) {
5037          elementOffset = waypoint.adapter.offset()[axis.offsetProp]
5038        }
5039
5040        if (typeof adjustment === 'function') {
5041          adjustment = adjustment.apply(waypoint)
5042        }
5043        else if (typeof adjustment === 'string') {
5044          adjustment = parseFloat(adjustment)
5045          if (waypoint.options.offset.indexOf('%') > - 1) {
5046            adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
5047          }
5048        }
5049
5050        contextModifier = axis.contextScroll - axis.contextOffset
5051        waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
5052        wasBeforeScroll = oldTriggerPoint < axis.oldScroll
5053        nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
5054        triggeredBackward = wasBeforeScroll && nowAfterScroll
5055        triggeredForward = !wasBeforeScroll && !nowAfterScroll
5056
5057        if (!freshWaypoint && triggeredBackward) {
5058          waypoint.queueTrigger(axis.backward)
5059          triggeredGroups[waypoint.group.id] = waypoint.group
5060        }
5061        else if (!freshWaypoint && triggeredForward) {
5062          waypoint.queueTrigger(axis.forward)
5063          triggeredGroups[waypoint.group.id] = waypoint.group
5064        }
5065        else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
5066          waypoint.queueTrigger(axis.forward)
5067          triggeredGroups[waypoint.group.id] = waypoint.group
5068        }
5069      }
5070    }
5071
5072    Waypoint.requestAnimationFrame(function() {
5073      for (var groupKey in triggeredGroups) {
5074        triggeredGroups[groupKey].flushTriggers()
5075      }
5076    })
5077
5078    return this
5079  }
5080
5081  /* Private */
5082  Context.findOrCreateByElement = function(element) {
5083    return Context.findByElement(element) || new Context(element)
5084  }
5085
5086  /* Private */
5087  Context.refreshAll = function() {
5088    for (var contextId in contexts) {
5089      contexts[contextId].refresh()
5090    }
5091  }
5092
5093  /* Public */
5094  /* http://imakewebthings.com/waypoints/api/context-find-by-element */
5095  Context.findByElement = function(element) {
5096    return contexts[element.waypointContextKey]
5097  }
5098
5099  window.onload = function() {
5100    if (oldWindowLoad) {
5101      oldWindowLoad()
5102    }
5103    Context.refreshAll()
5104  }
5105
5106
5107  Waypoint.requestAnimationFrame = function(callback) {
5108    var requestFn = window.requestAnimationFrame ||
5109      window.mozRequestAnimationFrame ||
5110      window.webkitRequestAnimationFrame ||
5111      requestAnimationFrameShim
5112    requestFn.call(window, callback)
5113  }
5114  Waypoint.Context = Context
5115}())
5116;(function() {
5117  'use strict'
5118
5119  function byTriggerPoint(a, b) {
5120    return a.triggerPoint - b.triggerPoint
5121  }
5122
5123  function byReverseTriggerPoint(a, b) {
5124    return b.triggerPoint - a.triggerPoint
5125  }
5126
5127  var groups = {
5128    vertical: {},
5129    horizontal: {}
5130  }
5131  var Waypoint = window.Waypoint
5132
5133  /* http://imakewebthings.com/waypoints/api/group */
5134  function Group(options) {
5135    this.name = options.name
5136    this.axis = options.axis
5137    this.id = this.name + '-' + this.axis
5138    this.waypoints = []
5139    this.clearTriggerQueues()
5140    groups[this.axis][this.name] = this
5141  }
5142
5143  /* Private */
5144  Group.prototype.add = function(waypoint) {
5145    this.waypoints.push(waypoint)
5146  }
5147
5148  /* Private */
5149  Group.prototype.clearTriggerQueues = function() {
5150    this.triggerQueues = {
5151      up: [],
5152      down: [],
5153      left: [],
5154      right: []
5155    }
5156  }
5157
5158  /* Private */
5159  Group.prototype.flushTriggers = function() {
5160    for (var direction in this.triggerQueues) {
5161      var waypoints = this.triggerQueues[direction]
5162      var reverse = direction === 'up' || direction === 'left'
5163      waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
5164      for (var i = 0, end = waypoints.length; i < end; i += 1) {
5165        var waypoint = waypoints[i]
5166        if (waypoint.options.continuous || i === waypoints.length - 1) {
5167          waypoint.trigger([direction])
5168        }
5169      }
5170    }
5171    this.clearTriggerQueues()
5172  }
5173
5174  /* Private */
5175  Group.prototype.next = function(waypoint) {
5176    this.waypoints.sort(byTriggerPoint)
5177    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
5178    var isLast = index === this.waypoints.length - 1
5179    return isLast ? null : this.waypoints[index + 1]
5180  }
5181
5182  /* Private */
5183  Group.prototype.previous = function(waypoint) {
5184    this.waypoints.sort(byTriggerPoint)
5185    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
5186    return index ? this.waypoints[index - 1] : null
5187  }
5188
5189  /* Private */
5190  Group.prototype.queueTrigger = function(waypoint, direction) {
5191    this.triggerQueues[direction].push(waypoint)
5192  }
5193
5194  /* Private */
5195  Group.prototype.remove = function(waypoint) {
5196    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
5197    if (index > -1) {
5198      this.waypoints.splice(index, 1)
5199    }
5200  }
5201
5202  /* Public */
5203  /* http://imakewebthings.com/waypoints/api/first */
5204  Group.prototype.first = function() {
5205    return this.waypoints[0]
5206  }
5207
5208  /* Public */
5209  /* http://imakewebthings.com/waypoints/api/last */
5210  Group.prototype.last = function() {
5211    return this.waypoints[this.waypoints.length - 1]
5212  }
5213
5214  /* Private */
5215  Group.findOrCreate = function(options) {
5216    return groups[options.axis][options.name] || new Group(options)
5217  }
5218
5219  Waypoint.Group = Group
5220}())
5221;(function() {
5222  'use strict'
5223
5224  var $ = window.jQuery
5225  var Waypoint = window.Waypoint
5226
5227  function JQueryAdapter(element) {
5228    this.$element = $(element)
5229  }
5230
5231  $.each([
5232    'innerHeight',
5233    'innerWidth',
5234    'off',
5235    'offset',
5236    'on',
5237    'outerHeight',
5238    'outerWidth',
5239    'scrollLeft',
5240    'scrollTop'
5241  ], function(i, method) {
5242    JQueryAdapter.prototype[method] = function() {
5243      var args = Array.prototype.slice.call(arguments)
5244      return this.$element[method].apply(this.$element, args)
5245    }
5246  })
5247
5248  $.each([
5249    'extend',
5250    'inArray',
5251    'isEmptyObject'
5252  ], function(i, method) {
5253    JQueryAdapter[method] = $[method]
5254  })
5255
5256  Waypoint.adapters.push({
5257    name: 'jquery',
5258    Adapter: JQueryAdapter
5259  })
5260  Waypoint.Adapter = JQueryAdapter
5261}())
5262;(function() {
5263  'use strict'
5264
5265  var Waypoint = window.Waypoint
5266
5267  function createExtension(framework) {
5268    return function() {
5269      var waypoints = []
5270      var overrides = arguments[0]
5271
5272      if (framework.isFunction(arguments[0])) {
5273        overrides = framework.extend({}, arguments[1])
5274        overrides.handler = arguments[0]
5275      }
5276
5277      this.each(function() {
5278        var options = framework.extend({}, overrides, {
5279          element: this
5280        })
5281        if (typeof options.context === 'string') {
5282          options.context = framework(this).closest(options.context)[0]
5283        }
5284        waypoints.push(new Waypoint(options))
5285      })
5286
5287      return waypoints
5288    }
5289  }
5290
5291  if (window.jQuery) {
5292    window.jQuery.fn.waypoint = createExtension(window.jQuery)
5293  }
5294  if (window.Zepto) {
5295    window.Zepto.fn.waypoint = createExtension(window.Zepto)
5296  }
5297}())
5298;
5299
5300/*!
5301Waypoints Inview Shortcut - 4.0.1
5302Copyright © 2011-2016 Caleb Troughton
5303Licensed under the MIT license.
5304https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
5305*/
5306(function() {
5307  'use strict'
5308
5309  function noop() {}
5310
5311  var Waypoint = window.Waypoint
5312
5313  /* http://imakewebthings.com/waypoints/shortcuts/inview */
5314  function Inview(options) {
5315    this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
5316    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
5317    this.waypoints = []
5318    this.element = this.options.element
5319    this.createWaypoints()
5320  }
5321
5322  /* Private */
5323  Inview.prototype.createWaypoints = function() {
5324    var configs = {
5325      vertical: [{
5326        down: 'enter',
5327        up: 'exited',
5328        offset: '100%'
5329      }, {
5330        down: 'entered',
5331        up: 'exit',
5332        offset: 'bottom-in-view'
5333      }, {
5334        down: 'exit',
5335        up: 'entered',
5336        offset: 0
5337      }, {
5338        down: 'exited',
5339        up: 'enter',
5340        offset: function() {
5341          return -this.adapter.outerHeight()
5342        }
5343      }],
5344      horizontal: [{
5345        right: 'enter',
5346        left: 'exited',
5347        offset: '100%'
5348      }, {
5349        right: 'entered',
5350        left: 'exit',
5351        offset: 'right-in-view'
5352      }, {
5353        right: 'exit',
5354        left: 'entered',
5355        offset: 0
5356      }, {
5357        right: 'exited',
5358        left: 'enter',
5359        offset: function() {
5360          return -this.adapter.outerWidth()
5361        }
5362      }]
5363    }
5364
5365    for (var i = 0, end = configs[this.axis].length; i < end; i++) {
5366      var config = configs[this.axis][i]
5367      this.createWaypoint(config)
5368    }
5369  }
5370
5371  /* Private */
5372  Inview.prototype.createWaypoint = function(config) {
5373    var self = this
5374    this.waypoints.push(new Waypoint({
5375      context: this.options.context,
5376      element: this.options.element,
5377      enabled: this.options.enabled,
5378      handler: (function(config) {
5379        return function(direction) {
5380          self.options[config[direction]].call(self, direction)
5381        }
5382      }(config)),
5383      offset: config.offset,
5384      horizontal: this.options.horizontal
5385    }))
5386  }
5387
5388  /* Public */
5389  Inview.prototype.destroy = function() {
5390    for (var i = 0, end = this.waypoints.length; i < end; i++) {
5391      this.waypoints[i].destroy()
5392    }
5393    this.waypoints = []
5394  }
5395
5396  Inview.prototype.disable = function() {
5397    for (var i = 0, end = this.waypoints.length; i < end; i++) {
5398      this.waypoints[i].disable()
5399    }
5400  }
5401
5402  Inview.prototype.enable = function() {
5403    for (var i = 0, end = this.waypoints.length; i < end; i++) {
5404      this.waypoints[i].enable()
5405    }
5406  }
5407
5408  Inview.defaults = {
5409    context: window,
5410    enabled: true,
5411    enter: noop,
5412    entered: noop,
5413    exit: noop,
5414    exited: noop
5415  }
5416
5417  Waypoint.Inview = Inview
5418}())
5419;
5420
5421/*
5422 * SmartMenus jQuery v0.9.6
5423 * http://www.smartmenus.org/
5424 *
5425 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd.
5426 * http://vadikom.com/
5427 *
5428 * Released under the MIT license:
5429 * http://www.opensource.org/licenses/MIT
5430 */
5431
5432(function($) {
5433
5434	var menuTrees = [],
5435		IE = !!window.createPopup, // we need to detect it, unfortunately
5436		IElt9 = IE && !document.defaultView,
5437		IElt8 = IE && !document.querySelector,
5438		IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined',
5439		mouse = false, // optimize for touch by default - we will detect for mouse input
5440		mouseDetectionEnabled = false;
5441
5442	// Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.)
5443	function initMouseDetection(disable) {
5444		if (!mouseDetectionEnabled && !disable) {
5445			// if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present
5446			// 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)
5447			var firstTime = true,
5448				lastMove = null;
5449			$(document).bind({
5450				'mousemove.smartmenus_mouse': function(e) {
5451					var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() };
5452					if (lastMove) {
5453						var deltaX = Math.abs(lastMove.x - thisMove.x),
5454							deltaY = Math.abs(lastMove.y - thisMove.y);
5455	 					if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
5456							mouse = true;
5457							// 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
5458							if (firstTime) {
5459								var $a = $(e.target).closest('a');
5460								if ($a.is('a')) {
5461									$.each(menuTrees, function() {
5462										if ($.contains(this.$root[0], $a[0])) {
5463											this.itemEnter({ currentTarget: $a[0] });
5464											return false;
5465										}
5466									});
5467								}
5468								firstTime = false;
5469							}
5470						}
5471					}
5472					lastMove = thisMove;
5473				},
5474				'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) {
5475					if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) {
5476						mouse = false;
5477					}
5478				}
5479			});
5480			mouseDetectionEnabled = true;
5481		} else if (mouseDetectionEnabled && disable) {
5482			$(document).unbind('.smartmenus_mouse');
5483			mouseDetectionEnabled = false;
5484		}
5485	};
5486
5487	$.SmartMenus = function(elm, options) {
5488		this.$root = $(elm);
5489		this.opts = options;
5490		this.rootId = ''; // internal
5491		this.$subArrow = null;
5492		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)
5493		this.activatedItems = []; // stores last activated A's for each level
5494		this.visibleSubMenus = []; // stores visible sub menus UL's
5495		this.showTimeout = 0;
5496		this.hideTimeout = 0;
5497		this.scrollTimeout = 0;
5498		this.clickActivated = false;
5499		this.zIndexInc = 0;
5500		this.$firstLink = null; // we'll use these for some tests
5501		this.$firstSub = null; // at runtime so we'll cache them
5502		this.disabled = false;
5503		this.$disableOverlay = null;
5504		this.init();
5505	};
5506
5507	$.extend($.SmartMenus, {
5508		hideAll: function() {
5509			$.each(menuTrees, function() {
5510				this.menuHideAll();
5511			});
5512		},
5513		destroy: function() {
5514			while (menuTrees.length) {
5515				menuTrees[0].destroy();
5516			}
5517			initMouseDetection(true);
5518		},
5519		prototype: {
5520			init: function(refresh) {
5521				var self = this;
5522
5523				if (!refresh) {
5524					menuTrees.push(this);
5525
5526					this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, '');
5527
5528					if (this.$root.hasClass('sm-rtl')) {
5529						this.opts.rightToLeftSubMenus = true;
5530					}
5531
5532					// init root (main menu)
5533					this.$root
5534						.data('smartmenus', this)
5535						.attr('data-smartmenus-id', this.rootId)
5536						.dataSM('level', 1)
5537						.bind({
5538							'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
5539							'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this)
5540						})
5541						.delegate('a', {
5542							'mouseenter.smartmenus': $.proxy(this.itemEnter, this),
5543							'mouseleave.smartmenus': $.proxy(this.itemLeave, this),
5544							'mousedown.smartmenus': $.proxy(this.itemDown, this),
5545							'focus.smartmenus': $.proxy(this.itemFocus, this),
5546							'blur.smartmenus': $.proxy(this.itemBlur, this),
5547							'click.smartmenus': $.proxy(this.itemClick, this),
5548							'touchend.smartmenus': $.proxy(this.itemTouchEnd, this)
5549						});
5550
5551					var eNamespace = '.smartmenus' + this.rootId;
5552					// hide menus on tap or click outside the root UL
5553					if (this.opts.hideOnClick) {
5554						$(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this))
5555							.bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this))
5556							.bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this))
5557							// for Opera Mobile < 11.5, webOS browser, etc. we'll check click too
5558							.bind('click' + eNamespace, $.proxy(this.docClick, this));
5559					}
5560					// hide sub menus on resize
5561					$(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
5562					$(window).bind('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
5563
5564					if (this.opts.subIndicators) {
5565						this.$subArrow = $('<span/>').addClass('sub-arrow');
5566						if (this.opts.subIndicatorsText) {
5567							this.$subArrow.html(this.opts.subIndicatorsText);
5568						}
5569					}
5570
5571					// make sure mouse detection is enabled
5572					initMouseDetection();
5573				}
5574
5575				// init sub menus
5576				this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0);
5577
5578				this.$firstLink = this.$root.find('a').eq(0);
5579
5580				// find current item
5581				if (this.opts.markCurrentItem) {
5582					var reDefaultDoc = /(index|default)\.[^#\?\/]*/i,
5583						reHash = /#.*/,
5584						locHref = window.location.href.replace(reDefaultDoc, ''),
5585						locHrefNoHash = locHref.replace(reHash, '');
5586					this.$root.find('a').each(function() {
5587						var href = this.href.replace(reDefaultDoc, ''),
5588							$this = $(this);
5589						if (href == locHref || href == locHrefNoHash) {
5590							$this.addClass('current');
5591							if (self.opts.markCurrentTree) {
5592								$this.parents('li').each(function() {
5593									var $this = $(this);
5594									if ($this.dataSM('sub')) {
5595										$this.children('a').addClass('current');
5596									}
5597								});
5598							}
5599						}
5600					});
5601				}
5602			},
5603			destroy: function() {
5604				this.menuHideAll();
5605				this.$root
5606					.removeData('smartmenus')
5607					.removeAttr('data-smartmenus-id')
5608					.removeDataSM('level')
5609					.unbind('.smartmenus')
5610					.undelegate('.smartmenus');
5611				var eNamespace = '.smartmenus' + this.rootId;
5612				$(document).unbind(eNamespace);
5613				$(window).unbind(eNamespace);
5614				if (this.opts.subIndicators) {
5615					this.$subArrow = null;
5616				}
5617				var self = this;
5618				$.each(this.subMenus, function() {
5619					if (this.hasClass('mega-menu')) {
5620						this.find('ul').removeDataSM('in-mega');
5621					}
5622					if (this.dataSM('shown-before')) {
5623						if (IElt8) {
5624							this.children().css({ styleFloat: '', width: '' });
5625						}
5626						if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) {
5627							if (!IE6) {
5628								this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap');
5629							} else {
5630								this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', '');
5631							}
5632						}
5633						if (this.dataSM('scroll-arrows')) {
5634							this.dataSM('scroll-arrows').remove();
5635						}
5636						this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' });
5637					}
5638					if (self.opts.subIndicators) {
5639						this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove();
5640					}
5641					this.removeDataSM('shown-before')
5642						.removeDataSM('ie-shim')
5643						.removeDataSM('scroll-arrows')
5644						.removeDataSM('parent-a')
5645						.removeDataSM('level')
5646						.removeDataSM('beforefirstshowfired')
5647						.parent().removeDataSM('sub');
5648				});
5649				if (this.opts.markCurrentItem) {
5650					this.$root.find('a.current').removeClass('current');
5651				}
5652				this.$root = null;
5653				this.$firstLink = null;
5654				this.$firstSub = null;
5655				if (this.$disableOverlay) {
5656					this.$disableOverlay.remove();
5657					this.$disableOverlay = null;
5658				}
5659				menuTrees.splice($.inArray(this, menuTrees), 1);
5660			},
5661			disable: function(noOverlay) {
5662				if (!this.disabled) {
5663					this.menuHideAll();
5664					// display overlay over the menu to prevent interaction
5665					if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) {
5666						var pos = this.$root.offset();
5667						this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({
5668							position: 'absolute',
5669							top: pos.top,
5670							left: pos.left,
5671							width: this.$root.outerWidth(),
5672							height: this.$root.outerHeight(),
5673							zIndex: this.getStartZIndex() + 1,
5674							opacity: 0
5675						}).appendTo(document.body);
5676					}
5677					this.disabled = true;
5678				}
5679			},
5680			docClick: function(e) {
5681				// hide on any click outside the menu or on a menu link
5682				if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) {
5683					this.menuHideAll($(e.target));
5684				}
5685			},
5686			docTouchEnd: function(e) {
5687				if (!this.lastTouch) {
5688					return;
5689				}
5690				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))) {
5691					if (this.hideTimeout) {
5692						clearTimeout(this.hideTimeout);
5693						this.hideTimeout = 0;
5694					}
5695					// hide with a delay to prevent triggering accidental unwanted click on some page element
5696					var self = this;
5697					this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350);
5698				}
5699				this.lastTouch = null;
5700			},
5701			docTouchMove: function(e) {
5702				if (!this.lastTouch) {
5703					return;
5704				}
5705				var touchPoint = e.originalEvent.touches[0];
5706				this.lastTouch.x2 = touchPoint.pageX;
5707				this.lastTouch.y2 = touchPoint.pageY;
5708			},
5709			docTouchStart: function(e) {
5710				var touchPoint = e.originalEvent.touches[0];
5711				this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target };
5712			},
5713			enable: function() {
5714				if (this.disabled) {
5715					if (this.$disableOverlay) {
5716						this.$disableOverlay.remove();
5717						this.$disableOverlay = null;
5718					}
5719					this.disabled = false;
5720				}
5721			},
5722			getHeight: function($elm) {
5723				return this.getOffset($elm, true);
5724			},
5725			// returns precise width/height float values in IE9+, FF4+, recent WebKit
5726			// http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
5727			getOffset: function($elm, height) {
5728				var old;
5729				if ($elm.css('display') == 'none') {
5730					old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility };
5731					$elm.css({ position: 'absolute', visibility: 'hidden' }).show();
5732				}
5733				var defaultView = $elm[0].ownerDocument.defaultView,
5734					compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null),
5735					val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']);
5736				if (val) {
5737					val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft'])
5738	 					+ parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight'])
5739	 					+ parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth'])
5740	 					+ parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']);
5741				} else {
5742					val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth;
5743				}
5744				if (old) {
5745					$elm.hide().css(old);
5746				}
5747				return val;
5748			},
5749			getWidth: function($elm) {
5750				return this.getOffset($elm);
5751			},
5752			getStartZIndex: function() {
5753				var zIndex = parseInt(this.$root.css('z-index'));
5754				return !isNaN(zIndex) ? zIndex : 1;
5755			},
5756			handleEvents: function() {
5757				return !this.disabled && this.isCSSOn();
5758			},
5759			handleItemEvents: function($a) {
5760				return this.handleEvents() && !this.isLinkInMegaMenu($a);
5761			},
5762			isCollapsible: function() {
5763				return this.$firstSub.css('position') == 'static';
5764			},
5765			isCSSOn: function() {
5766				return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'inline';
5767			},
5768			isFixed: function() {
5769				return this.$root.css('position') == 'fixed';
5770			},
5771			isLinkInMegaMenu: function($a) {
5772				return !$a.parent().parent().dataSM('level');
5773			},
5774			isTouchMode: function() {
5775				return !mouse || this.isCollapsible();
5776			},
5777			itemActivate: function($a) {
5778				var $li = $a.parent(),
5779					$ul = $li.parent(),
5780					level = $ul.dataSM('level');
5781				// 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
5782				if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) {
5783					var self = this;
5784					$($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() {
5785						self.itemActivate($(this).dataSM('parent-a'));
5786					});
5787				}
5788				// hide any visible deeper level sub menus
5789				if (this.visibleSubMenus.length > level) {
5790					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--) {
5791						this.menuHide(this.visibleSubMenus[i]);
5792					}
5793				}
5794				// save new active item and sub menu for this level
5795				this.activatedItems[level - 1] = $a;
5796				this.visibleSubMenus[level - 1] = $ul;
5797				if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) {
5798					return;
5799				}
5800				// show the sub menu if this item has one
5801				var $sub = $li.dataSM('sub');
5802				if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) {
5803					this.menuShow($sub);
5804				}
5805			},
5806			itemBlur: function(e) {
5807				var $a = $(e.currentTarget);
5808				if (!this.handleItemEvents($a)) {
5809					return;
5810				}
5811				this.$root.triggerHandler('blur.smapi', $a[0]);
5812			},
5813			itemClick: function(e) {
5814				var $a = $(e.currentTarget);
5815
5816				if (!this.handleItemEvents($a)) {
5817					return;
5818				}
5819				$a.removeDataSM('mousedown');
5820				if (this.$root.triggerHandler('click.smapi', $a[0]) === false) {
5821					return false;
5822				}
5823				var $sub = $a.parent().dataSM('sub');
5824				if (this.isTouchMode()) {
5825					// undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu
5826					if ($a.dataSM('href')) {
5827						$a.attr('href', $a.dataSM('href')).removeDataSM('href');
5828					}
5829					// if the sub is not visible
5830					if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
5831						// try to activate the item and show the sub
5832						this.itemActivate($a);
5833						// if "itemActivate" showed the sub, prevent the click so that the link is not loaded
5834						// 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
5835						if ($sub.is(':visible')) {
5836							return false;
5837						}
5838					}
5839				} else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) {
5840					this.clickActivated = true;
5841					this.menuShow($sub);
5842					return false;
5843				}
5844				if ($a.hasClass('disabled')) {
5845					return false;
5846				}
5847				if (this.$root.triggerHandler('select.smapi', $a[0]) === false) {
5848					return false;
5849				}
5850			},
5851			itemDown: function(e) {
5852				var $a = $(e.currentTarget);
5853				if (!this.handleItemEvents($a)) {
5854					return;
5855				}
5856				$a.dataSM('mousedown', true);
5857			},
5858			itemEnter: function(e) {
5859				var $a = $(e.currentTarget);
5860				if (!this.handleItemEvents($a)) {
5861					return;
5862				}
5863				if (!this.isTouchMode()) {
5864					if (this.showTimeout) {
5865						clearTimeout(this.showTimeout);
5866						this.showTimeout = 0;
5867					}
5868					var self = this;
5869					this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout);
5870				}
5871				this.$root.triggerHandler('mouseenter.smapi', $a[0]);
5872			},
5873			itemFocus: function(e) {
5874				var $a = $(e.currentTarget);
5875				if (!this.handleItemEvents($a)) {
5876					return;
5877				}
5878				// 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
5879				if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) {
5880					this.itemActivate($a);
5881				}
5882				this.$root.triggerHandler('focus.smapi', $a[0]);
5883			},
5884			itemLeave: function(e) {
5885				var $a = $(e.currentTarget);
5886				if (!this.handleItemEvents($a)) {
5887					return;
5888				}
5889				if (!this.isTouchMode()) {
5890					if ($a[0].blur) {
5891						$a[0].blur();
5892					}
5893					if (this.showTimeout) {
5894						clearTimeout(this.showTimeout);
5895						this.showTimeout = 0;
5896					}
5897				}
5898				$a.removeDataSM('mousedown');
5899				this.$root.triggerHandler('mouseleave.smapi', $a[0]);
5900			},
5901			itemTouchEnd: function(e) {
5902				var $a = $(e.currentTarget);
5903				if (!this.handleItemEvents($a)) {
5904					return;
5905				}
5906				// prevent the address bar on iPhone from sliding down when expanding a sub menu
5907				var $sub = $a.parent().dataSM('sub');
5908				if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
5909					$a.dataSM('href', $a.attr('href'));
5910					$a.attr('href', '#');
5911				}
5912			},
5913			menuFixLayout: function($ul) {
5914				// fixes a menu that is being shown for the first time
5915				if (!$ul.dataSM('shown-before')) {
5916					$ul.hide().dataSM('shown-before', true);
5917					// fix the layout of the items in IE<8
5918					if (IElt8) {
5919						$ul.children().css({ styleFloat: 'left', width: '100%' });
5920					}
5921				}
5922			},
5923			menuHide: function($sub) {
5924				if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) {
5925					return;
5926				}
5927				$sub.stop(true, true);
5928				if ($sub.is(':visible')) {
5929					var complete = function() {
5930						// unset z-index
5931						if (IElt9) {
5932							$sub.parent().css('z-index', '');
5933						} else {
5934							$sub.css('z-index', '');
5935						}
5936					};
5937					// if sub is collapsible (mobile view)
5938					if (this.isCollapsible()) {
5939						if (this.opts.collapsibleHideFunction) {
5940							this.opts.collapsibleHideFunction.call(this, $sub, complete);
5941						} else {
5942							$sub.hide(this.opts.collapsibleHideDuration, complete);
5943						}
5944					} else {
5945						if (this.opts.hideFunction) {
5946							this.opts.hideFunction.call(this, $sub, complete);
5947						} else {
5948							$sub.hide(this.opts.hideDuration, complete);
5949						}
5950					}
5951					// remove IE iframe shim
5952					if ($sub.dataSM('ie-shim')) {
5953						$sub.dataSM('ie-shim').remove();
5954					}
5955					// deactivate scrolling if it is activated for this sub
5956					if ($sub.dataSM('scroll')) {
5957						$sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide();
5958					}
5959					// unhighlight parent item
5960					$sub.dataSM('parent-a').removeClass('highlighted');
5961					var level = $sub.dataSM('level');
5962					this.activatedItems.splice(level - 1, 1);
5963					this.visibleSubMenus.splice(level - 1, 1);
5964					this.$root.triggerHandler('hide.smapi', $sub[0]);
5965				}
5966			},
5967			menuHideAll: function($item) {
5968				if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return;
5969				if (this.showTimeout) {
5970					clearTimeout(this.showTimeout);
5971					this.showTimeout = 0;
5972				}
5973				// hide all subs
5974				for (var i = this.visibleSubMenus.length - 1; i > 0; i--) {
5975					this.menuHide(this.visibleSubMenus[i]);
5976				}
5977				// hide root if it's popup
5978				if (this.opts.isPopup) {
5979					this.$root.stop(true, true);
5980					if (this.$root.is(':visible')) {
5981						if (this.opts.hideFunction) {
5982							this.opts.hideFunction.call(this, this.$root);
5983						} else {
5984							this.$root.hide(this.opts.hideDuration);
5985						}
5986						// remove IE iframe shim
5987						if (this.$root.dataSM('ie-shim')) {
5988							this.$root.dataSM('ie-shim').remove();
5989						}
5990					}
5991				}
5992				this.activatedItems = [];
5993				this.visibleSubMenus = [];
5994				this.clickActivated = false;
5995				// reset z-index increment
5996				this.zIndexInc = 0;
5997			},
5998			menuIframeShim: function($ul) {
5999				// create iframe shim for the menu
6000				if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
6001					$ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
6002						.css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
6003					);
6004				}
6005			},
6006			menuInit: function($ul) {
6007				if (!$ul.dataSM('in-mega')) {
6008					this.subMenus.push($ul);
6009					// mark UL's in mega drop downs (if any) so we can neglect them
6010					if ($ul.hasClass('mega-menu')) {
6011						$ul.find('ul').dataSM('in-mega', true);
6012					}
6013					// get level (much faster than, for example, using parentsUntil)
6014					var level = 2,
6015						par = $ul[0];
6016					while ((par = par.parentNode.parentNode) != this.$root[0]) {
6017						level++;
6018					}
6019					// cache stuff
6020					$ul.dataSM('parent-a', $ul.prevAll('a').eq(-1))
6021						.dataSM('level', level)
6022						.parent().dataSM('sub', $ul);
6023					// add sub indicator to parent item
6024					if (this.opts.subIndicators) {
6025						$ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone());
6026					}
6027				}
6028			},
6029			menuPosition: function($sub) {
6030				var fixIE = $('html.ie').length;
6031				// if (fixIE) {
6032				// 	var $rowParent = $($sub).closest('.main-menu-container');
6033				// 	$rowParent.height($rowParent.height());
6034				// }
6035				var $a = $sub.dataSM('parent-a'),
6036					$li = $sub.parent(),
6037					$ul = $sub.parent().parent(),
6038					$container = $ul.closest('.row-menu-inner'),
6039					level = $sub.dataSM('level'),
6040					subW = this.getWidth($sub),
6041					subH = this.getHeight($sub),
6042					itemOffset = $a.offset(),
6043					itemX = itemOffset.left,
6044					itemY = itemOffset.top,
6045					itemW = this.getWidth($a),
6046					itemH = this.getHeight($a),
6047					$win = $(window),
6048					winX = $win.scrollLeft(),
6049					winY = $win.scrollTop(),
6050					winW = $win.width(),
6051					winH = $win.height(),
6052					containerW = $container.width(),
6053					containerOffsetX = containerW + ((winW - containerW) / 2),
6054					horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'),
6055					subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
6056					subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
6057					x, y, leftPos;
6058				if (horizontalParent) {
6059					x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX;
6060					y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
6061				} else {
6062					x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX;
6063					y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
6064				}
6065				if (this.opts.keepInViewport && !this.isCollapsible()) {
6066					if (this.isFixed()) {
6067						itemX -= winX;
6068						itemY -= winY;
6069						winX = winY = 0;
6070					}
6071					var absX = itemX + x,
6072						absY = itemY + y;
6073					if (this.opts.rightToLeftSubMenus && absX < winX) {
6074						x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
6075					} else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) {
6076						x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW;
6077					}
6078					if (!horizontalParent) {
6079						if (subH < winH && absY + subH > winY + winH) {
6080							y += winY + winH - subH - absY;
6081						} else if (subH >= winH || absY < winY) {
6082							y += winY - absY;
6083						}
6084					}
6085					// do we need scrolling?
6086					// 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH"
6087					if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) {
6088						var self = this;
6089						if (!$sub.dataSM('scroll-arrows')) {
6090							$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]])
6091								.bind({
6092									mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); },
6093									mouseleave: function(e) {
6094										self.menuScrollStop($sub);
6095										self.menuScrollOut($sub, e);
6096									},
6097									'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
6098								})
6099								.insertAfter($sub)
6100							);
6101						}
6102						// bind events to show/hide arrows on hover and save scrolling data for this sub
6103						var vportY = winY - (itemY + itemH);
6104						$sub.dataSM('scroll', {
6105								vportY: vportY,
6106								subH: subH,
6107								winH: winH,
6108								step: 1
6109							})
6110							.bind({
6111								'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); },
6112								'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); },
6113								'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); }
6114							})
6115							.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
6115StartZIndex() + this.zIndexInc })
6116							.eq(0).css('margin-top', vportY).end()
6117							.eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end()
6118							.eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
6119					}
6120				}
6121				// if ($sub.hasClass('mega-menu-inner')) {
6122				// 	if ($('.menu-wrapper .megamenu-diff').length > 0) {
6123				// 		leftPos = parseFloat($('.menu-wrapper .megamenu-diff').outerWidth());
6124				// 		leftPos = -leftPos;
6125				// 	} else leftPos = parseFloat($('.menu-wrapper .main-menu-container').css('paddingLeft'));
6126
6127				// 	if ($('body.header-full-width').length > 0) {
6128				// 		$sub.css({ width: $('.box-container').width()});
6129				// 		leftPos = (leftPos - parseFloat($('.menu-wrapper .row-menu-inner').css('paddingLeft')));
6130				// 	} else $sub.css({ width: containerW});
6131				// 	leftPos = leftPos + 'px';
6132
6133				// } else {
6134				// 	leftPos = $li.position().left + 'px';
6135				// }
6136				if ($sub.hasClass('mega-menu-inner')) {
6137					$sub.css({ width: containerW});
6138					if ($('body.hmenu-center-split').length > 0) {
6139						leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px';
6140					} else {
6141						if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0) {
6142							leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px';
6143						} else {
6144							leftPos = '0px';
6145						}
6146					}
6147				} else {
6148					leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px';
6149					x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1;
6150				}
6151
6152				$sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) });
6153				// IE iframe shim
6154				this.menuIframeShim($sub);
6155				if ($sub.dataSM('ie-shim')) {
6156					$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) });
6157				}
6158			},
6159			menuScroll: function($sub, up, wheel) {
6160				var y = parseFloat($sub.css('margin-top')),
6161					scroll = $sub.dataSM('scroll'),
6162					end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH),
6163					step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
6164				$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
6165				y = parseFloat($sub.css('margin-top'));
6166				// show opposite arrow if appropriate
6167				if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
6168					$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
6169				}
6170				// accelerate when not using mousewheel to scroll
6171				if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
6172					$sub.dataSM('scroll').step += 0.5;
6173				}
6174				// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
6175				if (Math.abs(y - end) < 1) {
6176					$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
6177					$sub.dataSM('scroll').step = 1;
6178				} else if (!wheel) {
6179					var self = this;
6180					this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
6181				}
6182			},
6183			menuScrollMousewheel: function($sub, e) {
6184				var $closestSub = $(e.target).closest('ul');
6185				while ($closestSub.dataSM('in-mega')) {
6186					$closestSub = $closestSub.parent().closest('ul');
6187				}
6188				if ($closestSub[0] == $sub[0]) {
6189					var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
6190					if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
6191						this.menuScroll($sub, up, true);
6192					}
6193				}
6194				e.preventDefault();
6195			},
6196			menuScrollOut: function($sub, e) {
6197				var reClass = /^scroll-(up|down)/,
6198					$closestSub = $(e.relatedTarget).closest('ul');
6199				while ($closestSub.dataSM('in-mega')) {
6200					$closestSub = $closestSub.parent().closest('ul');
6201				}
6202				if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
6203					$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
6204				}
6205			},
6206			menuScrollOver: function($sub, e) {
6207				var reClass = /^scroll-(up|down)/,
6208					$closestSub = $(e.target).closest('ul');
6209				while ($closestSub.dataSM('in-mega')) {
6210					$closestSub = $closestSub.parent().closest('ul');
6211				}
6212				if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
6213					$sub.dataSM('scroll-arrows').css('visibility', 'visible');
6214				}
6215			},
6216			menuScrollStop: function($sub) {
6217				if (this.scrollTimeout) {
6218					clearTimeout(this.scrollTimeout);
6219					this.scrollTimeout = 0;
6220					$sub.dataSM('scroll').step = 1;
6221				}
6222			},
6223			menuShow: function($sub) {
6224				if (!$sub.dataSM('beforefirstshowfired')) {
6225					$sub.dataSM('beforefirstshowfired', true);
6226					if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
6227						return;
6228					}
6229				}
6230				if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
6231					return;
6232				}
6233				this.menuFixLayout($sub);
6234				$sub.stop(true, true);
6235				if (!$sub.is(':visible')) {
6236					// set z-index - for IE < 9 set it to the parent LI
6237					var zIndex = this.getStartZIndex() + (++this.zIndexInc);
6238					if (IElt9) {
6239						$sub.parent().css('z-index', zIndex);
6240					} else {
6241						$sub.css('z-index', zIndex);
6242					}
6243					// highlight parent item
6244					if (this.opts.keepHighlighted || this.isCollapsible()) {
6245						if ($sub.dataSM('parent-a').attr('data-type') != 'title')
6246							$sub.dataSM('parent-a').addClass('highlighted');
6247					}
6248					// min/max-width fix - no way to rely purely on CSS as all UL's are nested
6249					if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
6250						if (!IElt8) {
6251							$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
6252							if (this.opts.subMenusMinWidth) {
6253							 	$sub.css('min-width', this.opts.subMenusMinWidth);
6254							}
6255							if (this.opts.subMenusMaxWidth) {
6256							 	var noMaxWidth = this.getWidth($sub);
6257							 	$sub.css('max-width', this.opts.subMenusMaxWidth);
6258								if (noMaxWidth > this.getWidth($sub)) {
6259									$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
6260								}
6261							}
6262						// IE6,7
6263 						} else {
6264							$sub.children().css('styleFloat', 'none');
6265							if (IE6) {
6266								$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
6267									.children().children('a').css('white-space', 'nowrap');
6268							} else { // IE7
6269								$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
6270								if (this.opts.subMenusMinWidth) {
6271							    $sub.css('min-width', this.opts.subMenusMinWidth);
6272								}
6273							}
6274							if (this.opts.subMenusMaxWidth) {
6275								var noMaxWidth = $sub.width();
6276								if (IE6) {
6277							 		var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
6278									if (noMaxWidth > maxWidth) {
6279										$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
6280									} else {
6281										$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
6282									}
6283								} else { // IE7
6284									$sub.css('max-width', this.opts.subMenusMaxWidth);
6285									if (noMaxWidth > $sub.width()) {
6286										$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
6287									} else {
6288										$sub.width(noMaxWidth);
6289									}
6290								}
6291							} else {
6292							 	$sub.width($sub.width());
6293							}
6294							$sub.children().css('styleFloat', 'left');
6295						}
6296					}
6297					this.menuPosition($sub);
6298					// insert IE iframe shim
6299					if ($sub.dataSM('ie-shim')) {
6300						$sub.dataSM('ie-shim').insertBefore($sub);
6301					}
6302					var complete = function() {
6303						// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
6304						$sub.css('overflow', '');
6305					};
6306					// if sub is collapsible (mobile view)
6307					if (this.isCollapsible()) {
6308						if (this.opts.collapsibleShowFunction) {
6309							this.opts.collapsibleShowFunction.call(this, $sub, complete);
6310						} else {
6311							$sub.show(this.opts.collapsibleShowDuration, complete);
6312						}
6313					} else {
6314						if (this.opts.showFunction) {
6315							this.opts.showFunction.call(this, $sub, complete);
6316						} else {
6317							$sub.show(this.opts.showDuration, complete);
6318						}
6319					}
6320					// save new sub menu for this level
6321					this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
6322					this.$root.triggerHandler('show.smapi', $sub[0]);
6323				}
6324			},
6325			popupHide: function(noHideTimeout) {
6326				if (this.hideTimeout) {
6327					clearTimeout(this.hideTimeout);
6328					this.hideTimeout = 0;
6329				}
6330				var self = this;
6331				this.hideTimeout = setTimeout(function() {
6332					self.menuHideAll();
6333				}, noHideTimeout ? 1 : this.opts.hideTimeout);
6334			},
6335			popupShow: function(left, top) {
6336				if (!this.opts.isPopup) {
6337					alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
6338					return;
6339				}
6340				if (this.hideTimeout) {
6341					clearTimeout(this.hideTimeout);
6342					this.hideTimeout = 0;
6343				}
6344				this.menuFixLayout(this.$root);
6345				this.$root.stop(true, true);
6346				if (!this.$root.is(':visible')) {
6347					this.$root.css({ left: left, top: top });
6348					// IE iframe shim
6349					this.menuIframeShim(this.$root);
6350					if (this.$root.dataSM('ie-shim')) {
6351						this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
6351: left, top: top }).insertBefore(this.$root);
6352					}
6353					// show menu
6354					if (this.opts.showFunction) {
6355						this.opts.showFunction.call(this, this.$root);
6356					} else {
6357						this.$root.show(this.opts.showDuration);
6358					}
6359					this.visibleSubMenus[0] = this.$root;
6360				}
6361			},
6362			refresh: function() {
6363				this.menuHideAll();
6364				this.$root.find('ul').each(function() {
6365						var $this = $(this);
6366						if ($this.dataSM('scroll-arrows')) {
6367							$this.dataSM('scroll-arrows').remove();
6368						}
6369					})
6370					.removeDataSM('in-mega')
6371					.removeDataSM('shown-before')
6372					.removeDataSM('ie-shim')
6373					.removeDataSM('scroll-arrows')
6374					.removeDataSM('parent-a')
6375					.removeDataSM('level')
6376					.removeDataSM('beforefirstshowfired');
6377				this.$root.find('a.has-submenu').removeClass('has-submenu')
6378					.parent().removeDataSM('sub');
6379				if (this.opts.subIndicators) {
6380					this.$root.find('span.sub-arrow').remove();
6381				}
6382				if (this.opts.markCurrentItem) {
6383					this.$root.find('a.current').removeClass('current');
6384				}
6385				this.subMenus = [];
6386				this.init(true);
6387			},
6388			rootOut: function(e) {
6389				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
6390					return;
6391				}
6392				if (this.hideTimeout) {
6393					clearTimeout(this.hideTimeout);
6394					this.hideTimeout = 0;
6395				}
6396				if (!this.opts.showOnClick || !this.opts.hideOnClick) {
6397					var self = this;
6398					this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
6399				}
6400			},
6401			rootOver: function(e) {
6402				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
6403					return;
6404				}
6405				if (this.hideTimeout) {
6406					clearTimeout(this.hideTimeout);
6407					this.hideTimeout = 0;
6408				}
6409			},
6410			winResize: function(e) {
6411				if (!this.handleEvents()) {
6412					// we still need to resize the disable overlay if it's visible
6413					if (this.$disableOverlay) {
6414						var pos = this.$root.offset();
6415	 					this.$disableOverlay.css({
6416							top: pos.top,
6417							left: pos.left,
6418							width: this.$root.outerWidth(),
6419							height: this.$root.outerHeight()
6420						});
6421					}
6422					return;
6423				}
6424				// hide sub menus on resize - on mobile do it only on orientation change
6425				if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
6426					if (this.activatedItems.length) {
6427						this.activatedItems[this.activatedItems.length - 1][0].blur();
6428					}
6429					this.menuHideAll();
6430				}
6431			}
6432		}
6433	});
6434
6435	$.fn.dataSM = function(key, val) {
6436		if (val) {
6437			return this.data(key + '_smartmenus', val);
6438		}
6439		return this.data(key + '_smartmenus');
6440	}
6441
6442	$.fn.removeDataSM = function(key) {
6443		return this.removeData(key + '_smartmenus');
6444	}
6445
6446	$.fn.smartmenus = function(options) {
6447		if (typeof options == 'string') {
6448			var args = arguments,
6449				method = options;
6450			Array.prototype.shift.call(args);
6451			return this.each(function() {
6452				var smartmenus = $(this).data('smartmenus');
6453				if (smartmenus && smartmenus[method]) {
6454					smartmenus[method].apply(smartmenus, args);
6455				}
6456			});
6457		}
6458		var opts = $.extend({}, $.fn.smartmenus.defaults, options);
6459		return this.each(function() {
6460			new $.SmartMenus(this, opts);
6461		});
6462	}
6463
6464	// default settings
6465	$.fn.smartmenus.defaults = {
6466		isPopup:		false,		// is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
6467		mainMenuSubOffsetX:	0,		// pixels offset from default position
6468		mainMenuSubOffsetY:	0,		// pixels offset from default position
6469		subMenusSubOffsetX:	0,		// pixels offset from default position
6470		subMenusSubOffsetY:	0,		// pixels offset from default position
6471		subMenusMinWidth:	'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
6472		subMenusMaxWidth:	'20em',		// max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
6473		subIndicators: 		true,		// create sub menu indicators - creates a SPAN and inserts it in the A
6474		subIndicatorsPos: 	'prepend',	// position of the SPAN relative to the menu item content ('prepend', 'append')
6475		subIndicatorsText:	'+',		// [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
6476		scrollStep: 		30,		// pixels step when scrolling long sub menus that do not fit in the viewport height
6477		scrollInterval:		30,		// interval between each scrolling step
6478		scrollAccelerate:	true,		// accelerate scrolling or use a fixed step
6479		showTimeout:		250,		// timeout before showing the sub menus
6480		hideTimeout:		500,		// timeout before hiding the sub menus
6481		showDuration:		0,		// duration for show animation - set to 0 for no animation - matters only if showFunction:null
6482		showFunction:		null,		// custom function to use when showing a sub menu (the default is the jQuery 'show')
6483							// don't forget to call complete() at the end of whatever you do
6484							// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
6485		hideDuration:		0,		// duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
6486		hideFunction:		function($ul, complete) { $ul.fadeOut(200, complete); },	// custom function to use when hiding a sub menu (the default is the jQuery 'hide')
6487							// don't forget to call complete() at the end of whatever you do
6488							// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
6489		collapsibleShowDuration:0,		// duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
6490		collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); },	// custom function to use when showing a collapsible sub menu
6491							// (i.e. when mobile styles are used to make the sub menus collapsible)
6492		collapsibleHideDuration:0,		// duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
6493		collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); },	// custom function to use when hiding a collapsible sub menu
6494							// (i.e. when mobile styles are used to make the sub menus collapsible)
6495		showOnClick:		false,		// show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
6496		hideOnClick:		true,		// hide the sub menus on click/tap anywhere on the page
6497		keepInViewport:		true,		// reposition the sub menus if needed to make sure they always appear inside the viewport
6498		keepHighlighted:	true,		// keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
6499		markCurrentItem:	false,		// automatically add the 'current' class to the A element of the item linking to the current URL
6500		markCurrentTree:	true,		// add the 'current' class also to the A elements of all ancestor items of the current item
6501		rightToLeftSubMenus:	false,		// right to left display of the sub menus (check the CSS for the sub indicators' position)
6502		bottomToTopSubMenus:	false,		// bottom to top display of the sub menus
6503		overlapControlsInIE:	true		// make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
6504	};
6505
6506})(jQuery);
6507
6508/*
6509 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
6510 *
6511 * Uses the built in easing capabilities added In jQuery 1.1
6512 * to offer multiple easing options
6513 *
6514 * TERMS OF USE - jQuery Easing
6515 * 
6516 * Open source under the BSD License. 
6517 * 
6518 * Copyright © 2008 George McGinley Smith
6519 * All rights reserved.
6520 * 
6521 * Redistribution and use in source and binary forms, with or without modification, 
6522 * are permitted provided that the following conditions are met:
6523 * 
6524 * Redistributions of source code must retain the above copyright notice, this list of 
6525 * conditions and the following disclaimer.
6526 * Redistributions in binary form must reproduce the above copyright notice, this list 
6527 * of conditions and the following disclaimer in the documentation and/or other materials 
6528 * provided with the distribution.
6529 * 
6530 * Neither the name of the author nor the names of contributors may be used to endorse 
6531 * or promote products derived from this software without specific prior written permission.
6532 * 
6533 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
6534 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
6535 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
6536 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
vendor: 5,091 bytes, lines 6537-6682
6537 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
6538 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
6539 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6540 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
6541 * OF THE POSSIBILITY OF SUCH DAMAGE. 
6542 *
6543*/
6544
6545// t: current time, b: begInnIng value, c: change In value, d: duration
6546jQuery.easing['jswing'] = jQuery.easing['swing'];
6547
6548jQuery.extend( jQuery.easing,
6549{
6550	def: 'easeOutQuad',
6551	swing: function (x, t, b, c, d) {
6552		//alert(jQuery.easing.default);
6553		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
6554	},
6555	easeInQuad: function (x, t, b, c, d) {
6556		return c*(t/=d)*t + b;
6557	},
6558	easeOutQuad: function (x, t, b, c, d) {
6559		return -c *(t/=d)*(t-2) + b;
6560	},
6561	easeInOutQuad: function (x, t, b, c, d) {
6562		if ((t/=d/2) < 1) return c/2*t*t + b;
6563		return -c/2 * ((--t)*(t-2) - 1) + b;
6564	},
6565	easeInCubic: function (x, t, b, c, d) {
6566		return c*(t/=d)*t*t + b;
6567	},
6568	easeOutCubic: function (x, t, b, c, d) {
6569		return c*((t=t/d-1)*t*t + 1) + b;
6570	},
6571	easeInOutCubic: function (x, t, b, c, d) {
6572		if ((t/=d/2) < 1) return c/2*t*t*t + b;
6573		return c/2*((t-=2)*t*t + 2) + b;
6574	},
6575	easeInQuart: function (x, t, b, c, d) {
6576		return c*(t/=d)*t*t*t + b;
6577	},
6578	easeOutQuart: function (x, t, b, c, d) {
6579		return -c * ((t=t/d-1)*t*t*t - 1) + b;
6580	},
6581	easeInOutQuart: function (x, t, b, c, d) {
6582		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
6583		return -c/2 * ((t-=2)*t*t*t - 2) + b;
6584	},
6585	easeInQuint: function (x, t, b, c, d) {
6586		return c*(t/=d)*t*t*t*t + b;
6587	},
6588	easeOutQuint: function (x, t, b, c, d) {
6589		return c*((t=t/d-1)*t*t*t*t + 1) + b;
6590	},
6591	easeInOutQuint: function (x, t, b, c, d) {
6592		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
6593		return c/2*((t-=2)*t*t*t*t + 2) + b;
6594	},
6595	easeInSine: function (x, t, b, c, d) {
6596		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
6597	},
6598	easeOutSine: function (x, t, b, c, d) {
6599		return c * Math.sin(t/d * (Math.PI/2)) + b;
6600	},
6601	easeInOutSine: function (x, t, b, c, d) {
6602		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
6603	},
6604	easeInExpo: function (x, t, b, c, d) {
6605		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
6606	},
6607	easeOutExpo: function (x, t, b, c, d) {
6608		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
6609	},
6610	easeInOutExpo: function (x, t, b, c, d) {
6611		if (t==0) return b;
6612		if (t==d) return b+c;
6613		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
6614		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
6615	},
6616	easeInCirc: function (x, t, b, c, d) {
6617		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
6618	},
6619	easeOutCirc: function (x, t, b, c, d) {
6620		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
6621	},
6622	easeInOutCirc: function (x, t, b, c, d) {
6623		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
6624		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
6625	},
6626	easeInElastic: function (x, t, b, c, d) {
6627		var s=1.70158;var p=0;var a=c;
6628		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
6629		if (a < Math.abs(c)) { a=c; var s=p/4; }
6630		else var s = p/(2*Math.PI) * Math.asin (c/a);
6631		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
6632	},
6633	easeOutElastic: function (x, t, b, c, d) {
6634		var s=1.70158;var p=0;var a=c;
6635		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
6636		if (a < Math.abs(c)) { a=c; var s=p/4; }
6637		else var s = p/(2*Math.PI) * Math.asin (c/a);
6638		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
6639	},
6640	easeInOutElastic: function (x, t, b, c, d) {
6641		var s=1.70158;var p=0;var a=c;
6642		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
6643		if (a < Math.abs(c)) { a=c; var s=p/4; }
6644		else var s = p/(2*Math.PI) * Math.asin (c/a);
6645		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
6646		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
6647	},
6648	easeInBack: function (x, t, b, c, d, s) {
6649		if (s == undefined) s = 1.70158;
6650		return c*(t/=d)*t*((s+1)*t - s) + b;
6651	},
6652	easeOutBack: function (x, t, b, c, d, s) {
6653		if (s == undefined) s = 1.70158;
6654		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
6655	},
6656	easeInOutBack: function (x, t, b, c, d, s) {
6657		if (s == undefined) s = 1.70158; 
6658		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
6659		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
6660	},
6661	easeInBounce: function (x, t, b, c, d) {
6662		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
6663	},
6664	easeOutBounce: function (x, t, b, c, d) {
6665		if ((t/=d) < (1/2.75)) {
6666			return c*(7.5625*t*t) + b;
6667		} else if (t < (2/2.75)) {
6668			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
6669		} else if (t < (2.5/2.75)) {
6670			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
6671		} else {
6672			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
6673		}
6674	},
6675	easeInOutBounce: function (x, t, b, c, d) {
6676		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
6677		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
6678	}
6679});
6680
6681/*
6682 *
6683 * TERMS OF USE - EASING EQUATIONS
6684 * 
6685 * Open source under the BSD License. 
6686 * 
6687 * Copyright © 2001 Robert Penner
6688 * All rights reserved.
6689 * 
6690 * Redistribution and use in source and binary forms, with or without modification, 
6691 * are permitted provided that the following conditions are met:
6692 * 
6693 * Redistributions of source code must retain the above copyright notice, this list of 
6694 * conditions and the following disclaimer.
6695 * Redistributions in binary form must reproduce the above copyright notice, this list 
6696 * of conditions and the following disclaimer in the documentation and/or other materials 
6697 * provided with the distribution.
6698 * 
6699 * Neither the name of the author nor the names of contributors may be used to endorse 
6700 * or promote products derived from this software without specific prior written permission.
6701 * 
6702 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
6703 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
6704 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
6705 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
6706 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
6707 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
6708 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6709 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
6710 * OF THE POSSIBILITY OF SUCH DAMAGE. 
6711 *
6712 */
6713
6714(function($, window, undefined) {
6715    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
6716    // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
6717 
6718    // requestAnimationFrame polyfill by Erik Möller
6719    // fixes from Paul Irish and Tino Zijdel
6720 
6721    var lastTime = 0,
6722        running,
6723        animate = function (elem) {
6724            if (running) {
6725                window.requestAnimationFrame(animate, elem);
6726                jQuery.fx.tick();
6727            }
6728        },
6729        vendors = ['ms', 'moz', 'webkit', 'o'];
6730 
6731    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
6732        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
6733        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
6734            || window[vendors[x]+'CancelRequestAnimationFrame'];
6735    }
6736 
6737    if (!window.requestAnimationFrame)
6738        window.requestAnimationFrame = function(fn, element) {
6739            var currTime = new Date().getTime(),
6740                delta = currTime - lastTime,
6741                timeToCall = Math.max(0, 16 - delta);
6742 
6743            var id = window.setTimeout(function() {
6744                    fn(currTime + timeToCall);
6745                },
6746                timeToCall
6747            );
6748 
6749            lastTime = currTime + timeToCall;
6750 
6751            return id;
6752        };
6753 
6754    if (!window.cancelAnimationFrame) {
6755        window.cancelAnimationFrame = function(id) {
6756            clearTimeout(id);
6757        };
6758    }
6759 
6760    jQuery.fx.timer = function (timer) {
6761        if (timer() && jQuery.timers.push(timer) && !running) {
6762            running = true;
6763            animate(timer.elem);
6764        }
6765    };
6766 
6767    jQuery.fx.stop = function() {
6768        running = false;
6769    };
6770 
6771}(jQuery, this));
6772
6773/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
6774 * Licensed under the MIT License (LICENSE.txt).
6775 *
6776 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
6777 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
6778 * Thanks to: Seamus Leahy for adding deltaX and deltaY
6779 *
6780 * Version: 3.0.6
6781 *
6782 * Requires: 1.2.2+
6783 */
6784(function($) {
6785    var types = ['DOMMouseScroll', 'mousewheel'];
6786    if ($.event.fixHooks) {
6787        for (var i = types.length; i;) {
6788            $.event.fixHooks[types[--i]] = $.event.mouseHooks;
6789        }
6790    }
6791    $.event.special.mousewheel = {
6792        setup: function() {
6793            if (this.addEventListener) {
6794                for (var i = types.length; i;) {
6795                    this.addEventListener(types[--i], handler, false);
6796                }
6797            } else {
6798                this.onmousewheel = handler;
6799            }
6800        },
6801        teardown: function() {
6802            if (this.removeEventListener) {
6803                for (var i = types.length; i;) {
6804                    this.removeEventListener(types[--i], handler, false);
6805                }
6806            } else {
6807                this.onmousewheel = null;
6808            }
6809        }
6810    };
6811    $.fn.extend({
6812        mousewheel: function(fn) {
6813            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
6814        },
6815        unmousewheel: function(fn) {
6816            return this.unbind("mousewheel", fn);
6817        }
6818    });
6819
6820    function handler(event) {
6821        var orgEvent = event || window.event,
6822            args = [].slice.call(arguments, 1),
6823            delta = 0,
6824            returnValue = true,
6825            deltaX = 0,
6826            deltaY = 0;
6827        event = $.event.fix(orgEvent);
6828        event.type = "mousewheel";
6829        // Old school scrollwheel delta
6830        if (orgEvent.wheelDelta) {
6831            delta = orgEvent.wheelDelta / 120;
6832        }
6833        if (orgEvent.detail) {
6834            delta = -orgEvent.detail / 3;
6835        }
6836        // New school multidimensional scroll (touchpads) deltas
6837        deltaY = delta;
6838        // Gecko
6839        if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
6840            deltaY = 0;
6841            deltaX = -1 * delta;
6842        }
6843        // Webkit
6844        if (orgEvent.wheelDeltaY !== undefined) {
6845            deltaY = orgEvent.wheelDeltaY / 120;
6846        }
6847        if (orgEvent.wheelDeltaX !== undefined) {
6848            deltaX = -1 * orgEvent.wheelDeltaX / 120;
6849        }
6850        // Add event and delta to the front of the arguments
6851        args.unshift(event, delta, deltaX, deltaY);
6852        return ($.event.dispatch || $.event.handle).apply(this, args);
6853    }
6854})(jQuery);
6855
6856/**
6857 * jQuery iLightBox - Revolutionary Lightbox Plugin
6858 * http://www.ilightbox.net/
6859 *
6860 * @version: 2.2.4 - October 14, 2017
6861 *
6862 * @author: iProDev (Hemn Chawroka)
6863 *          http://www.iprodev.com/
6864 *
6865 */
6866(function($, window, undefined) {
6867
6868	var extensions = {
6869			flash: ['swf'],
6870			image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'],
6871			iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'],
6872			video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v']
6873		},
6874
6875		// Global DOM elements
6876		$win = $(window),
6877		$doc = $(document),
6878
6879		// Support indicators
6880		browser,
6881		transform,
6882		gpuAcceleration,
6883		fullScreenApi = '',
6884		userAgent = navigator.userAgent || navigator.vendor || window.opera,
6885		supportTouch = !!('ontouchstart' in window) && (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)),
6886		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 )|sy(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)),
6887
6888		// Events
6889		clickEvent = supportTouch ? "itap.iLightBox" : "click.iLightBox",
6890		touchStartEvent = supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox",
6891		touchStopEvent = supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox",
6892		touchMoveEvent = supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox",
6893
6894		// Math shorthands
6895		abs = Math.abs,
6896		sqrt = Math.sqrt,
6897		round = Math.round,
6898		max = Math.max,
6899		min = Math.min,
6900		floor = Math.floor,
6901		random = Math.random,
6902
6903		pluginspages = {
6904			quicktime: 'http://www.apple.com/quicktime/download',
6905			flash: 'http://www.adobe.com/go/getflash'
6906		},
6907
6908		iLightBox = function(el, options, items, instant) {
6909			var iL = this;
6910
6911			iL.options = options,
6912				iL.selector = el.selector || el,
6913				iL.context = el.context,
6914				iL.instant = instant;
6915
6916			if (items.length < 1) iL.attachItems();
6917			else iL.items = items;
6918
6919			iL.vars = {
6920				total: iL.items.length,
6921				start: 0,
6922				current: null,
6923				next: null,
6924				prev: null,
6925				BODY: $('body'),
6926				loadRequests: 0,
6927				overlay: $('<div class="ilightbox-overlay"></div>'),
6928				loader: $('<div class="ilightbox-loader"><div></div></div>'),
6929				toolbar: $('<div class="ilightbox-toolbar"></div>'),
6930				innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'),
6931				title: $('<div class="ilightbox-title"></div>'),
6932				closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'),
6933				fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'),
6934				innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'),
6935				innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'),
6936				innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'),
6937				holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6938				nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6939				prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6940				nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'),
6941				prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
6942				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>'),
6943				thumbs: false,
6944				nextLock: false,
6945				prevLock: false,
6946				hashLock: false,
6947				isMobile: false,
6948				mobileMaxWidth: 980,
6949				isInFullScreen: false,
6950				isSwipe: false,
6951				mouseID: 0,
6952				cycleID: 0,
6953				isPaused: 0,
6954				captionHeight: 39,
6955			};
6956
6957			// Hideable elements with mousemove event
6958			iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton);
6959
6960			iL.normalizeItems();
6961
6962			//Check necessary plugins
6963			iL.availPlugins();
6964
6965			//Set startFrom
6966			iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom;
6967
6968			//If randomStart
6969			iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom;
6970			iL.vars.start = iL.options.startFrom;
6971
6972			if (instant) iL.instantCall();
6973			else iL.patchItemsEvents();
6974
6975			if (iL.options.linkId) {
6976				iL.hashChangeHandler();
6977				$win.iLightBoxHashChange(function() {
6978					iL.hashChangeHandler();
6979				});
6980			}
6981
6982			if (supportTouch) {
6983				var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig,
6984					replace = "itap";
6985				iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace),
6986					iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace),
6987					iL.options.social.show = iL.options.social.show.replace(RegExp, replace),
6988					iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace);
6989			}
6990
6991			if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) {
6992				$.extend(iL.options.styles, {
6993					nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
6994					prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
6995					nextOpacity: 0,
6996					prevOpacity: 0
6997				});
6998			}
6999		};
7000
7001	//iLightBox helpers
7002	iLightBox.prototype = {
7003		showLoader: function() {
7004			var iL = this;
7005			iL.vars.loadRequests += 1;
7006			if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({
7007				//top: '-30px'
7008				opacity: '1'
7009			}, iL.options.show.speed, 'easeOutCirc');
7010			else iL.vars.loader.addClass('ilightbox-show').stop().animate({
7011				//left: '-30px'
7012				opacity: '1'
7013			}, iL.options.show.speed, 'easeOutCirc');
7014		},
7015
7016		hideLoader: function() {
7017			var iL = this;
7018			iL.vars.loadRequests -= 1;
7019			iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests;
7020			if (iL.options.path.toLowerCase() == "horizontal") {
7021				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
7022					//top: '-192px'
7023					opacity: '0'
7024				}, iL.options.show.speed, 'easeInCirc');
7025			} else {
7026				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
7027					//left: '-192px'
7028					opacity: '0'
7029				}, iL.options.show.speed, 'easeInCirc');
7030			}
7031		},
7032
7033		createUI: function() {
7034			var iL = this;
7035
7036			iL.ui = {
7037				currentElement: iL.vars.holder,
7038				nextElement: iL.vars.nextPhoto,
7039				prevElement: iL.vars.prevPhoto,
7040				currentItem: iL.vars.current,
7041				nextItem: iL.vars.next,
7042				prevItem: iL.vars.prev,
7043				hide: function() {
7044					iL.closeAction();
7045				},
7046				refresh: function() {
7047					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
7048				},
7049				fullscreen: function() {
7050					iL.fullScreenAction();
7051				}
7052			};
7053		},
7054
7055		attachItems: function() {
7056			var iL = this,
7057				itemsObject = new Array(),
7058				items = new Array();
7059
7060			$(iL.selector, iL.context).each(function() {
7061				var t = $(this),
7062					URL = t.attr(iL.options.attr) || null,
7063					options = t.data("options") && eval("({" + t.data("options") + "})") || {},
7064					caption = t.data('caption'),
7065					title = t.data('title'),
7066					type = t.data('type') || getTypeByExtension(URL),
7067					clone = t.data('lbox-clone') || false;
7068
7069				if (t.data('lbox-clone') != undefined) return;
7070
7071				//Uncode addition ##START##
7072				if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) {
7073					var ALBUM_URLS = JSON.parse(t.attr('data-album')),
7074						URL_i,
7075						URLS_LENGHT = ALBUM_URLS.length;
7076					for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) {
7077						if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) {
7078							var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\'';
7079							item_opts = item_opts && eval("({" + item_opts + "})") || {},
7080							items.push({
7081								URL: ALBUM_URLS[URL_i].url,
7082								caption: ALBUM_URLS[URL_i].caption,
7083								title: ALBUM_URLS[URL_i].title,
7084								type: getTypeByExtension(ALBUM_URLS[URL_i].url),
7085								options: item_opts,
7086								clone: clone
7087							});
7088							var newT = t;
7089							newT.attr('href',ALBUM_URLS[URL_i].url);
7090							if (!iL.instant) itemsObject.push(newT);
7091						}
7092					}
7093				} else {
7094				//Uncode addition ##END##
7095					items.push({
7096						URL: URL,
7097						caption: caption,
7098						title: title,
7099						type: type,
7100						options: options,
7101						clone: clone
7102					});
7103				}
7104
7105
7106				if (iL.vars != undefined) iL.vars.total = items.length;
7107
7108				if (!iL.instant) itemsObject.push(t);
7109			});
7110
7111			iL.items = items,
7112				iL.itemsObject = itemsObject;
7113
7114		},
7115
7116		normalizeItems: function() {
7117			var iL = this,
7118				newItems = new Array();
7119
7120			$.each(iL.items, function(key, val) {
7121
7122				if (typeof val == "string") val = {
7123					url: val
7124				};
7125
7126				var URL = val.url || val.URL || null,
7127					options = val.options || {},
7128					caption = val.caption || null,
7129					title = val.title || null,
7130					type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL),
7131					ext = (typeof URL != 'object') ? getExtension(URL) : '';
7132
7133				options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
7134				options.videoType = options.videoType || null,
7135				options.skin = options.skin || iL.options.skin,
7136				options.width = options.width || null,
7137				options.height = options.height || null,
7138				options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true,
7139				options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true,
7140				options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons);
7141
7142				if (type == "video") {
7143					options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {};
7144
7145					options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null;
7146					options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls";
7147					options.html5video.preload = options.html5video.preload || "metadata";
7148					options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false;
7149				}
7150
7151				if (!options.width || !options.height) {
7152					if (type == "video") options.width = 1280, options.height = 720;
7153					else if (type == "iframe") options.width = '100%', options.height = '90%';
7154					else if (type == "flash") options.width = 1280, options.height = 720;
7155				}
7156
7157				delete val.url;
7158				val.index = key;
7159				val.URL = URL;
7160				val.caption = caption;
7161				val.title = title;
7162				val.type = type;
7163				val.options = options;
7164				val.ext = ext;
7165
7166				newItems.push(val);
7167			});
7168
7169			iL.items = newItems;
7170		},
7171
7172		instantCall: function() {
7173			var iL = this,
7174				key = iL.vars.start;
7175
7176			iL.vars.current = key;
7177			iL.vars.next = (iL.items[key + 1]) ? key + 1 : null;
7178			iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null;
7179
7180			iL.addContents();
7181			iL.patchEvents();
7182		},
7183
7184		addContents: function() {
7185			var iL = this,
7186				vars = iL.vars,
7187				opts = iL.options,
7188				viewport = getViewport(),
7189				path = opts.path.toLowerCase(),
7190				recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) {
7191					return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition);
7192				}),
7193				needRecognition = recognizingItems.length > 0;
7194
7195			if (opts.mobileOptimizer && !opts.innerToolbar)
7196				vars.isMobile = viewport.width <= vars.mobileMaxWidth;
7197
7198			vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity);
7199
7200			if (opts.linkId)
7201				vars.overlay[0].setAttribute('linkid', opts.linkId);
7202
7203			//Add Toolbar Buttons
7204			if (opts.controls.toolbar) {
7205				vars.toolbar.addClass(opts.skin).append(vars.closeButton);
7206				if (opts.controls.fullscreen)
7207					vars.toolbar.append(vars.fullScreenButton);
7208				if (opts.controls.slideshow)
7209					vars.toolbar.append(vars.innerPlayButton);
7210				if (vars.total > 1)
7211					vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton);
7212			}
7213
7214			//Append elements to body
7215			vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto);
7216
7217			if (!opts.innerToolbar)
7218				vars.BODY.append(vars.toolbar);
7219			if (opts.controls.arrows)
7220				vars.BODY.append(vars.nextButton).append(vars.prevButton);
7221
7222			if (opts.controls.thumbnail && vars.total > 1) {
7223				vars.BODY.append(vars.thumbnails);
7224				vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path);
7225				$('div.ilightbox-thumbnails-grid', vars.thumbnails).empty();
7226				vars.thumbs = true;
7227			}
7228
7229			//Configure loader and arrows
7230			var loaderCss = (opts.path.toLowerCase() == "horizontal") ? {
7231				left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2))
7232			} : {
7233				top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2))
7234			};
7235			vars.loader.addClass(opts.skin).css(loaderCss);
7236			vars.nextButton.add(vars.prevButton).addClass(opts.skin);
7237			if (path == "horizontal")
7238				vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal');
7239
7240			// Configure arrow buttons
7241			vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
7242
7243			if (!opts.infinite) {
7244				vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
7245
7246				if (vars.current == 0)
7247					vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
7248				if (vars.current >= vars.total - 1)
7249					vars.nextButton.add(vars.innerNextButton).addClass('disabled');
7250			}
7251
7252			if (opts.show.effect) {
7253				vars.overlay.stop().fadeIn(opts.show.speed);
7254				vars.toolbar.stop().fadeIn(opts.show.speed);
7255			} else {
7256				vars.overlay.show();
7257				vars.toolbar.show();
7258			}
7259
7260			var length = recognizingItems.length;
7261			if (needRecognition) {
7262				iL.showLoader();
7263
7264				$.each(recognizingItems, function(key, val) {
7265					var resultFnc = function(result) {
7266							var key = -1,
7267								filter = iL.items.filter(function(e, i, arr) {
7268									if (e.URL == result.url)
7269										key = i;
7270
7271									return e.URL == result.url;
7272								}),
7273								self = iL.items[key];
7274
7275							if (result)
7276								$.extend(true, self, {
7277									URL: result.source,
7278									type: result.type,
7279									recognized: true,
7280									options: {
7281										html5video: result.html5video,
7282										width: (result.type == "image") ? 0 : (result.width || self.width),
7283										height: (result.type == "image") ? 0 : (result.height || self.height),
7284										thumbnail: self.options.thumbnail || result.thumbnail
7285									}
7286								});
7287
7288							length--;
7289
7290							if (length == 0) {
7291								iL.hideLoader();
7292
7293								vars.dontGenerateThumbs = false;
7294								iL.generateThumbnails();
7295
7296								if (opts.show.effect)
7297									setTimeout(function() {
7298										iL.generateBoxes();
7299									}, opts.show.speed);
7300								else
7301									iL.generateBoxes();
7302							}
7303						};
7304
7305					iL.ogpRecognition(this, resultFnc);
7306				});
7307			}
7308			else {
7309				if (opts.show.effect)
7310					setTimeout(function() {
7311						iL.generateBoxes();
7312					}, opts.show.speed);
7313				else
7314					iL.generateBoxes();
7315			}
7316
7317			iL.createUI();
7318
7319			window.iLightBox = {
7320				close: function() {
7321					iL.closeAction();
7322				},
7323				fullscreen: function() {
7324					iL.fullScreenAction();
7325				},
7326				moveNext: function() {
7327					iL.moveTo('next');
7328				},
7329				movePrev: function() {
7330					iL.moveTo('prev');
7331				},
7332				goTo: function(index) {
7333					iL.goTo(index);
7334				},
7335				refresh: function() {
7336					iL.refresh();
7337				},
7338				reposition: function() {
7339					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
7340				},
7341				setOption: function(options) {
7342					iL.setOption(options);
7343				},
7344				destroy: function() {
7345					iL.closeAction();
7346					iL.dispatchItemsEvents();
7347				}
7348			};
7349
7350			if (opts.linkId) {
7351				vars.hashLock = true;
7352				window.location.hash = opts.linkId + '/' + vars.current;
7353				setTimeout(function() {
7354					vars.hashLock = false;
7355				}, 55);
7356			}
7357
7358			if (!opts.slideshow.startPaused) {
7359				iL.resume();
7360				vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause');
7361			}
7362
7363			//Trigger the onOpen callback
7364			if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL);
7365		},
7366
7367		loadContent: function(obj, opt, speed) {
7368			var iL = this,
7369				holder, item;
7370
7371			iL.createUI();
7372
7373			obj.speed = speed || iL.options.effects.loadedFadeSpeed;
7374
7375			if (opt == 'current') {
7376				if (!obj.options.mousewheel) iL.vars.lockWheel = true;
7377				else iL.vars.lockWheel = false;
7378
7379				if (!obj.options.swipe) iL.vars.lockSwipe = true;
7380				else iL.vars.lockSwipe = false;
7381			}
7382
7383			switch (opt) {
7384				case 'current':
7385					holder = iL.vars.holder, item = iL.vars.current;
7386					break;
7387				case 'next':
7388					holder = iL.vars.nextPhoto, item = iL.vars.next;
7389					break;
7390				case 'prev':
7391					holder = iL.vars.prevPhoto, item = iL.vars.prev;
7392					break;
7393			}
7394
7395			holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin);
7396			$('div.ilightbox-inner-toolbar', holder).remove();
7397
7398			if (obj.title || iL.options.innerToolbar) {
7399				var innerToolbar = iL.vars.innerToolbar.clone();
7400				if (obj.title && iL.options.show.title) {
7401					var title = iL.vars.title.clone();
7402					title.empty().html(obj.title);
7403					innerToolbar.append(title);
7404				}
7405				if (iL.options.innerToolbar) {
7406					innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar);
7407				}
7408				holder.prepend(innerToolbar);
7409			}
7410
7411			//console.warn('loadContent', arguments);
7412
7413			iL.loadSwitcher(obj, holder, item, opt);
7414		},
7415
7416		loadSwitcher: function(obj, holder, item, opt) {
7417			var iL = this,
7418				opts = iL.options,
7419				api = {
7420					element: holder,
7421					position: item
7422				};
7423
7424			switch (obj.type) {
7425				case 'image':
7426					//Trigger the onBeforeLoad callback
7427					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7428					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7429
7430					iL.loadImage(obj.URL, function(img) {
7431						//Trigger the onAfterLoad callback
7432						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7433						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7434
7435						var width = (img) ? img.width : 400,
7436							height = (img) ? img.height : 200;
7437
7438						holder.data({
7439							naturalWidth: width,
7440							naturalHeight: height
7441						});
7442						$('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>');
7443
7444						//Trigger the onRender callback
7445						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7446						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7447
7448						iL.configureHolder(obj, opt, holder);
7449					});
7450
7451					break;
7452
7453				case 'video':
7454					holder.data({
7455						naturalWidth: obj.options.width,
7456						naturalHeight: obj.options.height
7457					});
7458
7459					if (opt === 'current') {
7460						iL.addContent(holder, obj);
7461
7462						//Trigger the onRender callback
7463						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7464						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7465					} else {
7466						$('div.ilightbox-container', holder).empty();
7467					}
7468
7469					iL.configureHolder(obj, opt, holder);
7470
7471					break;
7472
7473				case 'iframe':
7474					//iL.showLoader();
7475					holder.data({
7476						naturalWidth: obj.options.width,
7477						naturalHeight: obj.options.height
7478					});
7479
7480					iL.configureHolder(obj, opt, holder);
7481
7482					if (opt === 'current') {
7483						var el = iL.addContent(holder, obj);
7484
7485						//Trigger the onRender callback
7486						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7487						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7488
7489						//Trigger the onBeforeLoad callback
7490						if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7491						if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7492
7493						el.bind('load', function() {
7494							//Trigger the onAfterLoad callback
7495							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7496							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7497
7498							//iL.hideLoader();
7499							el.unbind('load');
7500						});
7501					} else {
7502						$('div.ilightbox-container', holder).empty();
7503					}
7504
7505					break;
7506
7507				case 'inline':
7508					var el = $(obj.URL),
7509						content = iL.addContent(holder, obj),
7510						images = findImageInElement(holder);
7511
7512					holder.data({
7513						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
7514						naturalHeight: (iL.items[item].options.height || el.outerHeight())
7515					});
7516					content.children().eq(0).show();
7517
7518					//Trigger the onRender callback
7519					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7520					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7521
7522					//Trigger the onBeforeLoad callback
7523					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7524					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7525
7526					iL.loadImage(images, function() {
7527						//Trigger the onAfterLoad callback
7528						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7529						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7530
7531						iL.configureHolder(obj, opt, holder);
7532					});
7533
7534					break;
7535
7536				case 'flash':
7537					var el = iL.addContent(holder, obj);
7538
7539					holder.data({
7540						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
7541						naturalHeight: (iL.items[item].options.height || el.outerHeight())
7542					});
7543
7544					//Trigger the onRender callback
7545					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7546					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7547
7548					iL.configureHolder(obj, opt, holder);
7549
7550					break;
7551
7552				case 'ajax':
7553					var ajax = obj.options.ajax || {};
7554					//Trigger the onBeforeLoad callback
7555					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7556					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7557
7558					iL.showLoader();
7559					$.ajax({
7560						url: obj.URL || opts.ajaxSetup.url,
7561						data: ajax.data || null,
7562						dataType: ajax.dataType || "html",
7563						type: ajax.type || opts.ajaxSetup.type,
7564						cache: ajax.cache || opts.ajaxSetup.cache,
7565						crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain,
7566						global: ajax.global || opts.ajaxSetup.global,
7567						ifModified: ajax.ifModified || opts.ajaxSetup.ifModified,
7568						username: ajax.username || opts.ajaxSetup.username,
7569						password: ajax.password || opts.ajaxSetup.password,
7570						beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend,
7571						complete: ajax.complete || opts.ajaxSetup.complete,
7572						success: function(data, textStatus, jqXHR) {
7573							iL.hideLoader();
7574
7575							var el = $(data),
7576								container = $('div.ilightbox-container', holder),
7577								elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')),
7578								elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')),
7579								css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? {
7580									'overflow': 'hidden'
7581								} : {};
7582
7583							container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el));
7584							holder.show().data({
7585								naturalWidth: (elWidth || container.outerWidth()),
7586								naturalHeight: (elHeight || container.outerHeight())
7587							}).hide();
7588
7589							//Trigger the onRender callback
7590							if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7591							if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7592
7593							var images = findImageInElement(holder);
7594							iL.loadImage(images, function() {
7595								//Trigger the onAfterLoad callback
7596								if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7597								if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7598
7599								iL.configureHolder(obj, opt, holder);
7600							});
7601
7602							opts.ajaxSetup.success(data, textStatus, jqXHR);
7603							if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR);
7604						},
7605						error: function(jqXHR, textStatus, errorThrown) {
7606							//Trigger the onAfterLoad callback
7607							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7608							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7609
7610							iL.hideLoader();
7611							$('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>');
7612							iL.configureHolder(obj, opt, holder);
7613
7614							opts.ajaxSetup.error(jqXHR, textStatus, errorThrown);
7615							if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown);
7616						}
7617					});
7618
7619					break;
7620
7621				case 'html':
7622					var object = obj.URL,
7623						el
7624					container = $('div.ilightbox-container', holder);
7625
7626					if (object[0].nodeName) el = object.clone();
7627					else {
7628						var dom = $(object);
7629						if (dom.selector) el = $('<div>' + dom + '</div>');
7630						else el = dom;
7631					}
7632
7633					var elWidth = iL.items[item].options.width || parseInt(el.attr('width')),
7634						elHeight = iL.items[item].options.height || parseInt(el.attr('height'));
7635
7636					iL.addContent(holder, obj);
7637
7638					el.appendTo(document.documentElement).hide();
7639
7640					//Trigger the onRender callback
7641					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7642					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7643
7644					var images = findImageInElement(holder);
7645
7646					//Trigger the onBeforeLoad callback
7647					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7648					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7649
7650					iL.loadImage(images, function() {
7651						//Trigger the onAfterLoad callback
7652						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7653						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7654
7655						holder.show().data({
7656							naturalWidth: (elWidth || container.outerWidth()),
7657							naturalHeight: (elHeight || container.outerHeight())
7658						}).hide();
7659						el.remove();
7660
7661						iL.configureHolder(obj, opt, holder);
7662					});
7663
7664					break;
7665			}
7666		},
7667
7668		configureHolder: function(obj, opt, holder) {
7669			var iL = this,
7670				vars = iL.vars,
7671				opts = iL.options;
7672
7673			if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev');
7674
7675			if (opt == "current")
7676				var item = vars.current;
7677			else if (opt == "next")
7678				var opacity = opts.styles.nextOpacity,
7679					item = vars.next;
7680			else
7681				var opacity = opts.styles.prevOpacity,
7682					item = vars.prev;
7683
7684			var api = {
7685				element: holder,
7686				position: item
7687			};
7688
7689			iL.items[item].options.width = iL.items[item].options.width || 0,
7690			iL.items[item].options.height = iL.items[item].options.height || 0;
7691
7692			if (opt == "current") {
7693				if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() {
7694					holder.css(transform, '');
7695					if (obj.caption) {
7696						iL.setCaption(obj, holder);
7697						var caption = $('div.ilightbox-caption', holder),
7698							percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100);
7699						if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
7699Speed);
7700					}
7701
7702					var social = obj.options.social;
7703					if (social) {
7704						iL.setSocial(social, obj.URL, holder);
7705						if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed);
7706					}
7707
7708					//Generate thumbnails
7709					iL.generateThumbnails();
7710
7711					//Trigger the onShow callback
7712					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7713					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7714				});
7715				else {
7716					holder.show();
7717
7718					//Generate thumbnails
7719					iL.generateThumbnails();
7720
7721					//Trigger the onShow callback
7722					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7723					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7724				}
7725			} else {
7726				if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() {
7727					if (opt == "next") vars.nextLock = false;
7728					else vars.prevLock = false;
7729
7730					//Generate thumbnails
7731					iL.generateThumbnails();
7732
7733					//Trigger the onShow callback
7734					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7735					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7736				});
7737				else {
7738					holder.css({
7739						opacity: opacity
7740					}).show();
7741					if (opt == "next") vars.nextLock = false;
7742					else vars.prevLock = false;
7743
7744					//Generate thumbnails
7745					iL.generateThumbnails();
7746
7747					//Trigger the onShow callback
7748					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7749					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7750				}
7751			}
7752
7753			setTimeout(function() {
7754				iL.repositionPhoto();
7755			}, 0);
7756		},
7757
7758		generateBoxes: function() {
7759			var iL = this,
7760				vars = iL.vars,
7761				opts = iL.options;
7762
7763			if (opts.infinite && vars.total >= 3) {
7764				if (vars.current == vars.total - 1) vars.next = 0;
7765				if (vars.current == 0) vars.prev = vars.total - 1;
7766			} else opts.infinite = false;
7767
7768			//UNCODE addition		
7769			if ( typeof iL.items[vars.current] == 'undefined' )
7770				vars.current = 0;
7771
7772			iL.loadContent(iL.items[vars.current], 'current', opts.show.speed);
7773
7774			if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed);
7775			if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed);
7776		},
7777
7778		generateThumbnails: function() {
7779			var iL = this,
7780				vars = iL.vars,
7781				opts = iL.options,
7782				timeOut = null;
7783
7784			if (vars.thumbs && !iL.vars.dontGenerateThumbs) {
7785				var thumbnails = vars.thumbnails,
7786					container = $('div.ilightbox-thumbnails-container', thumbnails),
7787					grid = $('div.ilightbox-thumbnails-grid', container),
7788					i = 0;
7789
7790				grid.removeAttr('style').empty();
7791
7792				$.each(iL.items, function(key, val) {
7793					var isActive = (vars.current == key) ? 'ilightbox-active' : '',
7794						opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity,
7795						thumb = val.options.thumbnail,
7796						thumbnail = $('<div class="ilightbox-thumbnail"></div>'),
7797						icon = $('<div class="ilightbox-thumbnail-icon"></div>');
7798
7799					thumbnail.css({
7800						opacity: 0
7801					}).addClass(isActive);
7802
7803					if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') {
7804						icon.addClass('ilightbox-thumbnail-video');
7805						thumbnail.append(icon);
7806					} else if (val.options.icon) {
7807						icon.addClass('ilightbox-thumbnail-' + val.options.icon);
7808						thumbnail.append(icon);
7809					}
7810
7811					if (thumb) iL.loadImage(thumb, function(img) {
7812						i++;
7813						if (img) thumbnail.data({
7814							naturalWidth: img.width,
7815							naturalHeight: img.height
7816						}).append('<img src="' + thumb + '" border="0" />');
7817						else thumbnail.data({
7818							naturalWidth: opts.thumbnails.maxWidth,
7819							naturalHeight: opts.thumbnails.maxHeight
7820						});
7821
7822						clearTimeout(timeOut);
7823						timeOut = setTimeout(function() {
7824							iL.positionThumbnails(thumbnails, container, grid);
7825						}, 20);
7826						setTimeout(function() {
7827							thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity);
7828						}, i * 20);
7829					});
7830
7831					grid.append(thumbnail);
7832				});
7833				iL.vars.dontGenerateThumbs = true;
7834			}
7835		},
7836
7837		positionThumbnails: function(thumbnails, container, grid) {
7838			var iL = this,
7839				vars = iL.vars,
7840				opts = iL.options,
7841				viewport = getViewport(),
7842				path = opts.path.toLowerCase();
7843
7844			if (!thumbnails) thumbnails = vars.thumbnails;
7845			if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails);
7846			if (!grid) grid = $('div.ilightbox-thumbnails-grid', container);
7847
7848			var thumbs = $('.ilightbox-thumbnail', grid),
7849				widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX,
7850				heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY,
7851				gridWidth = (path == 'horizontal') ? 0 : widthAvail,
7852				gridHeight = (path == 'horizontal') ? heightAvail : 0,
7853				active = $('.ilightbox-active', grid),
7854				gridCss = {},
7855				css = {};
7856
7857			if (arguments.length < 3) {
7858				thumbs.css({
7859					opacity: opts.thumbnails.normalOpacity
7860				});
7861				active.css({
7862					opacity: opts.thumbnails.activeOpacity
7863				});
7864			}
7865
7866			thumbs.each(function(i) {
7867				var t = $(this),
7868					data = t.data(),
7869					width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth;
7870				height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0;
7871				dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true);
7872
7873				t.css({
7874					width: dims.width,
7875					height: dims.height
7876				});
7877				if (path == 'horizontal') t.css({
7878					'float': 'left'
7879				});
7880
7881				(path == 'horizontal') ? (
7882					gridWidth += t.outerWidth()
7883				) : (
7884					gridHeight += t.outerHeight()
7885				);
7886			});
7887
7888			gridCss = {
7889				width: gridWidth,
7890				height: gridHeight
7891			};
7892
7893			grid.css(gridCss);
7894
7895			gridCss = {};
7896
7897			var gridOffset = grid.offset(),
7898				activeOffset = (active.length) ? active.offset() : {
7899					top: parseInt(heightAvail / 2),
7900					left: parseInt(widthAvail / 2)
7901				};
7902
7903			gridOffset.top = (gridOffset.top - $doc.scrollTop()),
7904				gridOffset.left = (gridOffset.left - $doc.scrollLeft()),
7905				activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()),
7906				activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft());
7907
7908			(path == 'horizontal') ? (
7909				gridCss.top = 0,
7910				gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2))
7911			) : (
7912				gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))),
7913				gridCss.left = 0
7914			);
7915
7916			if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc');
7917			else grid.css(gridCss);
7918		},
7919
7920		loadImage: function(image, callback) {
7921			if (!$.isArray(image)) image = [image];
7922
7923			var iL = this,
7924				length = image.length;
7925
7926			if (length > 0) {
7927				iL.showLoader();
7928				$.each(image, function(index, value) {
7929					var img = new Image();
7930					img.onload = function() {
7931						length -= 1;
7932						if (length == 0) {
7933							iL.hideLoader();
7934							callback(img);
7935						}
7936					};
7937					img.onerror = img.onabort = function() {
7938						length -= 1;
7939						if (length == 0) {
7940							iL.hideLoader();
7941							callback(false);
7942						}
7943					};
7944					img.src = image[index];
7945				});
7946			} else callback(false);
7947		},
7948
7949		patchItemsEvents: function() {
7950			var iL = this,
7951				vars = iL.vars,
7952				clickEvent = supportTouch ? "itap.iL" : "click.iL",
7953				vEvent = supportTouch ? "click.iL" : "itap.iL";
7954
7955			if (iL.context && iL.selector) {
7956				var $items = $(iL.selector, iL.context);
7957
7958				$(iL.context).on(clickEvent, iL.selector, function() {
7959					var $this = $(this),
7960						//UNCODE addition
7961						key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this);
7962					if (UNCODE.isMobile) {
7963						var isCarousel = $this.closest('.owl-carousel');
7964						if (isCarousel.length) {
7965							if (isCarousel.hasClass('owl-translating')) return false;
7966						}
7967					}
7968
7969					vars.current = key;
7970					vars.next = iL.items[key + 1] ? key + 1 : null;
7971					vars.prev = iL.items[key - 1] ? key - 1 : null;
7972
7973					iL.addContents();
7974					iL.patchEvents();
7975
7976					return false;
7977				}).on(vEvent, iL.selector, function() {
7978					return false;
7979				});
7980			} else
7981				$.each(iL.itemsObject, function(key, val) {
7982					val.on(clickEvent, function() {
7983						vars.current = key;
7984						vars.next = iL.items[key + 1] ? key + 1 : null;
7985						vars.prev = iL.items[key - 1] ? key - 1 : null;
7986
7987						iL.addContents();
7988						iL.patchEvents();
7989
7990						return false;
7991					}).on(vEvent, function() {
7992						return false;
7993					});
7994				});
7995		},
7996
7997		dispatchItemsEvents: function() {
7998			var iL = this,
7999				vars = iL.vars,
8000				opts = iL.options;
8001
8002			if (iL.context && iL.selector)
8003				$(iL.context).off('.iL', iL.selector);
8004			else
8005				$.each(iL.itemsObject, function(key, val) {
8006					val.off('.iL');
8007				});
8008		},
8009
8010		refresh: function() {
8011			var iL = this;
8012
8013			iL.dispatchItemsEvents();
8014			iL.attachItems();
8015			iL.normalizeItems();
8016			iL.patchItemsEvents();
8017		},
8018
8019		patchEvents: function() {
8020			var iL = this,
8021				vars = iL.vars,
8022				opts = iL.options,
8023				path = opts.path.toLowerCase(),
8024				holders = $('.ilightbox-holder'),
8025				fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox',
8026				durationThreshold = 1000,
8027				horizontalDistanceThreshold =
8028				verticalDistanceThreshold = 100,
8029				buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild];
8030
8031			$win.bind('resize.iLightBox', function() {
8032				var viewport = getViewport();
8033
8034				if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth;
8035				vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
8036
8037				iL.repositionPhoto(null);
8038				if (supportTouch) {
8039					clearTimeout(vars.setTime);
8040					vars.setTime = setTimeout(function() {
8041						var scrollTop = getScrollXY().y;
8042						window.scrollTo(0, scrollTop - 30);
8043						window.scrollTo(0, scrollTop + 30);
8044						window.scrollTo(0, scrollTop);
8045					}, 2000);
8046				}
8047				if (vars.thumbs) iL.positionThumbnails();
8048			}).bind('keydown.iLightBox', function(event) {
8049				if (opts.controls.keyboard) {
8050					switch (event.keyCode) {
8051						case 13:
8052							if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction();
8053							break;
8054						case 27:
8055							if (opts.keyboard.esc) iL.closeAction();
8056							break;
8057						case 37:
8058							if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev');
8059							break;
8060						case 38:
8061							if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev');
8062							break;
8063						case 39:
8064							if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next');
8065							break;
8066						case 40:
8067							if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next');
8068							break;
8069					}
8070				}
8071			});
8072
8073			if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() {
8074				iL.doFullscreen();
8075			});
8076
8077			var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) {
8078					return arr.lastIndexOf(e) === i;
8079				}),
8080				holderEvents = "";
8081
8082			$.each(holderEventsArr, function(key, val) {
8083				if (key != 0) holderEvents += ' ';
8084				holderEvents += val;
8085			});
8086
8087			$doc.on(clickEvent, '.ilightbox-overlay', function() {
8088				if (opts.overlay.blur) iL.closeAction();
8089			}).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() {
8090				iL.moveTo('next');
8091			}).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() {
8092				iL.moveTo('prev');
8093			}).on(clickEvent, '.ilightbox-thumbnail', function() {
8094				var t = $(this),
8095					thumbs = $('.ilightbox-thumbnail', vars.thumbnails),
8096					index = thumbs.index(t);
8097
8098				if (index != vars.current) iL.goTo(index);
8099			}).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
8100				var caption = $('div.ilightbox-caption', vars.holder),
8101					social = $('div.ilightbox-social', vars.holder),
8102					fadeSpeed = opts.effects.fadeSpeed;
8103
8104				if (vars.nextLock || vars.prevLock) {
8105					if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed);
8106					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed);
8107
8108					if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed);
8109					else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed);
8110				} else {
8111					if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed);
8112					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed);
8113
8114					if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed);
8115					else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed);
8116				}
8117			}).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) {
8118				if (e.type == 'mouseenter') vars.lockWheel = true;
8119				else vars.lockWheel = false;
8120			}).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() {
8121				var t = $(this);
8122
8123				if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction();
8124				else if (t.hasClass('ilightbox-play')) {
8125					iL.resume();
8126					t.addClass('ilightbox-pause').removeClass('ilightbox-play');
8127				} else if (t.hasClass('ilightbox-pause')) {
8128					iL.pause();
8129					t.addClass('ilightbox-play').removeClass('ilightbox-pause');
8130				} else iL.closeAction();
8131			}).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) {
8132				// prevent scrolling
8133				e.preventDefault();
8134			});
8135
8136			function mouseMoveHandler(e) {
8137				if (!vars.isMobile) {
8138					if (!vars.mouseID) {
8139						vars.hideableElements.show();
8140					}
8141
8142					vars.mouseID = clearTimeout(vars.mouseID);
8143
8144					if (buttonsArray.indexOf(e.target) === -1)
8145						vars.mouseID = setTimeout(function() {
8146							vars.hideableElements.hide();
8147							vars.mouseID = clearTimeout(vars.mouseID);
8148						}, 3000);
8149				}
8150			}
8151
8152			if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler);
8153
8154			if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
8155				if (e.type == 'mouseenter' && vars.cycleID) iL.pause();
8156				else if (e.type == 'mouseleave' && vars.isPaused) iL.resume();
8157			});
8158
8159			var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails');
8160
8161			if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) {
8162				if (!vars.lockWheel) {
8163					event.preventDefault();
8164					if (delta < 0) iL.moveTo('next');
8165					else if (delta > 0) iL.moveTo('prev');
8166				}
8167			});
8168
8169			if (opts.controls.swipe) holders.on(touchStartEvent, function(event) {
8170				if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return;
8171
8172				vars.BODY.addClass('ilightbox-closedhand');
8173
8174				var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event,
8175					scrollTop = $doc.scrollTop(),
8176					scrollLeft = $doc.scrollLeft(),
8177					offsets = [
8178						holders.eq(0).offset(),
8179						holders.eq(1).offset(),
8180						holders.eq(2).offset()
8181					],
8182					offSet = [{
8183						top: offsets[0].top - scrollTop,
8184						left: offsets[0].left - scrollLeft
8185					}, {
8186						top: offsets[1].top - scrollTop,
8187						left: offsets[1].left - scrollLeft
8188					}, {
8189						top: offsets[2].top - scrollTop,
8190						left: offsets[2].left - scrollLeft
8191					}],
8192					start = {
8193						time: (new Date()).getTime(),
8194						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
8195					},
8196					stop;
8197
8198				function moveEachHandler(i) {
8199					var t = $(this),
8200						offset = offSet[i],
8201						scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])];
8202
8203					t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px';
8204				}
8205
8206				function moveHandler(event) {
8207
8208					if (!start) return;
8209
8210					var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event;
8211
8212					stop = {
8213						time: (new Date()).getTime(),
8214						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
8215					};
8216
8217					holders.each(moveEachHandler);
8218
8219					// prevent scrolling
8220					event.preventDefault();
8221				}
8222
8223				function repositionHolders() {
8224					holders.each(function() {
8225						var t = $(this),
8226							offset = t.data('offset') || {
8227								top: t.offset().top - scrollTop,
8228								left: t.offset().left - scrollLeft
8229							},
8230							top = offset.top,
8231							left = offset.left;
8232
8233						t.css(transform, gpuAcceleration).stop().animate({
8234							top: top,
8235							left: left
8236						}, 500, 'easeOutCirc', function() {
8237							t.css(transform, '');
8238						});
8239					});
8240				}
8241
8242				holders.bind(touchMoveEvent, moveHandler);
8243				$doc.one(touchStopEvent, function(event) {
8244					holders.unbind(touchMoveEvent, moveHandler);
8245
8246					vars.BODY.removeClass('ilightbox-closedhand');
8247
8248					if (start && stop) {
8249						if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) {
8250							if (start.coords[0] > stop.coords[0]) {
8251								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
8252								else {
8253									vars.isSwipe = true;
8254									iL.moveTo('next');
8255								}
8256							} else {
8257								if (vars.current == 0 && !opts.infinite) repositionHolders();
8258								else {
8259									vars.isSwipe = true;
8260									iL.moveTo('prev');
8261								}
8262							}
8263						} 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) {
8264							if (start.coords[1] > stop.coords[1]) {
8265								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
8266								else {
8267									vars.isSwipe = true;
8268									iL.moveTo('next');
8269								}
8270							} else {
8271								if (vars.current == 0 && !opts.infinite) repositionHolders();
8272								else {
8273									vars.isSwipe = true;
8274									iL.moveTo('prev');
8275								}
8276							}
8277						} else repositionHolders();
8278					}
8279					start = stop = undefined;
8280				});
8281			});
8282
8283		},
8284
8285		goTo: function(index) {
8286			var iL = this,
8287				vars = iL.vars,
8288				opts = iL.options,
8289				diff = (index - vars.current);
8290
8291			if (opts.infinite) {
8292				if (index == vars.total - 1 && vars.current == 0) diff = -1;
8293				if (vars.current == vars.total - 1 && index == 0) diff = 1;
8294			}
8295
8296			if (diff == 1) iL.moveTo('next');
8297			else if (diff == -1) iL.moveTo('prev');
8298			else {
8299
8300				if (vars.nextLock || vars.prevLock) return false;
8301
8302				//Trigger the onBeforeChange callback
8303				if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui);
8304
8305				if (opts.linkId) {
8306					vars.hashLock = true;
8307					window.location.hash = opts.linkId + '/' + index;
8308				}
8309
8310				if (iL.items[index]) {
8311					if (!iL.items[index].options.mousewheel) vars.lockWheel = true;
8312					else iL.vars.lockWheel = false;
8313
8314					if (!iL.items[index].options.swipe) vars.lockSwipe = true;
8315					else vars.lockSwipe = false;
8316				}
8317
8318				$.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) {
8319					val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed);
8320				});
8321
8322				vars.current = index;
8323				vars.next = index + 1;
8324				vars.prev = index - 1;
8325
8326				iL.createUI();
8327
8328				setTimeout(function() {
8329					iL.generateBoxes();
8330				}, opts.effects.loadedFadeSpeed + 50);
8331
8332				$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active');
8333				iL.positionThumbnails();
8334
8335				if (opts.linkId) setTimeout(function() {
8336					vars.hashLock = false;
8337				}, 55);
8338
8339				// Configure arrow buttons
8340				if (!opts.infinite) {
8341					vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8342
8343					if (vars.current == 0) {
8344						vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8345					}
8346					if (vars.current >= vars.total - 1) {
8347						vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8348					}
8349				}
8350
8351				// Reset next cycle timeout
8352				iL.resetCycle();
8353
8354				//Trigger the onAfterChange callback
8355				if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui);
8356			}
8357		},
8358
8359		moveTo: function(side) {
8360			var iL = this,
8361				vars = iL.vars,
8362				opts = iL.options,
8363				path = opts.path.toLowerCase(),
8364				viewport = getViewport(),
8365				switchSpeed = opts.effects.switchSpeed;
8366
8367			if (vars.nextLock || vars.prevLock) return false;
8368			else {
8369
8370				var item = (side == "next") ? vars.next : vars.prev;
8371
8372				if (opts.linkId) {
8373					vars.hashLock = true;
8374					window.location.hash = opts.linkId + '/' + item;
8375				}
8376
8377				if (side == "next") {
8378					if (!iL.items[item]) return false;
8379					var firstHolder = vars.nextPhoto,
8380						secondHolder = vars.holder,
8381						lastHolder = vars.prevPhoto,
8382						firstClass = 'ilightbox-prev',
8383						secondClass = 'ilightbox-next';
8384				} else if (side == "prev") {
8385					if (!iL.items[item]) return false;
8386					var firstHolder = vars.prevPhoto,
8387						secondHolder = vars.holder,
8388						lastHolder = vars.nextPhoto,
8389						firstClass = 'ilightbox-next',
8390						secondClass = 'ilightbox-prev';
8391				}
8392
8393				//Trigger the onBeforeChange callback
8394				if (typeof opts.callback.onBeforeChange == 'function')
8395					opts.callback.onBeforeChange.call(iL, iL.ui);
8396
8397				(side == "next") ? vars.nextLock = true: vars.prevLock = true;
8398
8399				var captionFirst = $('div.ilightbox-caption', secondHolder),
8400					socialFirst = $('div.ilightbox-social', secondHolder);
8401
8402				if (captionFirst.length)
8403					captionFirst.stop().fadeOut(switchSpeed, function() {
8404						$(this).remove();
8405					});
8406				if (socialFirst.length)
8407					socialFirst.stop().fadeOut(switchSpeed, function() {
8408						$(this).remove();
8409					});
8410
8411				if (iL.items[item].caption) {
8412					iL.setCaption(iL.items[item], firstHolder);
8413					var caption = $('div.ilightbox-caption', firstHolder),
8414						percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100);
8415					if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed);
8416				}
8417
8418				var social = iL.items[item].options.social;
8419				if (social) {
8420					iL.setSocial(social, iL.items[item].URL, firstHolder);
8421					if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed);
8422				}
8423
8424				$.each([firstHolder, secondHolder, lastHolder], function(key, val) {
8425					val.removeClass('ilightbox-next ilightbox-prev');
8426				});
8427
8428				var firstOffset = firstHolder.data('offset'),
8429					winW = (viewport.width - (opts.styles.pageOffsetX)),
8430					winH = (viewport.height - (opts.styles.pageOffsetY)),
8431					width = firstOffset.newDims.width,
8432					height = firstOffset.newDims.height,
8433					thumbsOffset = firstOffset.thumbsOffset,
8434					diff = firstOffset.diff,
8435					top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)),
8436					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
8437
8438				var secondOffset = secondHolder.data('offset'),
8439					object = secondOffset.object;
8440
8441				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
8442					var objRatio = width / height;
8443					height = height - vars.captionHeight;
8444					width = height * objRatio;
8445					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top,
8446					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
8447				}*/
8448
8449				firstHolder.show().css(transform, gpuAcceleration).animate({
8450					top: top,
8451					left: left,
8452					opacity: 1
8453				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8454					firstHolder.css(transform, '');
8455				});
8456
8457				$('div.ilightbox-container', firstHolder).animate({
8458					width: width,
8459					height: height
8460				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
8461
8462				diff = secondOffset.diff;
8463
8464				width = secondOffset.newDims.width,
8465					height = secondOffset.newDims.height;
8466
8467				width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
8468					height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
8469					top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2));
8470
8471				if (side == 'prev')
8472					left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2));
8473				else {
8474					top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)),
8475					left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2));
8476				}
8477
8478				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
8479					var objRatio = width / height;
8480					height = height - vars.captionHeight;
8481					width = height * objRatio;
8482					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top;
8483				}*/
8484
8485				$('div.ilightbox-container', secondHolder).animate({
8486					width: width,
8487					height: height
8488				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
8489
8490				secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({
8491					top: top,
8492					left: left,
8493					opacity: opts.styles.prevOpacity,
8494				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8495					secondHolder.css(transform, '');
8496
8497					$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active');
8498					iL.positionThumbnails();
8499
8500					if (iL.items[item]) {
8501						if (!iL.items[item].options.mousewheel) vars.lockWheel = true;
8502						else vars.lockWheel = false;
8503
8504						if (!iL.items[item].options.swipe) vars.lockSwipe = true;
8505						else vars.lockSwipe = false;
8506					}
8507
8508					vars.isSwipe = false;
8509
8510					// Remove iframe & video from previous slide
8511					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
8512						$('div.ilightbox-container', secondHolder).empty();
8513					}
8514
8515					if (side == "next") {
8516						vars.nextPhoto = lastHolder,
8517							vars.prevPhoto = secondHolder,
8518							vars.holder = firstHolder;
8519
8520						vars.nextPhoto.hide();
8521
8522						vars.next = vars.next + 1,
8523							vars.prev = vars.current,
8524							vars.current = vars.current + 1;
8525
8526						if (opts.infinite) {
8527							if (vars.current > vars.total - 1) vars.current = 0;
8528							if (vars.current == vars.total - 1) vars.next = 0;
8529							if (vars.current == 0) vars.prev = vars.total - 1;
8530						}
8531
8532						iL.createUI();
8533
8534						if (!iL.items[vars.next])
8535							vars.nextLock = false;
8536						else
8537							iL.loadContent(iL.items[vars.next], 'next');
8538					} else {
8539						vars.prevPhoto = lastHolder;
8540						vars.nextPhoto = secondHolder;
8541						vars.holder = firstHolder;
8542
8543						vars.prevPhoto.hide();
8544
8545						vars.next = vars.current;
8546						vars.current = vars.prev;
8547						vars.prev = vars.current - 1;
8548
8549						if (opts.infinite) {
8550							if (vars.current == vars.total - 1) vars.next = 0;
8551							if (vars.current == 0) vars.prev = vars.total - 1;
8552						}
8553
8554						iL.createUI();
8555
8556						if (!iL.items[vars.prev])
8557							vars.prevLock = false;
8558						else
8559							iL.loadContent(iL.items[vars.prev], 'prev');
8560					}
8561
8562					// Add iframe & video content for current slide
8563					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
8564						iL.loadContent(iL.items[vars.current], 'current');
8565					}
8566
8567					if (opts.linkId) setTimeout(function() {
8568						vars.hashLock = false;
8569					}, 55);
8570
8571					// Configure arrow buttons
8572					if (!opts.infinite) {
8573						vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8574
8575						if (vars.current == 0)
8576							vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8577						if (vars.current >= vars.total - 1)
8578							vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8579					}
8580
8581					iL.repositionPhoto();
8582
8583					// Reset next cycle timeout
8584					iL.resetCycle();
8585
8586					//Trigger the onAfterChange callback
8587					if (typeof opts.callback.onAfterChange == 'function')
8588						opts.callback.onAfterChange.call(iL, iL.ui);
8589				});
8590
8591				top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)),
8592					left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left');
8593
8594				lastHolder.css(transform, gpuAcceleration).animate({
8595					top: top,
8596					left: left,
8597					opacity: opts.styles.nextOpacity
8598				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8599					lastHolder.css(transform, '');
8600				}).addClass(secondClass);
8601			}
8602		},
8603
8604		setCaption: function(obj, target) {
8605			var iL = this,
8606				caption = $('<div class="ilightbox-caption"></div>');
8607
8608			if (obj.caption) {
8609				caption.html(obj.caption);
8610				$('div.ilightbox-container', target).append(caption);
8611			}
8612		},
8613
8614		normalizeSocial: function(obj, url) {
8615			var iL = this,
8616				vars = iL.vars,
8617				opts = iL.options,
8618				baseURL = window.location.href;
8619
8620			$.each(obj, function(key, value) {
8621				if (!value)
8622					return true;
8623
8624				var item = key.toLowerCase(),
8625					source, text;
8626
8627				switch (item) {
8628					case 'facebook':
8629						source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}",
8630							text = "Share on Facebook";
8631						break;
8632					case 'twitter':
8633						source = "http://twitter.com/home?status={URL}",
8634							text = "Share on Twitter";
8635						break;
8636					case 'googleplus':
8637						source = "https://plus.google.com/share?url={URL}",
8638							text = "Share on Google+";
8639						break;
8640					case 'delicious':
8641						source = "http://delicious.com/post?url={URL}",
8642							text = "Share on Delicious";
8643						break;
8644					case 'digg':
8645						source = "http://digg.com/submit?phase=2&url={URL}",
8646							text = "Share on Digg";
8647						break;
8648					case 'reddit':
8649						source = "http://reddit.com/submit?url={URL}",
8650							text = "Share on reddit";
8651						break;
8652				}
8653
8654				obj[key] = {
8655					URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL,
8656					source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url),
8657					text: value.text || text || "Share on " + key,
8658					width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640,
8659					height: value.height || 360
8660				};
8661
8662			});
8663
8664			return obj;
8665		},
8666
8667		setSocial: function(obj, url, target) {
8668			var iL = this,
8669				socialBar = $('<div class="ilightbox-social"></div>'),
8670				buttons = '<ul>';
8671
8672			obj = iL.normalizeSocial(obj, url);
8673
8674			$.each(obj, function(key, value) {
8675				var item = key.toLowerCase(),
8676					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, '+'));
8677				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>';
8678			});
8679
8680			buttons += '</ul>';
8681
8682			socialBar.html(buttons);
8683			$('div.ilightbox-container', target).append(socialBar);
8684		},
8685
8686		fullScreenAction: function() {
8687			var iL = this,
8688				vars = iL.vars;
8689
8690			if (fullScreenApi.supportsFullScreen) {
8691				if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement);
8692				else fullScreenApi.requestFullScreen(document.documentElement);
8693			} else {
8694				iL.doFullscreen();
8695			}
8696		},
8697
8698		doFullscreen: function() {
8699			var iL = this,
8700				vars = iL.vars,
8701				viewport = getViewport(),
8702				opts = iL.options;
8703
8704			if (opts.fullAlone) {
8705				var currentHolder = vars.holder,
8706					current = iL.items[vars.current],
8707					windowWidth = viewport.width,
8708					windowHeight = viewport.height,
8709					elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader],
8710					hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
8711
8712				if (!vars.isInFullScreen) {
8713					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true;
8714					vars.overlay.css({
8715						opacity: 1
8716					});
8717
8718					$.each(hideElements, function(i, element) {
8719						element.hide();
8720					});
8721
8722					vars.fullScreenButton.attr('title', opts.text.exitFullscreen);
8723
8724					if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
8725						naturalWidthOld: currentHolder.data('naturalWidth'),
8726						naturalHeightOld: currentHolder.data('naturalHeight'),
8727						naturalWidth: windowWidth,
8728						naturalHeight: windowHeight
8729					});
8730					else {
8731						var viewport = current.options.fullViewPort || opts.fullViewPort || '',
8732							newWidth = windowWidth,
8733							newHeight = windowHeight,
8734							width = currentHolder.data('naturalWidth'),
8735							height = currentHolder.data('naturalHeight');
8736
8737						if (viewport.toLowerCase() == 'fill') {
8738							newHeight = (newWidth / width) * height;
8739
8740							if (newHeight < windowHeight) {
8741								newWidth = (windowHeight / height) * width,
8742									newHeight = windowHeight;
8743							}
8744						} else if (viewport.toLowerCase() == 'fit') {
8745							var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true);
8746
8747							newWidth = dims.width,
8748								newHeight = dims.height;
8749						} else if (viewport.toLowerCase() == 'stretch') {
8750							newWidth = newWidth,
8751								newHeight = newHeight;
8752						} else {
8753							var scale = (width > newWidth || height > newHeight) ? true : false,
8754								dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale);
8755							newWidth = dims.width,
8756								newHeight = dims.height;
8757						}
8758
8759						currentHolder.data({
8760							naturalWidthOld: currentHolder.data('naturalWidth'),
8761							naturalHeightOld: currentHolder.data('naturalHeight'),
8762							naturalWidth: newWidth,
8763							naturalHeight: newHeight
8764						});
8765					}
8766
8767					$.each(elements, function(key, val) {
8768						val.addClass('ilightbox-fullscreen');
8769					});
8770
8771					//Trigger the onEnterFullScreen callback
8772					if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui);
8773				} else {
8774					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false;
8775					vars.overlay.css({
8776						opacity: iL.options.overlay.opacity
8777					});
8778
8779					$.each(hideElements, function(i, element) {
8780						element.show();
8781					});
8782
8783					vars.fullScreenButton.attr('title', opts.text.enterFullscreen);
8784
8785					currentHolder.data({
8786						naturalWidth: currentHolder.data('naturalWidthOld'),
8787						naturalHeight: currentHolder.data('naturalHeightOld'),
8788						naturalWidthOld: null,
8789						naturalHeightOld: null
8790					});
8791
8792					$.each(elements, function(key, val) {
8793						val.removeClass('ilightbox-fullscreen');
8794					});
8795
8796					//Trigger the onExitFullScreen callback
8797					if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui);
8798				}
8799			} else {
8800				if (!vars.isInFullScreen) vars.isInFullScreen = true;
8801				else vars.isInFullScreen = false;
8802			}
8803			iL.repositionPhoto(true);
8804		},
8805
8806		closeAction: function() {
8807			var iL = this,
8808				vars = iL.vars,
8809				opts = iL.options;
8810
8811			$win.unbind('.iLightBox');
8812			$doc.off('.iLightBox');
8813
8814			if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement);
8815
8816			$('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox');
8817
8818			if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() {
8819				vars.overlay.remove();
8820				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
8821			});
8822			else {
8823				vars.overlay.remove();
8824				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
8825			}
8826
8827			var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
8828
8829			$.each(fadeOuts, function(i, element) {
8830				element.removeAttr('style').remove();
8831			});
8832
8833			vars.dontGenerateThumbs = vars.isInFullScreen = false;
8834
8835			window.iLightBox = null;
8836
8837			if (opts.linkId) {
8838				vars.hashLock = true;
8839				removeHash();
8840				setTimeout(function() {
8841					vars.hashLock = false;
8842				}, 55);
8843			}
8844
8845			//Trigger the onHide callback
8846			if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui);
8847		},
8848
8849		repositionPhoto: function() {
8850			var iL = this,
8851				vars = iL.vars,
8852				opts = iL.options,
8853				path = opts.path.toLowerCase(),
8854				viewport = getViewport(),
8855				winWidth = viewport.width,
8856				winHeight = viewport.height;
8857
8858			if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0;
8859
8860			var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()),
8861				thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)),
8862				width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)),
8863				height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)),
8864				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,
8865				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)));
8866
8867			var elObject = {
8868				type: 'current',
8869				width: width,
8870				height: height,
8871				item: iL.items[vars.current],
8872				offsetW: offsetW,
8873				offsetH: offsetH,
8874				thumbsOffsetW: thumbsOffsetW,
8875				thumbsOffsetH: thumbsOffsetH,
8876				animate: arguments.length,
8877				holder: vars.holder
8878			};
8879
8880			iL.repositionEl(elObject);
8881
8882			if (iL.items[vars.next]) {
8883				elObject = $.extend(elObject, {
8884					type: 'next',
8885					item: iL.items[vars.next],
8886					offsetX: opts.styles.nextOffsetX,
8887					offsetY: opts.styles.nextOffsetY,
8888					holder: vars.nextPhoto
8889				});
8890
8891				iL.repositionEl(elObject);
8892			}
8893
8894			if (iL.items[vars.prev]) {
8895				elObject = $.extend(elObject, {
8896					type: 'prev',
8897					item: iL.items[vars.prev],
8898					offsetX: opts.styles.nextOffsetX,
8899					offsetY: opts.styles.prevOffsetY,
8900					holder: vars.prevPhoto
8901				});
8902
8903				iL.repositionEl(elObject);
8904			}
8905
8906			var loaderCss = (path == "horizontal") ? {
8907				left: parseInt((width / 2) - (vars.loader.outerWidth() / 2))
8908			} : {
8909				top: parseInt((height / 2) - (vars.loader.outerHeight() / 2))
8910			};
8911			vars.loader.css(loaderCss);
8912		},
8913
8914		repositionEl: function(obj) {
8915			var iL = this,
8916				vars = iL.vars,
8917				opts = iL.options,
8918				path = opts.path.toLowerCase(),
8919				widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW),
8920				heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH),
8921				itemParent = obj.item,
8922				item = obj.item.options,
8923				holder = obj.holder,
8924				offsetX = obj.offsetX || 0,
8925				offsetY = obj.offsetY || 0,
8926				thumbsOffsetW = obj.thumbsOffsetW,
8927				thumbsOffsetH = obj.thumbsOffsetH;
8928
8929			if (obj.type == 'current') {
8930				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);
8931				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);
8932			} else {
8933				if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width;
8934				if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height;
8935			}
8936
8937			heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight());
8938
8939			var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'),
8940				height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight');
8941
8942			var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? {
8943					width: width,
8944					height: height
8945				} : iL.getNewDimenstions(widthAvail, heightAvail, width, height)),
8946				newDims = $.extend({}, dims, {});
8947
8948			if (obj.type == 'prev' || obj.type == 'next')
8949				width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)),
8950				height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale));
8951			else
8952				width = dims.width,
8953				height = dims.height;
8954
8955			var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2),
8956				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);
8957
8958			switch (obj.type) {
8959				case 'current':
8960					var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)),
8961						left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2));
8962					break;
8963
8964				case 'next':
8965					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)),
8966						left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2));
8967					break;
8968
8969				case 'prev':
8970					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)),
8971						left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2));
8972					break;
8973			}
8974
8975			holder.data('offset', {
8976				top: top,
8977				left: left,
8978				newDims: newDims,
8979				diff: {
8980					W: widthDiff,
8981					H: heightDiff
8982				},
8983				thumbsOffset: {
8984					W: thumbsOffsetW,
8985					H: thumbsOffsetH
8986				},
8987				object: obj
8988			});
8989
8990      var opacityMobile;
8991      if ( isMobile ) {
8992        opacityMobile = {
8993          opacity: 1,
8994          top: top,
8995          left: left
8996        };
8997      } else {
8998        opacityMobile = {
8999          top: top,
9000          left: left
9001        };
9002      }
9003
9004      if (obj.animate > 0 && opts.effects.reposition) {
9005        holder.css(transform, gpuAcceleration).stop().animate(
9006          opacityMobile, 
9007          opts.effects.repositionSpeed, 'easeOutCirc', function() {
9008          holder.css(transform, '');
9009        });
9010        $('div.ilightbox-container', holder).stop().animate({
9011          width: width,
9012          height: height
9013        }, opts.effects.repositionSpeed, 'easeOutCirc');
9014        $('div.ilightbox-inner-toolbar', holder).stop().animate({
9015          width: width
9016        }, opts.effects.repositionSpeed, 'easeOutCirc', function() {
9017          $(this).css('overflow', 'visible');
9018        });
9019      } else {
9020        holder.css(opacityMobile);
9021        $('div.ilightbox-container', holder).css({
9022          width: width,
9023          height: height
9024        });
9025        $('div.ilightbox-inner-toolbar', holder).css({
9026          width: width
9027        });
9028      }
9029    },
9030
9031
9032		resume: function(priority) {
9033			var iL = this,
9034				vars = iL.vars,
9035				opts = iL.options;
9036
9037			if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) {
9038				return;
9039			}
9040
9041			vars.isPaused = 0;
9042
9043			if (vars.cycleID) {
9044				vars.cycleID = clearTimeout(vars.cycleID);
9045			}
9046
9047			vars.cycleID = setTimeout(function() {
9048				if (vars.current == vars.total - 1) iL.goTo(0);
9049				else iL.moveTo('next');
9050			}, opts.slideshow.pauseTime);
9051		},
9052
9053		pause: function(priority) {
9054			var iL = this,
9055				vars = iL.vars,
9056				opts = iL.options;
9057
9058			if (priority < vars.isPaused) {
9059				return;
9060			}
9061
9062			vars.isPaused = priority || 100;
9063
9064			if (vars.cycleID) {
9065				vars.cycleID = clearTimeout(vars.cycleID);
9066			}
9067		},
9068
9069		resetCycle: function() {
9070			var iL = this,
9071				vars = iL.vars,
9072				opts = iL.options;
9073
9074			if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) {
9075				iL.resume();
9076			}
9077		},
9078
9079		getNewDimenstions: function(width, height, width_old, height_old, thumb) {
9080			var iL = this;
9081
9082			if (!width) factor = height / height_old;
9083			else if (!height) factor = width / width_old;
9084			else factor = min(width / width_old, height / height_old);
9085
9086			if (!thumb) {
9087				if (factor > iL.options.maxScale) factor = iL.options.maxScale;
9088				else if (factor < iL.options.minScale) factor = iL.options.minScale;
9089			}
9090
9091			var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width,
9092				final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height;
9093
9094			return {
9095				width: final_width,
9096				height: final_height,
9097				ratio: factor
9098			};
9099		},
9100
9101		setOption: function(options) {
9102			var iL = this;
9103
9104			iL.options = $.extend(true, iL.options, options || {});
9105			iL.refresh();
9106		},
9107
9108		availPlugins: function() {
9109			var iL = this,
9110				testEl = document.createElement("video");
9111
9112			iL.plugins = {
9113				flash: !isMobile,
9114				quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false,
9115				html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')),
9116				html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')),
9117				html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')),
9118				html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, ''))
9119			};
9120		},
9121
9122		addContent: function(element, obj) {
9123			var iL = this,
9124				el;
9125
9126			switch (obj.type) {
9127				case 'video':
9128					var HTML5 = false,
9129						videoType = obj.videoType,
9130						html5video = obj.options.html5video;
9131
9132					if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264)
9133						obj.ext = 'mp4',
9134						obj.URL = html5video.h264 || obj.URL;
9135					else if (html5video.webm && iL.plugins.html5WebM)
9136						obj.ext = 'webm',
9137						obj.URL = html5video.webm || obj.URL;
9138					else if (html5video.ogg && iL.plugins.html5Vorbis)
9139						obj.ext = 'ogv',
9140						obj.URL = html5video.ogg || obj.URL;
9141
9142					if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4";
9143					else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm";
9144					else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg";
9145					else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime";
9146
9147					if (HTML5) {
9148						el = $('<video />
9148', {
9149							"width": "100%",
9150							"height": "100%",
9151							"preload": html5video.preload,
9152							"autoplay": html5video.autoplay,
9153							"poster": html5video.poster,
9154							"controls": html5video.controls
9155						}).append($('<source />', {
9156							"src": obj.URL,
9157							"type": videoType
9158						}));
9159					} else {
9160						if (!iL.plugins.quicktime) el = $('<span />', {
9161							"class": "ilightbox-alert",
9162							html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime')
9163						});
9164						else {
9165
9166							el = $('<object />', {
9167								"type": "video/quicktime",
9168								"pluginspage": pluginspages.quicktime
9169							}).attr({
9170								"data": obj.URL,
9171								"width": "100%",
9172								"height": "100%"
9173							}).append($('<param />', {
9174								"name": "src",
9175								"value": obj.URL
9176							})).append($('<param />', {
9177								"name": "autoplay",
9178								"value": "false"
9179							})).append($('<param />', {
9180								"name": "loop",
9181								"value": "false"
9182							})).append($('<param />', {
9183								"name": "scale",
9184								"value": "tofit"
9185							}));
9186
9187							if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false');
9188						}
9189					}
9190
9191					break;
9192
9193				case 'flash':
9194					if (!iL.plugins.flash) el = $('<span />', {
9195						"class": "ilightbox-alert",
9196						html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player')
9197					});
9198					else {
9199						var flashvars = "",
9200							i = 0;
9201
9202						if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) {
9203							if (i != 0) flashvars += "&";
9204							flashvars += k + "=" + encodeURIComponent(v);
9205							i++;
9206						});
9207						else flashvars = null;
9208
9209						el = $('<embed />').attr({
9210							"type": "application/x-shockwave-flash",
9211							"src": obj.URL,
9212							"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
9213							"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
9214							"quality": "high",
9215							"bgcolor": "#000000",
9216							"play": "true",
9217							"loop": "true",
9218							"menu": "true",
9219							"wmode": "transparent",
9220							"scale": "showall",
9221							"allowScriptAccess": "always",
9222							"allowFullScreen": "true",
9223							"flashvars": flashvars,
9224							"fullscreen": "yes"
9225						});
9226					}
9227
9228					break;
9229
9230				case 'iframe':
9231					el = $('<iframe />').attr({
9232						"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
9233						"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
9234						src: obj.URL,
9235						frameborder: 0,
9236						'hspace': 0,
9237						'vspace': 0,
9238						'scrolling': supportTouch ? 'auto' : 'scroll',
9239						'webkitAllowFullScreen': '',
9240						'mozallowfullscreen': '',
9241						'allowFullScreen': ''
9242					});
9243
9244					break;
9245
9246				case 'inline':
9247					el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true));
9248
9249					break;
9250
9251				case 'html':
9252					var object = obj.URL,
9253						el;
9254
9255					if (object[0].nodeName) {
9256						el = $('<div class="ilightbox-wrapper"></div>').html(object);
9257					} else {
9258						var dom = $(obj.URL),
9259							html = (dom.selector) ? $('<div>' + dom + '</div>') : dom;
9260						el = $('<div class="ilightbox-wrapper"></div>').html(html);
9261					}
9262
9263					break;
9264			}
9265
9266			$('div.ilightbox-container', element).empty().html(el);
9267
9268			// For fixing Chrome about just playing the video for first time
9269			if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() {
9270				var src = el[0].currentSrc + '?' + floor(random() * 30000);
9271				el[0].currentSrc = src;
9272				el[0].src = src;
9273			});
9274
9275			return el;
9276		},
9277
9278		ogpRecognition: function(obj, callback) {
9279			var iL = this,
9280				url = obj.URL;
9281
9282			iL.showLoader();
9283			doAjax(url, function(data) {
9284				iL.hideLoader();
9285				if (data) {
9286					var object = new Object();
9287
9288					object.length = false,
9289					object.url = data.url;
9290
9291					if (data.status == 200) {
9292						var result = data.results,
9293							type = result.type,
9294							source = result.source;
9295
9296						object.source = source.src,
9297						object.width = source.width && parseInt(source.width) || 0,
9298						object.height = source.height && parseInt(source.height) || 0,
9299						object.type = type,
9300						object.thumbnail = source.thumbnail || result.images && result.images[0],
9301						object.html5video = result.html5video || {},
9302						object.length = true;
9303
9304						if (source.type == 'application/x-shockwave-flash') object.type = "flash";
9305						else if (source.type.indexOf("video/") != -1) object.type = "video";
9306						else if (source.type.indexOf("/html") != -1) object.type = "iframe";
9307						else if (source.type.indexOf("image/") != -1) object.type = "image";
9308
9309					} else if (typeof data.response != 'undefined')
9310						throw data.response;
9311
9312					callback.call(this, object.length ? object : false);
9313				}
9314			});
9315		},
9316
9317		hashChangeHandler: function(url) {
9318			var iL = this,
9319				vars = iL.vars,
9320				opts = iL.options,
9321				URL = url || window.location.href,
9322				hash = parseURI(URL).hash,
9323				split = hash.split('/'),
9324				index = split[1];
9325
9326			if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return;
9327
9328			if (index) {
9329				var target = split[1] || 0;
9330				if (iL.items[target]) {
9331					var overlay = $('.ilightbox-overlay');
9332					if (overlay.length && overlay.attr('linkid') == opts.linkId) {
9333						iL.goTo(target);
9334					} else {
9335						iL.itemsObject[target].trigger(supportTouch ? 'itap' : 'click');
9336						iL.goTo(target);
9337					}
9338				} else {
9339					var overlay = $('.ilightbox-overlay');
9340					if (overlay.length) iL.closeAction();
9341				}
9342			} else {
9343				var overlay = $('.ilightbox-overlay');
9344				if (overlay.length) iL.closeAction();
9345			}
9346		}
9347	};
9348
9349	/**
9350	 * Parse style to pixels.
9351	 *
9352	 * @param {Object}   $element   jQuery object with element.
9353	 * @param {Property} property   CSS property to get the pixels from.
9354	 *
9355	 * @return {Int}
9356	 */
9357	function getPixel($element, property) {
9358		return parseInt($element.css(property), 10) || 0;
9359	}
9360
9361	/**
9362	 * Make sure that number is within the limits.
9363	 *
9364	 * @param {Number} number
9365	 * @param {Number} min
9366	 * @param {Number} max
9367	 *
9368	 * @return {Number}
9369	 */
9370	function within(number, min, max) {
9371		return number < min ? min : number > max ? max : number;
9372	}
9373
9374	/**
9375	 * Get viewport/window size (width and height).
9376	 *
9377	 * @return {Object}
9378	 */
9379	function getViewport() {
9380		var e = window,
9381			a = 'inner';
9382		if (!('innerWidth' in window)) {
9383			a = 'client';
9384			e = document.documentElement || document.body;
9385		}
9386		return {
9387			width: e[a + 'Width'],
9388			height: e[a + 'Height']
9389		}
9390	}
9391
9392	/**
9393	 * Remove hash tag from the URL
9394	 *
9395	 * @return {Void}
9396	 */
9397	function removeHash() {
9398		var scroll = getScrollXY();
9399
9400		window.location.hash = "";
9401
9402		// Restore the scroll offset, should be flicker free
9403		window.scrollTo(scroll.x, scroll.y);
9404	}
9405
9406	/**
9407	 * Do the ajax requests with callback.
9408	 *
9409	 * @param {String}   url
9410	 * @param {Function} callback
9411	 *
9412	 * @return {Void}
9413	 */
9414	function doAjax(url, callback) {
9415		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');
9416		$.ajax({
9417			url: url,
9418			dataType: 'jsonp'
9419		});
9420
9421		iLCallback = function(data) {
9422			callback.call(this, data);
9423		};
9424	}
9425
9426	/**
9427	 * Find image from DOM elements
9428	 *
9429	 * @param {Element} element
9430	 *
9431	 * @return {Void}
9432	 */
9433	function findImageInElement(element) {
9434		var elements = $('*', element),
9435			imagesArr = new Array();
9436
9437		elements.each(function() {
9438			var url = "",
9439				element = this;
9440
9441			if ($(element).css("background-image") != "none") {
9442				url = $(element).css("background-image");
9443			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
9444				url = $(element).attr("src");
9445			}
9446
9447			if (url.indexOf("gradient") == -1) {
9448				url = url.replace(/url\(\"/g, "");
9449				url = url.replace(/url\(/g, "");
9450				url = url.replace(/\"\)/g, "");
9451				url = url.replace(/\)/g, "");
9452
9453				var urls = url.split(",");
9454
9455				for (var i = 0; i < urls.length; i++) {
9456					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
9457						var extra = "";
9458						if (browser.msie && browser.version < 9) {
9459							extra = "?" + floor(random() * 3000);
9460						}
9461						imagesArr.push(urls[i] + extra);
9462					}
9463				}
9464			}
9465		});
9466
9467		return imagesArr;
9468	}
9469
9470	/**
9471	 * Get file extension.
9472	 *
9473	 * @param {String} URL
9474	 *
9475	 * @return {String}
9476	 */
9477	function getExtension(URL) {
9478		if (URL !== null) {
9479			var ext = URL.split('.').pop().toLowerCase(),
9480				extra = ext.indexOf('?') !== -1 ? ext.split('?').pop() : '';
9481
9482			return ext.replace(extra, '');
9483		}
9484	}
9485
9486	/**
9487	 * Get type via extension.
9488	 *
9489	 * @param {String} URL
9490	 *
9491	 * @return {String}
9492	 */
9493	function getTypeByExtension(URL) {
9494		var type,
9495			ext = getExtension(URL);
9496
9497		if (extensions.image.indexOf(ext) !== -1) type = 'image';
9498		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
9499		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
9500		else type = 'iframe';
9501
9502		return type;
9503	}
9504
9505	/**
9506	 * Return value from percent of a number.
9507	 *
9508	 * @param {Number} percent
9509	 * @param {Number} total
9510	 *
9511	 * @return {Number}
9512	 */
9513	function percentToValue(percent, total) {
9514		return parseInt((total / 100) * percent);
9515	}
9516
9517	/**
9518	 * A JavaScript equivalent of PHP’s parse_url.
9519	 *
9520	 * @param {String} url           The URL to parse.
9521	 *
9522	 * @return {Mixed}
9523	 */
9524	function parseURI(url) {
9525		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
9526		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
9527		return (m ? {
9528			href: m[0] || '',
9529			protocol: m[1] || '',
9530			authority: m[2] || '',
9531			host: m[3] || '',
9532			hostname: m[4] || '',
9533			port: m[5] || '',
9534			pathname: m[6] || '',
9535			search: m[7] || '',
9536			hash: m[8] || ''
9537		} : null);
9538	}
9539
9540	/**
9541	 * Gets the absolute URI.
9542	 *
9543	 * @param {String} href     The relative URL.
9544	 * @param {String} base     The base URL.
9545	 *
9546	 * @return {String}         The absolute URL.
9547	 */
9548	function absolutizeURI(base, href) { // RFC 3986
9549		var iL = this;
9550
9551		function removeDotSegments(input) {
9552			var output = [];
9553			input.replace(/^(\.\.?(\/|$))+/, '')
9554				.replace(/\/(\.(\/|$))+/g, '/')
9555				.replace(/\/\.\.$/, '/../')
9556				.replace(/\/?[^\/]*/g, function(p) {
9557					if (p === '/..') {
9558						output.pop();
9559					} else {
9560						output.push(p);
9561					}
9562				});
9563			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
9564		}
9565
9566		href = parseURI(href || '');
9567		base = parseURI(base || '');
9568
9569		return !href || !base ? null : (href.protocol || base.protocol) +
9570			(href.protocol || href.authority ? href.authority : base.authority) +
9571			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)) +
9572			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
9573			href.hash;
9574	}
9575
9576	/**
9577	 * A JavaScript equivalent of PHP’s version_compare.
9578	 *
9579	 * @param {String} v1
9580	 * @param {String} v2
9581	 * @param {String} operator
9582	 *
9583	 * @return {Boolean}
9584	 */
9585	function version_compare(v1, v2, operator) {
9586		this.php_js = this.php_js || {};
9587		this.php_js.ENV = this.php_js.ENV || {};
9588		var i = 0,
9589			x = 0,
9590			compare = 0,
9591			vm = {
9592				'dev': -6,
9593				'alpha': -5,
9594				'a': -5,
9595				'beta': -4,
9596				'b': -4,
9597				'RC': -3,
9598				'rc': -3,
9599				'#': -2,
9600				'p': 1,
9601				'pl': 1
9602			},
9603			prepVersion = function(v) {
9604				v = ('' + v).replace(/[_\-+]/g, '.');
9605				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
9606				return (!v.length ? [-8] : v.split('.'));
9607			},
9608			numVersion = function(v) {
9609				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
9610			};
9611		v1 = prepVersion(v1);
9612		v2 = prepVersion(v2);
9613		x = max(v1.length, v2.length);
9614		for (i = 0; i < x; i++) {
9615			if (v1[i] == v2[i]) {
9616				continue;
9617			}
9618			v1[i] = numVersion(v1[i]);
9619			v2[i] = numVersion(v2[i]);
9620			if (v1[i] < v2[i]) {
9621				compare = -1;
9622				break;
9623			} else if (v1[i] > v2[i]) {
9624				compare = 1;
9625				break;
9626			}
9627		}
9628		if (!operator) {
9629			return compare;
9630		}
9631
9632		switch (operator) {
9633			case '>':
9634			case 'gt':
9635				return (compare > 0);
9636			case '>=':
9637			case 'ge':
9638				return (compare >= 0);
9639			case '<=':
9640			case 'le':
9641				return (compare <= 0);
9642			case '==':
9643			case '=':
9644			case 'eq':
9645				return (compare === 0);
9646			case '<>':
9647			case '!=':
9648			case 'ne':
9649				return (compare !== 0);
9650			case '':
9651			case '<':
9652			case 'lt':
9653				return (compare < 0);
9654			default:
9655				return null;
9656		}
9657	}
9658
9659
9660	// Begin the iLightBox plugin
9661	$.fn.iLightBox = function() {
9662
9663		var args = arguments,
9664			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
9665			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
9666
9667		if (!opt) opt = {};
9668
9669		// Default options. Play carefully.
9670		var options = $.extend(true, {
9671			attr: 'href',
9672			path: 'vertical',
9673			skin: 'dark',
9674			linkId: false,
9675			infinite: false,
9676			startFrom: 0,
9677			randomStart: false,
9678			keepAspectRatio: true,
9679			maxScale: 1,
9680			minScale: .2,
9681			innerToolbar: false,
9682			smartRecognition: false,
9683			mobileOptimizer: true,
9684			fullAlone: true,
9685			fullViewPort: null,
9686			fullStretchTypes: 'flash, video',
9687			overlay: {
9688				blur: true,
9689				opacity: .85
9690			},
9691			controls: {
9692				arrows: false,
9693				slideshow: false,
9694				toolbar: true,
9695				fullscreen: true,
9696				thumbnail: true,
9697				keyboard: true,
9698				mousewheel: true,
9699				swipe: true
9700			},
9701			keyboard: {
9702				left: true, // previous
9703				right: true, // next
9704				up: true, // previous
9705				down: true, // next
9706				esc: true, // close
9707				shift_enter: true // fullscreen
9708			},
9709			show: {
9710				effect: true,
9711				speed: 300,
9712				title: true
9713			},
9714			hide: {
9715				effect: true,
9716				speed: 300
9717			},
9718			caption: {
9719				start: true,
9720				show: 'mouseenter',
9721				hide: 'mouseleave'
9722			},
9723			social: {
9724				start: true,
9725				show: 'mouseenter',
9726				hide: 'mouseleave',
9727				buttons: false
9728			},
9729			styles: {
9730				pageOffsetX: 0,
9731				pageOffsetY: 0,
9732				nextOffsetX: 45,
9733				nextOffsetY: 0,
9734				nextOpacity: 1,
9735				nextScale: 1,
9736				prevOffsetX: 45,
9737				prevOffsetY: 0,
9738				prevOpacity: 1,
9739				prevScale: 1
9740			},
9741			thumbnails: {
9742				maxWidth: 120,
9743				maxHeight: 80,
9744				normalOpacity: 1,
9745				activeOpacity: .6
9746			},
9747			effects: {
9748				reposition: true,
9749				repositionSpeed: 200,
9750				switchSpeed: 500,
9751				loadedFadeSpeed: 180,
9752				fadeSpeed: 200
9753			},
9754			slideshow: {
9755				pauseTime: 5000,
9756				pauseOnHover: false,
9757				startPaused: true
9758			},
9759			text: {
9760				close: "Press Esc to close",
9761				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
9762				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
9763				slideShow: "Slideshow",
9764				next: "Next",
9765				previous: "Previous"
9766			},
9767			errors: {
9768				loadImage: "An error occurred when trying to load photo.",
9769				loadContents: "An error occurred when trying to load contents.",
9770				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
9771			},
9772			ajaxSetup: {
9773				url: '',
9774				beforeSend: function(jqXHR, settings) {},
9775				cache: false,
9776				complete: function(jqXHR, textStatus) {},
9777				crossDomain: false,
9778				error: function(jqXHR, textStatus, errorThrown) {},
9779				success: function(data, textStatus, jqXHR) {},
9780				global: true,
9781				ifModified: false,
9782				username: null,
9783				password: null,
9784				type: 'GET'
9785			},
9786			callback: {}
9787		}, opt);
9788
9789		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
9790
9791		items = $.isArray(items) ? items : new Array();
9792
9793		if (typeof args[0] == 'string') items[0] = args[0];
9794
9795		if (version_compare($.fn.jquery, '1.8', '>=')) {
9796			var iLB = new iLightBox($(this), options, items, instant);
9797			return {
9798				close: function() {
9799					iLB.closeAction();
9800				},
9801				fullscreen: function() {
9802					iLB.fullScreenAction();
9803				},
9804				moveNext: function() {
9805					iLB.moveTo('next');
9806				},
9807				movePrev: function() {
9808					iLB.moveTo('prev');
9809				},
9810				goTo: function(index) {
9811					iLB.goTo(index);
9812				},
9813				refresh: function() {
9814					iLB.refresh();
9815				},
9816				reposition: function() {
9817					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
9818				},
9819				setOption: function(options) {
9820					iLB.setOption(options);
9821				},
9822				destroy: function() {
9823					iLB.closeAction();
9824					iLB.dispatchItemsEvents();
9825				}
9826			};
9827		} else {
9828			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
9829		}
9830
9831	};
9832
9833
9834	$.iLightBox = function() {
9835		return $.fn.iLightBox(arguments[0], arguments[1]);
9836	};
9837
9838
9839	$.extend($.easing, {
9840		easeInCirc: function(x, t, b, c, d) {
9841			return -c * (sqrt(1 - (t /= d) * t) - 1) + b;
9842		},
9843		easeOutCirc: function(x, t, b, c, d) {
9844			return c * sqrt(1 - (t = t / d - 1) * t) + b;
9845		},
9846		easeInOutCirc: function(x, t, b, c, d) {
9847			if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b;
9848			return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b;
9849		}
9850	});
9851
9852	function getScrollXY() {
9853		var scrOfX = 0,
9854			scrOfY = 0;
9855		if (typeof(window.pageYOffset) == 'number') {
9856			//Netscape compliant
9857			scrOfY = window.pageYOffset;
9858			scrOfX = window.pageXOffset;
9859		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
9860			//DOM compliant
9861			scrOfY = document.body.scrollTop;
9862			scrOfX = document.body.scrollLeft;
9863		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
9864			//IE6 standards compliant mode
9865			scrOfY = document.documentElement.scrollTop;
9866			scrOfX = document.documentElement.scrollLeft;
9867		}
9868		return {
9869			x: scrOfX,
9870			y: scrOfY
9871		};
9872	}
9873
9874	(function() {
9875		// add new event shortcuts
9876		$.each(("touchstart touchmove touchend " +
9877			"tap taphold " +
9878			"swipe swipeleft swiperight " +
9879			"scrollstart scrollstop").split(" "), function(i, name) {
9880
9881			$.fn[name] = function(fn) {
9882				return fn ? this.bind(name, fn) : this.trigger(name);
9883			};
9884
9885			// jQuery < 1.8
9886			// if ($.attrFn) {
9887			// 	$.attrFn[name] = true;
9888			// }
9889		});
9890
9891		var tapSettings = {
9892			startEvent: 'touchstart.iTap',
9893			endEvent: 'touchend.iTap'
9894		};
9895
9896		// tap Event:
9897		$.event.special.itap = {
9898			setup: function() {
9899
9900				var self = this,
9901					$self = $(this),
9902					start, stop;
9903
9904				$self.bind(tapSettings.startEvent, function(event) {
9905					start = getScrollXY();
9906
9907					$self.one(tapSettings.endEvent, function(event) {
9908						stop = getScrollXY();
9909
9910						var orgEvent = event || window.event;
9911						event = $.event.fix(orgEvent);
9912						event.type = "itap";
9913
9914						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
9915
9916						start = stop = undefined;
9917					});
9918				});
9919			},
9920
9921			teardown: function() {
9922				$(this).unbind(tapSettings.startEvent);
9923			}
9924		};
9925	}());
9926
9927
9928	//Fullscreen API
9929	(function() {
9930		fullScreenApi = {
9931				supportsFullScreen: false,
9932				isFullScreen: function() {
9933					return false;
9934				},
9935				requestFullScreen: function() {},
9936				cancelFullScreen: function() {},
9937				fullScreenEventName: '',
9938				prefix: ''
9939			},
9940			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
9941
9942		// check for native support
9943		if (typeof document.cancelFullScreen != 'undefined') {
9944			fullScreenApi.supportsFullScreen = true;
9945		} else {
9946			// check for fullscreen support by vendor prefix
9947			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
9948				fullScreenApi.prefix = browserPrefixes[i];
9949
9950				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
9951					fullScreenApi.supportsFullScreen = true;
9952
9953					break;
9954				}
9955			}
9956		}
9957
9958		// update methods to do something useful
9959		if (fullScreenApi.supportsFullScreen) {
9960			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
9961
9962			fullScreenApi.isFullScreen = function() {
9963				switch (this.prefix) {
9964					case '':
9965						return document.fullScreen;
9966					case 'webkit':
9967						return document.webkitIsFullScreen;
9968					default:
9969						return document[this.prefix + 'FullScreen'];
9970				}
9971			}
9972			fullScreenApi.requestFullScreen = function(el) {
9973				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
9974			}
9975			fullScreenApi.cancelFullScreen = function(el) {
9976				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
9977			}
9978		}
9979	}());
9980
9981	// Browser detect
9982	(function() {
9983		function uaMatch(ua) {
9984			ua = ua.toLowerCase();
9985
9986			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
9987				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
9988				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
9989				/(msie) ([\w.]+)/.exec(ua) ||
9990				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
9991
9992			return {
9993				browser: match[1] || "",
9994				version: match[2] || "0"
9995			};
9996		}
9997
9998		var matched = uaMatch(navigator.userAgent);
9999		browser = {};
10000
10001		if (matched.browser) {
10002			browser[matched.browser] = true;
10003			browser.version = matched.version;
10004		}
10005
10006		// Chrome is Webkit, but Webkit is also Safari.
10007		if (browser.chrome) {
10008			browser.webkit = true;
10009		} else if (browser.webkit) {
10010			browser.safari = true;
10011		}
10012	}());
10013
10014	// Feature detects
10015	(function() {
10016		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
10017		var el = document.createElement('div');
10018
10019		function testProp(prop) {
10020			for (var p = 0, pl = prefixes.length; p < pl; p++) {
10021				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
10022				if (el.style[prefixedProp] !== undefined) {
10023					return prefixedProp;
10024				}
10025			}
10026		}
10027
10028		// Global support indicators
10029		transform = testProp('transform') || '';
10030		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
10031	}());
10032
10033
10034	/*
10035		PluginDetect v0.7.9
10036		www.pinlady.net/PluginDetect/license/
10037		[ getVersion onWindowLoaded BetterIE ]
10038		[ Flash QuickTime Shockwave ]
10039	*/
10040	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;
10040d++){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);
10040d.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)}
10040c.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;
10040if(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();
10041
10042	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)};
10043
10044
10045	/*
10046		jQuery hashchange event v1.3
10047		https://github.com/cowboy/jquery-hashchange
10048		Copyright (c) 2010 "Cowboy" Ben Alman
10049		Dual licensed under the MIT and GPL licenses.
10050	*/
10051	(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=
10052	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||
10053	"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;
10053a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
10054
10055	if (!Array.prototype.filter) {
10056		Array.prototype.filter = function(fun /*, thisp */ ) {
10057			"use strict";
10058
10059			if (this == null)
10060				throw new TypeError();
10061
10062			var t = Object(this);
10063			var len = t.length >>> 0;
10064			if (typeof fun != "function")
10065				throw new TypeError();
10066
10067			var res = [];
10068			var thisp = arguments[1];
10069			for (var i = 0; i < len; i++) {
10070				if (i in t) {
10071					var val = t[i]; // in case fun mutates this
10072					if (fun.call(thisp, val, i, t))
10073						res.push(val);
10074				}
10075			}
10076
10077			return res;
10078		};
10079	}
10080
10081	if (!Array.prototype.indexOf) {
10082		Array.prototype.indexOf = function(searchElement, fromIndex) {
10083			var k;
10084
10085			if (this == null) {
10086				throw new TypeError('"this" is null or not defined');
10087			}
10088
10089			var O = Object(this);
10090
10091			var len = O.length >>> 0;
10092
10093			if (len === 0) {
10094				return -1;
10095			}
10096
10097			var n = +fromIndex || 0;
10098
10099			if (abs(n) === Infinity) {
10100				n = 0;
10101			}
10102
10103			if (n >= len) {
10104				return -1;
10105			}
10106
10107			k = max(n >= 0 ? n : len - abs(n), 0);
10108
10109			while (k < len) {
10110				var kValue;
10111				if (k in O && O[k] === searchElement) {
10112					return k;
10113				}
10114				k++;
10115			}
10116			return -1;
10117		};
10118	}
10119
10120	if (!Array.prototype.lastIndexOf) {
10121		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
10122			"use strict";
10123
10124			if (this == null)
10125				throw new TypeError();
10126
10127			var t = Object(this);
10128			var len = t.length >>> 0;
10129			if (len === 0)
10130				return -1;
10131
10132			var n = len;
10133			if (arguments.length > 1) {
10134				n = Number(arguments[1]);
10135				if (n != n)
10136					n = 0;
10137				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
10138					n = (n > 0 || -1) * floor(abs(n));
10139			}
10140
10141			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
10142
10143			for (; k >= 0; k--) {
10144				if (k in t && t[k] === searchElement)
10145					return k;
10146			}
10147			return -1;
10148		};
10149	}
10150})(jQuery, this);
10151
10152/**
10153 * Owl carousel
vendor: 12,045 bytes, lines 10154-10659
10154 * @version 2.0.0-beta.3
10155 * @author Bartosz Wojciechowski
10156 * @license The MIT License (MIT)
10157 * @todo Lazy Load Icon
10158 * @todo prevent animationend bubling
10159 * @todo itemsScaleUp
10160 * @todo Test Zepto
10161 * @todo stagePadding calculate wrong active classes
10162 */
10163;(function($, window, document, undefined) {
10164
10165	/**
10166	 * Creates a carousel.
10167	 * @class The Owl Carousel.
10168	 * @public
10169	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
10170	 * @param {Object} [options] - The options
10171	 */
10172	function Owl(element, options) {
10173
10174		/**
10175		 * Current settings for the carousel.
10176		 * @public
10177		 */
10178		this.settings = null;
10179
10180		/**
10181		 * Current options set by the caller including defaults.
10182		 * @public
10183		 */
10184		this.options = $.extend({}, Owl.Defaults, options);
10185
10186		/**
10187		 * Plugin element.
10188		 * @public
10189		 */
10190		this.$element = $(element);
10191
10192		/**
10193		 * Proxied event handlers.
10194		 * @protected
10195		 */
10196		this._handlers = {};
10197
10198		/**
10199		 * References to the running plugins of this carousel.
10200		 * @protected
10201		 */
10202		this._plugins = {};
10203
10204		/**
10205		 * Currently suppressed events to prevent them from beeing retriggered.
10206		 * @protected
10207		 */
10208		this._supress = {};
10209
10210		/**
10211		 * Absolute current position.
10212		 * @protected
10213		 */
10214		this._current = null;
10215
10216		/**
10217		 * Animation speed in milliseconds.
10218		 * @protected
10219		 */
10220		this._speed = null;
10221
10222		/**
10223		 * Coordinates of all items in pixel.
10224		 * @todo The name of this member is missleading.
10225		 * @protected
10226		 */
10227		this._coordinates = [];
10228
10229		/**
10230		 * Current breakpoint.
10231		 * @todo Real media queries would be nice.
10232		 * @protected
10233		 */
10234		this._breakpoint = null;
10235
10236		/**
10237		 * Current width of the plugin element.
10238		 */
10239		this._width = null;
10240
10241		/**
10242		 * All real items.
10243		 * @protected
10244		 */
10245		this._items = [];
10246
10247		/**
10248		 * All cloned items.
10249		 * @protected
10250		 */
10251		this._clones = [];
10252
10253		/**
10254		 * Merge values of all items.
10255		 * @todo Maybe this could be part of a plugin.
10256		 * @protected
10257		 */
10258		this._mergers = [];
10259
10260		/**
10261		 * Widths of all items.
10262		 */
10263		this._widths = [];
10264
10265		/**
10266		 * Invalidated parts within the update process.
10267		 * @protected
10268		 */
10269		this._invalidated = {};
10270
10271		/**
10272		 * Ordered list of workers for the update process.
10273		 * @protected
10274		 */
10275		this._pipe = [];
10276
10277		/**
10278		 * Current state information for the drag operation.
10279		 * @todo #261
10280		 * @protected
10281		 */
10282		this._drag = {
10283			time: null,
10284			target: null,
10285			pointer: null,
10286			stage: {
10287				start: null,
10288				current: null
10289			},
10290			direction: null
10291		};
10292
10293		/**
10294		 * Current state information and their tags.
10295		 * @type {Object}
10296		 * @protected
10297		 */
10298		this._states = {
10299			current: {},
10300			tags: {
10301				'initializing': [ 'busy' ],
10302				'animating': [ 'busy' ],
10303				'dragging': [ 'interacting' ]
10304			}
10305		};
10306
10307		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
10308			this._handlers[handler] = $.proxy(this[handler], this);
10309		}, this));
10310
10311		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
10312			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
10313				= new plugin(this);
10314		}, this));
10315
10316		$.each(Owl.Workers, $.proxy(function(priority, worker) {
10317			this._pipe.push({
10318				'filter': worker.filter,
10319				'run': $.proxy(worker.run, this)
10320			});
10321		}, this));
10322
10323		this.setup();
10324		this.initialize();
10325	}
10326
10327	/**
10328	 * Default options for the carousel.
10329	 * @public
10330	 */
10331	Owl.Defaults = {
10332		items: 3,
10333		loop: false,
10334		center: false,
10335		rewind: false,
10336
10337		mouseDrag: true,
10338		touchDrag: true,
10339		pullDrag: true,
10340		freeDrag: false,
10341
10342		margin: 0,
10343		stagePadding: 0,
10344
10345		merge: false,
10346		mergeFit: true,
10347		autoWidth: false,
10348
10349		startPosition: 0,
10350		rtl: false,
10351
10352		smartSpeed: 250,
10353		fluidSpeed: false,
10354		dragEndSpeed: false,
10355
10356		responsive: {},
10357		responsiveRefreshRate: 200,
10358		responsiveBaseElement: window,
10359
10360		fallbackEasing: 'swing',
10361
10362		info: false,
10363
10364		nestedItemSelector: false,
10365		itemElement: 'div',
10366		stageElement: 'div',
10367
10368		refreshClass: 'owl-refresh',
10369		loadedClass: 'owl-loaded',
10370		loadingClass: 'owl-loading',
10371		rtlClass: 'owl-rtl',
10372		responsiveClass: 'owl-responsive',
10373		dragClass: 'owl-drag',
10374		itemClass: 'owl-item',
10375		stageClass: 'owl-stage',
10376		stageOuterClass: 'owl-stage-outer',
10377		grabClass: 'owl-grab'
10378	};
10379
10380	/**
10381	 * Enumeration for width.
10382	 * @public
10383	 * @readonly
10384	 * @enum {String}
10385	 */
10386	Owl.Width = {
10387		Default: 'default',
10388		Inner: 'inner',
10389		Outer: 'outer'
10390	};
10391
10392	/**
10393	 * Enumeration for types.
10394	 * @public
10395	 * @readonly
10396	 * @enum {String}
10397	 */
10398	Owl.Type = {
10399		Event: 'event',
10400		State: 'state'
10401	};
10402
10403	/**
10404	 * Contains all registered plugins.
10405	 * @public
10406	 */
10407	Owl.Plugins = {};
10408
10409	/**
10410	 * List of workers involved in the update process.
10411	 */
10412	Owl.Workers = [ {
10413		filter: [ 'width', 'settings' ],
10414		run: function() {
10415			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
10416			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
10417		}
10418	}, {
10419		filter: [ 'width', 'items', 'settings' ],
10420		run: function(cache) {
10421			cache.current = this._items && this._items[this.relative(this._current)];
10422		}
10423	}, {
10424		filter: [ 'items', 'settings' ],
10425		run: function() {
10426			this.$stage.children('.cloned').remove();
10427		}
10428	}, {
10429		filter: [ 'width', 'items', 'settings' ],
10430		run: function(cache) {
10431			var margin = this.settings.margin || '',
10432				grid = !this.settings.autoWidth,
10433				rtl = this.settings.rtl,
10434				css = {
10435					'width': 'auto',
10436					'margin-left': rtl ? margin : '',
10437					'margin-right': rtl ? '' : margin
10438				};
10439
10440			!grid && this.$stage.children().css(css);
10441
10442			cache.css = css;
10443		}
10444	}, {
10445		filter: [ 'width', 'items', 'settings' ],
10446		run: function(cache) {
10447			var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
10448				merge = null,
10449				iterator = this._items.length,
10450				grid = !this.settings.autoWidth,
10451				widths = [];
10452
10453			cache.items = {
10454				merge: false,
10455				width: width
10456			};
10457
10458			while (iterator--) {
10459				merge = this._mergers[iterator];
10460				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
10461
10462				cache.items.merge = merge > 1 || cache.items.merge;
10463
10464				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
10465			}
10466
10467			this._widths = widths;
10468		}
10469	}, {
10470		filter: [ 'items', 'settings' ],
10471		run: function() {
10472			var clones = [],
10473				items = this._items,
10474				settings = this.settings,
10475				view = Math.max(settings.items * 2, 4),
10476				size = Math.ceil(items.length / 2) * 2,
10477				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
10478				append = '',
10479				prepend = '';
10480
10481			repeat /= 2;
10482
10483			while (repeat--) {
10484				clones.push(this.normalize(clones.length / 2, true));
10485				append = append + items[clones[clones.length - 1]][0].outerHTML;
10486				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
10487				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
10488			}
10489
10490			this._clones = clones;
10491
10492			// var appendVideo = $(append).find('.uncode-video-container');
10493			// if (appendVideo.length) {
10494			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
10495			// }
10496			// var prependVideo = $(prepend).find('.uncode-video-container');
10497			// if (prependVideo.length) {
10498			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
10499			// }
10500			$(append).addClass('cloned').appendTo(this.$stage);
10501			$(prepend).addClass('cloned').prependTo(this.$stage);
10502		}
10503	}, {
10504		filter: [ 'width', 'items', 'settings' ],
10505		run: function() {
10506			var rtl = this.settings.rtl ? 1 : -1,
10507				size = this._clones.length + this._items.length,
10508				iterator = -1,
10509				previous = 0,
10510				current = 0,
10511				coordinates = [];
10512
10513			while (++iterator < size) {
10514				previous = coordinates[iterator - 1] || 0;
10515				current = this._widths[this.relative(iterator)] + this.settings.margin;
10516				coordinates.push(previous + current * rtl);
10517			}
10518
10519			this._coordinates = coordinates;
10520		}
10521	}, {
10522		filter: [ 'width', 'items', 'settings' ],
10523		run: function() {
10524			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
10525				padding = stagePadding,
10526				coordinates = this._coordinates,
10527				css = {
10528					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
10529					'padding-left': padding || '',
10530					'padding-right': padding || ''
10531				};
10532
10533			this.$stage.css(css);
10534		}
10535	}, {
10536		filter: [ 'width', 'items', 'settings' ],
10537		run: function(cache) {
10538			var iterator = this._coordinates.length,
10539				grid = !this.settings.autoWidth,
10540				items = this.$stage.children();
10541
10542			if (grid && cache.items.merge) {
10543				while (iterator--) {
10544					cache.css.width = this._widths[this.relative(iterator)];
10545					items.eq(iterator).css(cache.css);
10546				}
10547			} else if (grid) {
10548				cache.css.width = cache.items.width;
10549				items.css(cache.css);
10550			}
10551		}
10552	}, {
10553		filter: [ 'items' ],
10554		run: function() {
10555			this._coordinates.length < 1 && this.$stage.removeAttr('style');
10556		}
10557	}, {
10558		filter: [ 'width', 'items', 'settings' ],
10559		run: function(cache) {
10560			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
10561			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
10562			this.reset(cache.current);
10563		}
10564	}, {
10565		filter: [ 'position' ],
10566		run: function() {
10567			this.animate(this.coordinates(this._current));
10568		}
10569	}, {
10570		filter: [ 'width', 'position', 'items', 'settings' ],
10571		run: function() {
10572			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
10573				rtl = this.settings.rtl ? 1 : -1,
10574				padding = this.settings.stagePadding * 2,
10575				begin = this.coordinates(this.current()) + padding,
10576				end = begin + this.width() * rtl,
10577				inner, outer, matches = [], i, n;
10578
10579			for (i = 0, n = this._coordinates.length; i < n; i++) {
10580				inner = this._coordinates[i - 1] || 0;
10581				outer = Math.abs(this._coordinates[i]) + padding * rtl;
10582
10583				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
10584					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
10585					matches.push(i);
10586				}
10587			}
10588
10589			this.$stage.children('.active').removeClass('active');
10590			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
10591
10592			if (this.settings.center) {
10593				this.$stage.children('.center').removeClass('center');
10594				this.$stage.children().eq(this.current()).addClass('center');
10595			}
10596		}
10597	} ];
10598
10599	/**
10600	 * Initializes the carousel.
10601	 * @protected
10602	 */
10603	Owl.prototype.initialize = function() {
10604		this.enter('initializing');
10605		this.trigger('initialize');
10606
10607		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
10608
10609		if (this.settings.autoWidth && !this.is('pre-loading')) {
10610			var imgs, nestedSelector, width;
10611			imgs = this.$element.find('img');
10612			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
10613			width = this.$element.children(nestedSelector).width();
10614
10615			if (imgs.length && width <= 0) {
10616				this.preloadAutoWidthImages(imgs);
10617			}
10618		}
10619
10620		this.$element.addClass(this.options.loadingClass);
10621
10622		// create stage
10623		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
10624			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
10625
10626		// append stage
10627		this.$element.append(this.$stage.parent());
10628
10629		// append content
10630		this.replace(this.$element.children().not(this.$stage.parent()));
10631
10632		// check visibility
10633		if (this.$element.is(':visible')) {
10634			// update view
10635			this.refresh();
10636		} else {
10637			// invalidate width
10638			this.invalidate('width');
10639		}
10640
10641		this.$element
10642			.removeClass(this.options.loadingClass)
10643			.addClass(this.options.loadedClass);
10644
10645		// register event handlers
10646		this.registerEventHandlers();
10647
10648		this.leave('initializing');
10649		this.trigger('initialized');
10650	};
10651
10652	/**
10653	 * Setups the current settings.
10654	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
10655	 * @todo Support for media queries by using `matchMedia` would be nice.
10656	 * @public
10657	 */
10658	Owl.prototype.setup = function() {
10659		var viewport = this.viewport(),
10660			overwrites = this.options.responsive,
10661			match = -1,
10662			settings = null;
10663
10664		if (!overwrites) {
10665			settings = $.extend({}, this.options);
10666		} else {
10667			$.each(overwrites, function(breakpoint) {
10668				if (breakpoint <= viewport && breakpoint > match) {
10669					match = Number(breakpoint);
10670				}
10671			});
10672
10673			settings = $.extend({}, this.options, overwrites[match]);
10674			delete settings.responsive;
10675
10676			// responsive class
10677			if (settings.responsiveClass) {
10678				this.$element.attr('class',
10679					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
10680				);
10681			}
10682		}
10683
10684		if (this.settings === null || this._breakpoint !== match) {
10685			this.trigger('change', { property: { name: 'settings', value: settings } });
10686			this._breakpoint = match;
10687			this.settings = settings;
10688			this.invalidate('settings');
10689			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
10690		}
10691	};
10692
10693	/**
10694	 * Updates option logic if necessery.
10695	 * @protected
10696	 */
10697	Owl.prototype.optionsLogic = function() {
10698		if (this.settings.autoWidth) {
10699			this.settings.stagePadding = false;
10700			this.settings.merge = false;
10701		}
10702	};
10703
10704	/**
10705	 * Prepares an item before add.
10706	 * @todo Rename event parameter `content` to `item`.
10707	 * @protected
10708	 * @returns {jQuery|HTMLElement} - The item container.
10709	 */
10710	Owl.prototype.prepare = function(item, index) {
10711		var event = this.trigger('prepare', { content: item });
10712		if (!event.data) {
10713			event.data = $('<' + this.settings.itemElement + '/>')
10714				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
10715		}
10716
10717		this.trigger('prepared', { content: event.data });
10718
10719		return event.data;
10720	};
10721
10722	/**
10723	 * Updates the view.
10724	 * @public
10725	 */
10726	Owl.prototype.update = function() {
10727		var i = 0,
10728			n = this._pipe.length,
10729			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
10730			cache = {};
10731
10732		while (i < n) {
10733			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
10734				this._pipe[i].run(cache);
10735			}
10736			i++;
10737		}
10738
10739		this._invalidated = {};
10740
10741		!this.is('valid') && this.enter('valid');
10742	};
10743
10744	/**
10745	 * Gets the width of the view.
10746	 * @public
10747	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
10748	 * @returns {Number} - The width of the view in pixel.
10749	 */
10750	Owl.prototype.width = function(dimension) {
10751		dimension = dimension || Owl.Width.Default;
10752		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
10753		switch (dimension) {
10754			case Owl.Width.Inner:
10755			case Owl.Width.Outer:
10756				return this._width;
10757			default:
10758				return this._width - stagePadding * 2 + this.settings.margin;
10759		}
10760	};
10761
10762	/**
10763	 * Refreshes the carousel primarily for adaptive purposes.
10764	 * @public
10765	 */
10766	Owl.prototype.refresh = function() {
10767		this.enter('refreshing');
10768		this.trigger('refresh');
10769
10770		this.setup();
10771
10772		this.optionsLogic();
10773
10774		this.$element.addClass(this.options.refreshClass);
10775
10776		this.update();
10777
10778		this.$element.removeClass(this.options.refreshClass);
10779
10780		this.leave('refreshing');
10781		this.trigger('refreshed');
10782	};
10783
10784	/**
10785	 * Checks window `resize` event.
10786	 * @protected
10787	 */
10788	Owl.prototype.onThrottledResize = function() {
10789		window.clearTimeout(this.resizeTimer);
10790		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
10791	};
10792
10793	/**
10794	 * Checks window `resize` event.
10795	 * @protected
10796	 */
10797	Owl.prototype.onResize = function() {
10798		if (!this._items.length) {
10799			return false;
10800		}
10801
10802		if (this._width === this.$element.width()) {
10803			return false;
10804		}
10805
10806		if (!this.$element.is(':visible')) {
10807			return false;
10808		}
10809
10810		this.enter('resizing');
10811
10812		if (this.trigger('resize').isDefaultPrevented()) {
10813			this.leave('resizing');
10814			return false;
10815		}
10816
10817		this.invalidate('width');
10818
10819		this.refresh();
10820
10821		this.leave('resizing');
10822		this.trigger('resized');
10823	};
10824
10825	/**
10826	 * Registers event handlers.
10827	 * @todo Check `msPointerEnabled`
10828	 * @todo #261
10829	 * @protected
10830	 */
10831	Owl.prototype.registerEventHandlers = function() {
10832		if ($.support.transition) {
10833			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
10834		}
10835
10836		if (this.settings.responsive !== false) {
10837			this.on(window, 'resize', this._handlers.onThrottledResize);
10838		}
10839
10840		if (this.settings.mouseDrag) {
10841			this.$element.addClass(this.options.dragClass);
10842			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
10843			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
10844		}
10845
10846		if (this.settings.touchDrag){
10847			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
10848			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
10849		}
10850	};
10851
10852	/**
10853	 * Handles `touchstart` and `mousedown` events.
10854	 * @todo Horizontal swipe threshold as option
10855	 * @todo #261
10856	 * @protected
10857	 * @param {Event} event - The event arguments.
10858	 */
10859	Owl.prototype.onDragStart = function(event) {
10860		var stage = null;
10861
10862		if (event.which === 3) {
10863			return;
10864		}
10865
vendor: 9,106 bytes, lines 10866-11181
10866		if ($.support.transform) {
10867			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
10868			stage = {
10869				x: stage[stage.length === 16 ? 12 : 4],
10870				y: stage[stage.length === 16 ? 13 : 5]
10871			};
10872		} else {
10873			stage = this.$stage.position();
10874			stage = {
10875				x: this.settings.rtl ?
10876					stage.left + this.$stage.width() - this.width() + this.settings.margin :
10877					stage.left,
10878				y: stage.top
10879			};
10880		}
10881
10882		if (this.is('animating')) {
10883			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
10884			this.invalidate('position');
10885		}
10886
10887		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
10888
10889		this.speed(0);
10890
10891		this._drag.time = new Date().getTime();
10892		this._drag.target = $(event.target);
10893		this._drag.stage.start = stage;
10894		this._drag.stage.current = stage;
10895		this._drag.pointer = this.pointer(event);
10896
10897		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
10898
10899		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
10900			var delta = this.difference(this._drag.pointer, this.pointer(event));
10901
10902			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
10903
10904			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
10905				return;
10906			}
10907
10908			event.preventDefault();
10909
10910			this.enter('dragging');
10911			this.trigger('drag');
10912		}, this));
10913	};
10914
10915	/**
10916	 * Handles the `touchmove` and `mousemove` events.
10917	 * @todo #261
10918	 * @protected
10919	 * @param {Event} event - The event arguments.
10920	 */
10921	Owl.prototype.onDragMove = function(event) {
10922		var minimum = null,
10923			maximum = null,
10924			pull = null,
10925			delta = this.difference(this._drag.pointer, this.pointer(event)),
10926			stage = this.difference(this._drag.stage.start, delta);
10927
10928		if (!this.is('dragging')) {
10929			return;
10930		}
10931
10932		event.preventDefault();
10933
10934		if (this.settings.loop) {
10935			minimum = this.coordinates(this.minimum());
10936			maximum = this.coordinates(this.maximum() + 1) - minimum;
10937			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
10938		} else {
10939			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
10940			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
10941			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
10942			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
10943		}
10944
10945		this._drag.stage.current = stage;
10946
10947		this.animate(stage.x);
10948	};
10949
10950	/**
10951	 * Handles the `touchend` and `mouseup` events.
10952	 * @todo #261
10953	 * @todo Threshold for click event
10954	 * @protected
10955	 * @param {Event} event - The event arguments.
10956	 */
10957	Owl.prototype.onDragEnd = function(event) {
10958		var delta = this.difference(this._drag.pointer, this.pointer(event)),
10959			stage = this._drag.stage.current,
10960			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
10961
10962		$(document).off('.owl.core');
10963
10964		this.$element.removeClass(this.options.grabClass);
10965
10966		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
10967			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
10968			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
10969			this.invalidate('position');
10970			this.update();
10971
10972			this._drag.direction = direction;
10973
10974			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
10975				this._drag.target.one('click.owl.core', function() { return false; });
10976			}
10977		}
10978
10979		if (!this.is('dragging')) {
10980			return;
10981		}
10982
10983		this.leave('dragging');
10984		this.trigger('dragged');
10985	};
10986
10987	/**
10988	 * Gets absolute position of the closest item for a coordinate.
10989	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
10990	 * @protected
10991	 * @param {Number} coordinate - The coordinate in pixel.
10992	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
10993	 * @return {Number} - The absolute position of the closest item.
10994	 */
10995	Owl.prototype.closest = function(coordinate, direction) {
10996		var position = -1,
10997			pull = 30,
10998			width = this.width(),
10999			coordinates = this.coordinates();
11000
11001		if (!this.settings.freeDrag) {
11002			// check closest item
11003			$.each(coordinates, $.proxy(function(index, value) {
11004				if (coordinate > value - pull && coordinate < value + pull) {
11005					position = index;
11006				} else if (this.op(coordinate, '<', value)
11007					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
11008					position = direction === 'left' ? index + 1 : index;
11009				}
11010				return position === -1;
11011			}, this));
11012		}
11013
11014		if (!this.settings.loop) {
11015			// non loop boundries
11016			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
11017				position = coordinate = this.minimum();
11018			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
11019				position = coordinate = this.maximum();
11020			}
11021		}
11022
11023		return position;
11024	};
11025
11026	/**
11027	 * Animates the stage.
11028	 * @todo #270
11029	 * @public
11030	 * @param {Number} coordinate - The coordinate in pixels.
11031	 */
11032	Owl.prototype.animate = function(coordinate) {
11033		var animate = this.speed() > 0;
11034
11035		this.is('animating') && this.onTransitionEnd();
11036
11037		if (animate) {
11038			this.enter('animating');
11039			this.trigger('translate');
11040		}
11041
11042		if ($.support.transform3d && $.support.transition) {
11043			this.$stage.css({
11044				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
11045				transition: (this.speed() / 1000) + 's'
11046			});
11047		} else if (animate) {
11048			this.$stage.animate({
11049				left: coordinate + 'px'
11050			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
11051		} else {
11052			this.$stage.css({
11053				left: coordinate + 'px'
11054			});
11055		}
11056	};
11057
11058	/**
11059	 * Checks whether the carousel is in a specific state or not.
11060	 * @param {String} state - The state to check.
11061	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
11062	 */
11063	Owl.prototype.is = function(state) {
11064		return this._states.current[state] && this._states.current[state] > 0;
11065	};
11066
11067	/**
11068	 * Sets the absolute position of the current item.
11069	 * @public
11070	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
11071	 * @returns {Number} - The absolute position of the current item.
11072	 */
11073	Owl.prototype.current = function(position) {
11074		if (position === undefined) {
11075			return this._current;
11076		}
11077
11078		if (this._items.length === 0) {
11079			return undefined;
11080		}
11081
11082		position = this.normalize(position);
11083
11084		if (this._current !== position) {
11085			var event = this.trigger('change', { property: { name: 'position', value: position } });
11086
11087			if (event.data !== undefined) {
11088				position = this.normalize(event.data);
11089			}
11090
11091			this._current = position;
11092
11093			this.invalidate('position');
11094
11095			this.trigger('changed', { property: { name: 'position', value: this._current } });
11096		}
11097
11098		return this._current;
11099	};
11100
11101	/**
11102	 * Invalidates the given part of the update routine.
11103	 * @param {String} [part] - The part to invalidate.
11104	 * @returns {Array.<String>} - The invalidated parts.
11105	 */
11106	Owl.prototype.invalidate = function(part) {
11107		if ($.type(part) === 'string') {
11108			this._invalidated[part] = true;
11109			this.is('valid') && this.leave('valid');
11110		}
11111		return $.map(this._invalidated, function(v, i) { return i });
11112	};
11113
11114	/**
11115	 * Resets the absolute position of the current item.
11116	 * @public
11117	 * @param {Number} position - The absolute position of the new item.
11118	 */
11119	Owl.prototype.reset = function(position) {
11120		position = this.normalize(position);
11121
11122		if (position === undefined) {
11123			return;
11124		}
11125
11126		this._speed = 0;
11127		this._current = position;
11128
11129		this.suppress([ 'translate', 'translated' ]);
11130
11131		this.animate(this.coordinates(position));
11132
11133		this.release([ 'translate', 'translated' ]);
11134	};
11135
11136	/**
11137	 * Normalizes an absolute or a relative position of an item.
11138	 * @public
11139	 * @param {Number} position - The absolute or relative position to normalize.
11140	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
11141	 * @returns {Number} - The normalized position.
11142	 */
11143	Owl.prototype.normalize = function(position, relative) {
11144		var n = this._items.length,
11145			m = relative ? 0 : this._clones.length;
11146
11147		if (!$.isNumeric(position) || n < 1) {
11148			position = undefined;
11149		} else if (position < 0 || position >= n + m) {
11150			position = ((position - m / 2) % n + n) % n + m / 2;
11151		}
11152
11153		return position;
11154	};
11155
11156	/**
11157	 * Converts an absolute position of an item into a relative one.
11158	 * @public
11159	 * @param {Number} position - The absolute position to convert.
11160	 * @returns {Number} - The converted position.
11161	 */
11162	Owl.prototype.relative = function(position) {
11163		position -= this._clones.length / 2;
11164		return this.normalize(position, true);
11165	};
11166
11167	/**
11168	 * Gets the maximum position for the current item.
11169	 * @public
11170	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
11171	 * @returns {Number}
11172	 */
11173	Owl.prototype.maximum = function(relative) {
11174		var settings = this.settings,
11175			maximum = this._coordinates.length,
11176			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
11177			i = -1, j;
11178
11179		if (settings.loop) {
11180			maximum = this._clones.length / 2 + this._items.length - 1;
11181		} else if (settings.autoWidth || settings.merge) {
11182			// binary search
11183			while (maximum - i > 1) {
11184				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
11185					? i = j : maximum = j;
11186			}
11187		} else if (settings.center) {
11188			maximum = this._items.length - 1;
11189		} else {
11190			maximum = this._items.length - settings.items;
11191		}
11192
11193		if (relative) {
11194			maximum -= this._clones.length / 2;
11195		}
11196
11197		return Math.max(maximum, 0);
11198	};
11199
11200	/**
11201	 * Gets the minimum position for the current item.
11202	 * @public
11203	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
11204	 * @returns {Number}
11205	 */
11206	Owl.prototype.minimum = function(relative) {
11207		return relative ? 0 : this._clones.length / 2;
11208	};
11209
11210	/**
11211	 * Gets an item at the specified relative position.
11212	 * @public
11213	 * @param {Number} [position] - The relative position of the item.
11214	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
11215	 */
11216	Owl.prototype.items = function(position) {
11217		if (position === undefined) {
11218			return this._items.slice();
11219		}
11220
11221		position = this.normalize(position, true);
11222		return this._items[position];
11223	};
11224
11225	/**
11226	 * Gets an item at the specified relative position.
11227	 * @public
11228	 * @param {Number} [position] - The relative position of the item.
11229	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
11230	 */
11231	Owl.prototype.mergers = function(position) {
11232		if (position === undefined) {
11233			return this._mergers.slice();
11234		}
11235
11236		position = this.normalize(position, true);
11237		return this._mergers[position];
11238	};
11239
11240	/**
11241	 * Gets the absolute positions of clones for an item.
11242	 * @public
11243	 * @param {Number} [position] - The relative position of the item.
11244	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
11245	 */
11246	Owl.prototype.clones = function(position) {
11247		var odd = this._clones.length / 2,
11248			even = odd + this._items.length,
11249			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
11250
11251		if (position === undefined) {
11252			return $.map(this._clones, function(v, i) { return map(i) });
11253		}
11254
11255		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
11256	};
11257
11258	/**
11259	 * Sets the current animation speed.
11260	 * @public
11261	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
11262	 * @returns {Number} - The current animation speed in milliseconds.
11263	 */
11264	Owl.prototype.speed = function(speed) {
11265		if (speed !== undefined) {
11266			this._speed = speed;
11267		}
11268
11269		return this._speed;
11270	};
11271
11272	/**
11273	 * Gets the coordinate of an item.
11274	 * @todo The name of this method is missleanding.
11275	 * @public
11276	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
11277	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
11278	 */
11279	Owl.prototype.coordinates = function(position) {
11280		var coordinate = null;
11281
11282		if (position === undefined) {
11283			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
11284				return this.coordinates(index);
11285			}, this));
11286		}
11287
11288		if (this.settings.center) {
11289			coordinate = this._coordinates[position];
11290			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
11291		} else {
11292			coordinate = this._coordinates[position - 1] || 0;
11293		}
11294
11295		return coordinate;
11296	};
11297
11298	/**
11299	 * Calculates the speed for a translation.
11300	 * @protected
11301	 * @param {Number} from - The absolute position of the start item.
11302	 * @param {Number} to - The absolute position of the target item.
11303	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
11304	 * @returns {Number} - The time in milliseconds for the translation.
11305	 */
11306	Owl.prototype.duration = function(from, to, factor) {
11307		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
11308	};
11309
11310	/**
11311	 * Slides to the specified item.
11312	 * @public
11313	 * @param {Number} position - The position of the item.
11314	 * @param {Number} [speed] - The time in milliseconds for the transition.
11315	 */
11316	Owl.prototype.to = function(position, speed) {
11317		var current = this.current(),
11318			revert = null,
11319			distance = position - this.relative(current),
11320			direction = (distance > 0) - (distance < 0),
11321			items = this._items.length,
11322			minimum = this.minimum(),
11323			maximum = this.maximum();
11324
11325		if (this.settings.loop) {
11326			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
11327				distance += direction * -1 * items;
11328			}
11329
11330			position = current + distance;
11331			revert = ((position - minimum) % items + items) % items + minimum;
11332
11333			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
11334				current = revert - distance;
11335				position = revert;
11336				this.reset(current);
11337			}
11338		} else if (this.settings.rewind) {
11339			maximum += 1;
11340			position = (position % maximum + maximum) % maximum;
11341		} else {
11342			position = Math.max(minimum, Math.min(maximum, position));
11343		}
11344
11345		this.speed(this.duration(current, position, speed));
11346		this.current(position);
11347
11348		if (this.$element.is(':visible')) {
11349			this.update();
11350		}
11351	};
11352
11353	/**
11354	 * Slides to the next item.
11355	 * @public
11356	 * @param {Number}
vendor: 12,284 bytes, lines 11356-11776
11356 [speed] - The time in milliseconds for the transition.
11357	 */
11358	Owl.prototype.next = function(speed) {
11359		speed = speed || false;
11360		this.to(this.relative(this.current()) + 1, speed);
11361	};
11362
11363	/**
11364	 * Slides to the previous item.
11365	 * @public
11366	 * @param {Number} [speed] - The time in milliseconds for the transition.
11367	 */
11368	Owl.prototype.prev = function(speed) {
11369		speed = speed || false;
11370		this.to(this.relative(this.current()) - 1, speed);
11371	};
11372
11373	/**
11374	 * Handles the end of an animation.
11375	 * @protected
11376	 * @param {Event} event - The event arguments.
11377	 */
11378	Owl.prototype.onTransitionEnd = function(event) {
11379
11380		// if css2 animation then event object is undefined
11381		if (event !== undefined) {
11382			event.stopPropagation();
11383
11384			// Catch only owl-stage transitionEnd event
11385			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
11386				return false;
11387			}
11388		}
11389
11390		this.leave('animating');
11391		this.trigger('translated');
11392	};
11393
11394	/**
11395	 * Gets viewport width.
11396	 * @protected
11397	 * @return {Number} - The width in pixel.
11398	 */
11399	Owl.prototype.viewport = function() {
11400		var width;
11401		if (this.options.responsiveBaseElement !== window) {
11402			width = $(this.options.responsiveBaseElement).width();
11403		} else if (window.innerWidth) {
11404			width = window.innerWidth;
11405		} else if (document.documentElement && document.documentElement.clientWidth) {
11406			width = document.documentElement.clientWidth;
11407		} else {
11408			throw 'Can not detect viewport width.';
11409		}
11410
11411		return width;
11412	};
11413
11414	/**
11415	 * Replaces the current content.
11416	 * @public
11417	 * @param {HTMLElement|jQuery|String} content - The new content.
11418	 */
11419	Owl.prototype.replace = function(content) {
11420		this.$stage.empty();
11421		this._items = [];
11422
11423		if (content) {
11424			content = (content instanceof jQuery) ? content : $(content);
11425		}
11426
11427		if (this.settings.nestedItemSelector) {
11428			content = content.find('.' + this.settings.nestedItemSelector);
11429		}
11430
11431		content.filter(function() {
11432			return this.nodeType === 1;
11433		}).each($.proxy(function(index, item) {
11434			item = this.prepare(item, index);
11435			this.$stage.append(item);
11436			this._items.push(item);
11437			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
11438		}, this));
11439
11440		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
11441
11442		this.invalidate('items');
11443	};
11444
11445	/**
11446	 * Adds an item.
11447	 * @todo Use `item` instead of `content` for the event arguments.
11448	 * @public
11449	 * @param {HTMLElement|jQuery|String} content - The item content to add.
11450	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
11451	 */
11452	Owl.prototype.add = function(content, position) {
11453		var current = this.relative(this._current);
11454
11455		position = position === undefined ? this._items.length : this.normalize(position, true);
11456		content = content instanceof jQuery ? content : $(content);
11457
11458		this.trigger('add', { content: content, position: position });
11459
11460		content = this.prepare(content, this._items[current].index());
11461
11462		if (this._items.length === 0 || position === this._items.length) {
11463			this._items.length === 0 && this.$stage.append(content);
11464			this._items.length !== 0 && this._items[position - 1].after(content);
11465			this._items.push(content);
11466			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
11467		} else {
11468			this._items[position].before(content);
11469			this._items.splice(position, 0, content);
11470			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
11471		}
11472
11473		this._items[current] && this.reset(this._items[current].index());
11474
11475		this.invalidate('items');
11476
11477		this.trigger('added', { content: content, position: position });
11478	};
11479
11480	/**
11481	 * Removes an item by its position.
11482	 * @todo Use `item` instead of `content` for the event arguments.
11483	 * @public
11484	 * @param {Number} position - The relative position of the item to remove.
11485	 */
11486	Owl.prototype.remove = function(position) {
11487		position = this.normalize(position, true);
11488
11489		if (position === undefined) {
11490			return;
11491		}
11492
11493		this.trigger('remove', { content: this._items[position], position: position });
11494
11495		this._items[position].remove();
11496		this._items.splice(position, 1);
11497		this._mergers.splice(position, 1);
11498
11499		this.invalidate('items');
11500
11501		this.trigger('removed', { content: null, position: position });
11502	};
11503
11504	/**
11505	 * Preloads images with auto width.
11506	 * @todo Replace by a more generic approach
11507	 * @protected
11508	 */
11509	Owl.prototype.preloadAutoWidthImages = function(images) {
11510		images.each($.proxy(function(i, element) {
11511			this.enter('pre-loading');
11512			element = $(element);
11513			$(new Image()).one('load', $.proxy(function(e) {
11514				element.attr('src', e.target.src);
11515				element.css('opacity', 1);
11516				this.leave('pre-loading');
11517				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
11518			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
11519		}, this));
11520	};
11521
11522	/**
11523	 * Destroys the carousel.
11524	 * @public
11525	 */
11526	Owl.prototype.destroy = function() {
11527
11528		this.$element.off('.owl.core');
11529		this.$stage.off('.owl.core');
11530		$(document).off('.owl.core');
11531
11532		if (this.settings.responsive !== false) {
11533			window.clearTimeout(this.resizeTimer);
11534			this.off(window, 'resize', this._handlers.onThrottledResize);
11535		}
11536
11537		for (var i in this._plugins) {
11538			this._plugins[i].destroy();
11539		}
11540
11541		this.$stage.children('.cloned').remove();
11542
11543		this.$stage.unwrap();
11544		this.$stage.children().contents().unwrap();
11545		this.$stage.children().unwrap();
11546
11547		this.$element
11548			.removeClass(this.options.refreshClass)
11549			.removeClass(this.options.loadingClass)
11550			.removeClass(this.options.loadedClass)
11551			.removeClass(this.options.rtlClass)
11552			.removeClass(this.options.dragClass)
11553			.removeClass(this.options.grabClass)
11554			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
11555			.removeData('owl.carousel');
11556	};
11557
11558	/**
11559	 * Operators to calculate right-to-left and left-to-right.
11560	 * @protected
11561	 * @param {Number} [a] - The left side operand.
11562	 * @param {String} [o] - The operator.
11563	 * @param {Number} [b] - The right side operand.
11564	 */
11565	Owl.prototype.op = function(a, o, b) {
11566		var rtl = this.settings.rtl;
11567		switch (o) {
11568			case '<':
11569				return rtl ? a > b : a < b;
11570			case '>':
11571				return rtl ? a < b : a > b;
11572			case '>=':
11573				return rtl ? a <= b : a >= b;
11574			case '<=':
11575				return rtl ? a >= b : a <= b;
11576			default:
11577				break;
11578		}
11579	};
11580
11581	/**
11582	 * Attaches to an internal event.
11583	 * @protected
11584	 * @param {HTMLElement} element - The event source.
11585	 * @param {String} event - The event name.
11586	 * @param {Function} listener - The event handler to attach.
11587	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
11588	 */
11589	Owl.prototype.on = function(element, event, listener, capture) {
11590		if (element.addEventListener) {
11591			element.addEventListener(event, listener, capture);
11592		} else if (element.attachEvent) {
11593			element.attachEvent('on' + event, listener);
11594		}
11595	};
11596
11597	/**
11598	 * Detaches from an internal event.
11599	 * @protected
11600	 * @param {HTMLElement} element - The event source.
11601	 * @param {String} event - The event name.
11602	 * @param {Function} listener - The attached event handler to detach.
11603	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
11604	 */
11605	Owl.prototype.off = function(element, event, listener, capture) {
11606		if (element.removeEventListener) {
11607			element.removeEventListener(event, listener, capture);
11608		} else if (element.detachEvent) {
11609			element.detachEvent('on' + event, listener);
11610		}
11611	};
11612
11613	/**
11614	 * Triggers a public event.
11615	 * @todo Remove `status`, `relatedTarget` should be used instead.
11616	 * @protected
11617	 * @param {String} name - The event name.
11618	 * @param {*} [data=null] - The event data.
11619	 * @param {String} [namespace=carousel] - The event namespace.
11620	 * @param {String} [state] - The state which is associated with the event.
11621	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
11622	 * @returns {Event} - The event arguments.
11623	 */
11624	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
11625		var status = {
11626			item: { count: this._items.length, index: this.current() }
11627		}, handler = $.camelCase(
11628			$.grep([ 'on', name, namespace ], function(v) { return v })
11629				.join('-').toLowerCase()
11630		), event = $.Event(
11631			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
11632			$.extend({ relatedTarget: this }, status, data)
11633		);
11634
11635		if (!this._supress[name]) {
11636			$.each(this._plugins, function(name, plugin) {
11637				if (plugin.onTrigger) {
11638					plugin.onTrigger(event);
11639				}
11640			});
11641
11642			this.register({ type: Owl.Type.Event, name: name });
11643			this.$element.trigger(event);
11644
11645			if (this.settings && typeof this.settings[handler] === 'function') {
11646				this.settings[handler].call(this, event);
11647			}
11648		}
11649
11650		return event;
11651	};
11652
11653	/**
11654	 * Enters a state.
11655	 * @param name - The state name.
11656	 */
11657	Owl.prototype.enter = function(name) {
11658		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
11659			if (this._states.current[name] === undefined) {
11660				this._states.current[name] = 0;
11661			}
11662
11663			this._states.current[name]++;
11664		}, this));
11665	};
11666
11667	/**
11668	 * Leaves a state.
11669	 * @param name - The state name.
11670	 */
11671	Owl.prototype.leave = function(name) {
11672		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
11673			this._states.current[name]--;
11674		}, this));
11675	};
11676
11677	/**
11678	 * Registers an event or state.
11679	 * @public
11680	 * @param {Object} object - The event or state to register.
11681	 */
11682	Owl.prototype.register = function(object) {
11683		if (object.type === Owl.Type.Event) {
11684			if (!$.event.special[object.name]) {
11685				$.event.special[object.name] = {};
11686			}
11687
11688			if (!$.event.special[object.name].owl) {
11689				var _default = $.event.special[object.name]._default;
11690				$.event.special[object.name]._default = function(e) {
11691					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
11692						return _default.apply(this, arguments);
11693					}
11694					return e.namespace && e.namespace.indexOf('owl') > -1;
11695				};
11696				$.event.special[object.name].owl = true;
11697			}
11698		} else if (object.type === Owl.Type.State) {
11699			if (!this._states.tags[object.name]) {
11700				this._states.tags[object.name] = object.tags;
11701			} else {
11702				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
11703			}
11704
11705			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
11706				return $.inArray(tag, this._states.tags[object.name]) === i;
11707			}, this));
11708		}
11709	};
11710
11711	/**
11712	 * Suppresses events.
11713	 * @protected
11714	 * @param {Array.<String>} events - The events to suppress.
11715	 */
11716	Owl.prototype.suppress = function(events) {
11717		$.each(events, $.proxy(function(index, event) {
11718			this._supress[event] = true;
11719		}, this));
11720	};
11721
11722	/**
11723	 * Releases suppressed events.
11724	 * @protected
11725	 * @param {Array.<String>} events - The events to release.
11726	 */
11727	Owl.prototype.release = function(events) {
11728		$.each(events, $.proxy(function(index, event) {
11729			delete this._supress[event];
11730		}, this));
11731	};
11732
11733	/**
11734	 * Gets unified pointer coordinates from event.
11735	 * @todo #261
11736	 * @protected
11737	 * @param {Event} - The `mousedown` or `touchstart` event.
11738	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
11739	 */
11740	Owl.prototype.pointer = function(event) {
11741		var result = { x: null, y: null };
11742
11743		event = event.originalEvent || event || window.event;
11744
11745		event = event.touches && event.touches.length ?
11746			event.touches[0] : event.changedTouches && event.changedTouches.length ?
11747				event.changedTouches[0] : event;
11748
11749		if (event.pageX) {
11750			result.x = event.pageX;
11751			result.y = event.pageY;
11752		} else {
11753			result.x = event.clientX;
11754			result.y = event.clientY;
11755		}
11756
11757		return result;
11758	};
11759
11760	/**
11761	 * Gets the difference of two vectors.
11762	 * @todo #261
11763	 * @protected
11764	 * @param {Object} - The first vector.
11765	 * @param {Object} - The second vector.
11766	 * @returns {Object} - The difference.
11767	 */
11768	Owl.prototype.difference = function(first, second) {
11769		return {
11770			x: first.x - second.x,
11771			y: first.y - second.y
11772		};
11773	};
11774
11775	/**
11776	 * The jQuery Plugin for the Owl Carousel
vendor: 32,236 bytes, lines 11777-13059
11777	 * @todo Navigation plugin `next` and `prev`
11778	 * @public
11779	 */
11780	$.fn.owlCarousel = function(option) {
11781		var args = Array.prototype.slice.call(arguments, 1);
11782
11783		return this.each(function() {
11784			var $this = $(this),
11785				data = $this.data('owl.carousel');
11786
11787			if (!data) {
11788				data = new Owl(this, typeof option == 'object' && option);
11789				$this.data('owl.carousel', data);
11790
11791				$.each([
11792					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
11793				], function(i, event) {
11794					data.register({ type: Owl.Type.Event, name: event });
11795					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
11796						if (e.namespace && e.relatedTarget !== this) {
11797							this.suppress([ event ]);
11798							data[event].apply(this, [].slice.call(arguments, 1));
11799							this.release([ event ]);
11800						}
11801					}, data));
11802				});
11803			}
11804
11805			if (typeof option == 'string' && option.charAt(0) !== '_') {
11806				data[option].apply(data, args);
11807			}
11808		});
11809	};
11810
11811	/**
11812	 * The constructor for the jQuery Plugin
11813	 * @public
11814	 */
11815	$.fn.owlCarousel.Constructor = Owl;
11816
11817})(window.Zepto || window.jQuery, window, document);
11818
11819/**
11820 * AutoRefresh Plugin
11821 * @version 2.0.0-beta.3
11822 * @author Artus Kolanowski
11823 * @license The MIT License (MIT)
11824 */
11825;(function($, window, document, undefined) {
11826
11827	/**
11828	 * Creates the auto refresh plugin.
11829	 * @class The Auto Refresh Plugin
11830	 * @param {Owl} carousel - The Owl Carousel
11831	 */
11832	var AutoRefresh = function(carousel) {
11833		/**
11834		 * Reference to the core.
11835		 * @protected
11836		 * @type {Owl}
11837		 */
11838		this._core = carousel;
11839
11840		/**
11841		 * Refresh interval.
11842		 * @protected
11843		 * @type {number}
11844		 */
11845		this._interval = null;
11846
11847		/**
11848		 * Whether the element is currently visible or not.
11849		 * @protected
11850		 * @type {Boolean}
11851		 */
11852		this._visible = null;
11853
11854		/**
11855		 * All event handlers.
11856		 * @protected
11857		 * @type {Object}
11858		 */
11859		this._handlers = {
11860			'initialized.owl.carousel': $.proxy(function(e) {
11861				if (e.namespace && this._core.settings.autoRefresh) {
11862					this.watch();
11863				}
11864			}, this)
11865		};
11866
11867		// set default options
11868		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
11869
11870		// register event handlers
11871		this._core.$element.on(this._handlers);
11872	};
11873
11874	/**
11875	 * Default options.
11876	 * @public
11877	 */
11878	AutoRefresh.Defaults = {
11879		autoRefresh: true,
11880		autoRefreshInterval: 500
11881	};
11882
11883	/**
11884	 * Watches the element.
11885	 */
11886	AutoRefresh.prototype.watch = function() {
11887		if (this._interval) {
11888			return;
11889		}
11890
11891		this._visible = this._core.$element.is(':visible');
11892		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
11893	};
11894
11895	/**
11896	 * Refreshes the element.
11897	 */
11898	AutoRefresh.prototype.refresh = function() {
11899		if (this._core.$element.is(':visible') === this._visible) {
11900			return;
11901		}
11902
11903		this._visible = !this._visible;
11904
11905		this._core.$element.toggleClass('owl-hidden', !this._visible);
11906
11907		this._visible && (this._core.invalidate('width') && this._core.refresh());
11908	};
11909
11910	/**
11911	 * Destroys the plugin.
11912	 */
11913	AutoRefresh.prototype.destroy = function() {
11914		var handler, property;
11915
11916		window.clearInterval(this._interval);
11917
11918		for (handler in this._handlers) {
11919			this._core.$element.off(handler, this._handlers[handler]);
11920		}
11921		for (property in Object.getOwnPropertyNames(this)) {
11922			typeof this[property] != 'function' && (this[property] = null);
11923		}
11924	};
11925
11926	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
11927
11928})(window.Zepto || window.jQuery, window, document);
11929
11930/**
11931 * Lazy Plugin
11932 * @version 2.0.0-beta.3
11933 * @author Bartosz Wojciechowski
11934 * @license The MIT License (MIT)
11935 */
11936;(function($, window, document, undefined) {
11937
11938	/**
11939	 * Creates the lazy plugin.
11940	 * @class The Lazy Plugin
11941	 * @param {Owl} carousel - The Owl Carousel
11942	 */
11943	var Lazy = function(carousel) {
11944
11945		/**
11946		 * Reference to the core.
11947		 * @protected
11948		 * @type {Owl}
11949		 */
11950		this._core = carousel;
11951
11952		/**
11953		 * Already loaded items.
11954		 * @protected
11955		 * @type {Array.<jQuery>}
11956		 */
11957		this._loaded = [];
11958
11959		/**
11960		 * Event handlers.
11961		 * @protected
11962		 * @type {Object}
11963		 */
11964		this._handlers = {
11965			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
11966				if (!e.namespace) {
11967					return;
11968				}
11969
11970				if (!this._core.settings || !this._core.settings.lazyLoad) {
11971					return;
11972				}
11973
11974				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
11975					var settings = this._core.settings,
11976						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
11977						i = ((settings.center && n * -1) || 0),
11978						position = ((e.property && e.property.value) || this._core.current()) + i,
11979						clones = this._core.clones().length,
11980						load = $.proxy(function(i, v) { this.load(v) }, this);
11981
11982					while (i++ < n) {
11983						this.load(clones / 2 + this._core.relative(position));
11984						clones && $.each(this._core.clones(this._core.relative(position)), load);
11985						position++;
11986					}
11987				}
11988			}, this)
11989		};
11990
11991		// set the default options
11992		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
11993
11994		// register event handler
11995		this._core.$element.on(this._handlers);
11996	}
11997
11998	/**
11999	 * Default options.
12000	 * @public
12001	 */
12002	Lazy.Defaults = {
12003		lazyLoad: false
12004	}
12005
12006	/**
12007	 * Loads all resources of an item at the specified position.
12008	 * @param {Number} position - The absolute position of the item.
12009	 * @protected
12010	 */
12011	Lazy.prototype.load = function(position) {
12012		var $item = this._core.$stage.children().eq(position),
12013			$elements = $item && $item.find('.owl-lazy');
12014
12015		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
12016			return;
12017		}
12018
12019		$elements.each($.proxy(function(index, element) {
12020			var $element = $(element), image,
12021				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
12022
12023			this._core.trigger('load', { element: $element, url: url }, 'lazy');
12024
12025			if ($element.is('img')) {
12026				$element.one('load.owl.lazy', $.proxy(function() {
12027					$element.css('opacity', 1);
12028					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
12029				}, this)).attr('src', url);
12030			} else {
12031				image = new Image();
12032				image.onload = $.proxy(function() {
12033					$element.css({
12034						'background-image': 'url(' + url + ')',
12035						'opacity': '1'
12036					});
12037					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
12038				}, this);
12039				image.src = url;
12040			}
12041		}, this));
12042
12043		this._loaded.push($item.get(0));
12044	}
12045
12046	/**
12047	 * Destroys the plugin.
12048	 * @public
12049	 */
12050	Lazy.prototype.destroy = function() {
12051		var handler, property;
12052
12053		for (handler in this.handlers) {
12054			this._core.$element.off(handler, this.handlers[handler]);
12055		}
12056		for (property in Object.getOwnPropertyNames(this)) {
12057			typeof this[property] != 'function' && (this[property] = null);
12058		}
12059	};
12060
12061	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
12062
12063})(window.Zepto || window.jQuery, window, document);
12064
12065/**
12066 * AutoHeight Plugin
12067 * @version 2.0.0-beta.3
12068 * @author Bartosz Wojciechowski
12069 * @license The MIT License (MIT)
12070 */
12071;(function($, window, document, undefined) {
12072
12073	/**
12074	 * Creates the auto height plugin.
12075	 * @class The Auto Height Plugin
12076	 * @param {Owl} carousel - The Owl Carousel
12077	 */
12078	var AutoHeight = function(carousel) {
12079		/**
12080		 * Reference to the core.
12081		 * @protected
12082		 * @type {Owl}
12083		 */
12084		this._core = carousel;
12085
12086		/**
12087		 * All event handlers.
12088		 * @protected
12089		 * @type {Object}
12090		 */
12091		this._handlers = {
12092			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
12093				if (e.namespace && this._core.settings.autoHeight) {
12094					this.update();
12095				}
12096			}, this),
12097			'changed.owl.carousel': $.proxy(function(e) {
12098				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
12099					this.update();
12100				}
12101			}, this),
12102			'loaded.owl.lazy': $.proxy(function(e) {
12103				if (e.namespace && this._core.settings.autoHeight
12104					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
12105					this.update();
12106				}
12107			}, this)
12108		};
12109
12110		// set default options
12111		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
12112
12113		// register event handlers
12114		this._core.$element.on(this._handlers);
12115	};
12116
12117	/**
12118	 * Default options.
12119	 * @public
12120	 */
12121	AutoHeight.Defaults = {
12122		autoHeight: false,
12123		autoHeightClass: 'owl-height'
12124	};
12125
12126	/**
12127	 * Updates the view.
12128	 */
12129	AutoHeight.prototype.update = function() {
12130		var start = this._core._current,
12131			end = start + this._core.settings.items,
12132			visible = this._core.$stage.children().toArray().slice(start, end);
12133			heights = [],
12134			maxheight = 0;
12135
12136		$.each(visible, function(index, item) {
12137			heights.push($(item).height());
12138		});
12139
12140		maxheight = Math.max.apply(null, heights);
12141
12142		this._core.$stage.parent()
12143			.height(maxheight)
12144			.addClass(this._core.settings.autoHeightClass);
12145	};
12146
12147	AutoHeight.prototype.destroy = function() {
12148		var handler, property;
12149
12150		for (handler in this._handlers) {
12151			this._core.$element.off(handler, this._handlers[handler]);
12152		}
12153		for (property in Object.getOwnPropertyNames(this)) {
12154			typeof this[property] != 'function' && (this[property] = null);
12155		}
12156	};
12157
12158	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
12159
12160})(window.Zepto || window.jQuery, window, document);
12161
12162/**
12163 * Video Plugin
12164 * @version 2.0.0-beta.3
12165 * @author Bartosz Wojciechowski
12166 * @license The MIT License (MIT)
12167 */
12168;(function($, window, document, undefined) {
12169
12170	/**
12171	 * Creates the video plugin.
12172	 * @class The Video Plugin
12173	 * @param {Owl} carousel - The Owl Carousel
12174	 */
12175	var Video = function(carousel) {
12176		/**
12177		 * Reference to the core.
12178		 * @protected
12179		 * @type {Owl}
12180		 */
12181		this._core = carousel;
12182
12183		/**
12184		 * Cache all video URLs.
12185		 * @protected
12186		 * @type {Object}
12187		 */
12188		this._videos = {};
12189
12190		/**
12191		 * Current playing item.
12192		 * @protected
12193		 * @type {jQuery}
12194		 */
12195		this._playing = null;
12196
12197		/**
12198		 * All event handlers.
12199		 * @todo The cloned content removale is too late
12200		 * @protected
12201		 * @type {Object}
12202		 */
12203		this._handlers = {
12204			'initialized.owl.carousel': $.proxy(function(e) {
12205				if (e.namespace) {
12206					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
12207				}
12208			}, this),
12209			'resize.owl.carousel': $.proxy(function(e) {
12210				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
12211					e.preventDefault();
12212				}
12213			}, this),
12214			'refreshed.owl.carousel': $.proxy(function(e) {
12215				if (e.namespace && this._core.is('resizing')) {
12216					this._core.$stage.find('.cloned .owl-video-frame').remove();
12217				}
12218			}, this),
12219			'changed.owl.carousel': $.proxy(function(e) {
12220				if (e.namespace && e.property.name === 'position' && this._playing) {
12221					this.stop();
12222				}
12223			}, this),
12224			'prepared.owl.carousel': $.proxy(function(e) {
12225				if (!e.namespace) {
12226					return;
12227				}
12228
12229				var $element = $(e.content).find('.owl-video');
12230
12231				if ($element.length) {
12232					$element.css('display', 'none');
12233					this.fetch($element, $(e.content));
12234				}
12235			}, this)
12236		};
12237
12238		// set default options
12239		this._core.options = $.extend({}, Video.Defaults, this._core.options);
12240
12241		// register event handlers
12242		this._core.$element.on(this._handlers);
12243
12244		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
12245			this.play(e);
12246		}, this));
12247	};
12248
12249	/**
12250	 * Default options.
12251	 * @public
12252	 */
12253	Video.Defaults = {
12254		video: false,
12255		videoHeight: false,
12256		videoWidth: false
12257	};
12258
12259	/**
12260	 * Gets the video ID and the type (YouTube/Vimeo only).
12261	 * @protected
12262	 * @param {jQuery} target - The target containing the video data.
12263	 * @param {jQuery} item - The item containing the video.
12264	 */
12265	Video.prototype.fetch = function(target, item) {
12266		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
12267			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
12268			width = target.attr('data-width') || this._core.settings.videoWidth,
12269			height = target.attr('data-height') || this._core.settings.videoHeight,
12270			url = target.attr('href');
12271
12272		if (url) {
12273			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+)?/);
12274
12275			if (id[3].indexOf('youtu') > -1) {
12276				type = 'youtube';
12277			} else if (id[3].indexOf('vimeo') > -1) {
12278				type = 'vimeo';
12279			} else {
12280				throw new Error('Video URL not supported.');
12281			}
12282			id = id[6];
12283		} else {
12284			throw new Error('Missing video URL.');
12285		}
12286
12287		this._videos[url] = {
12288			type: type,
12289			id: id,
12290			width: width,
12291			height: height
12292		};
12293
12294		item.attr('data-video', url);
12295
12296		this.thumbnail(target, this._videos[url]);
12297	};
12298
12299	/**
12300	 * Creates video thumbnail.
12301	 * @protected
12302	 * @param {jQuery} target - The target containing the video data.
12303	 * @param {Object} info - The video info object.
12304	 * @see `fetch`
12305	 */
12306	Video.prototype.thumbnail = function(target, video) {
12307		var tnLink,
12308			icon,
12309			path,
12310			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
12311			customTn = target.find('img'),
12312			srcType = 'src',
12313			lazyClass = '',
12314			settings = this._core.settings,
12315			create = function(path) {
12316				icon = '<div class="owl-video-play-icon"></div>';
12317
12318				if (settings.lazyLoad) {
12319					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
12320				} else {
12321					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
12322				}
12323				target.after(tnLink);
12324				target.after(icon);
12325			};
12326
12327		// wrap video content into owl-video-wrapper div
12328		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
12329
12330		if (this._core.settings.lazyLoad) {
12331			srcType = 'data-src';
12332			lazyClass = 'owl-lazy';
12333		}
12334
12335		// custom thumbnail
12336		if (customTn.length) {
12337			create(customTn.attr(srcType));
12338			customTn.remove();
12339			return false;
12340		}
12341
12342		if (video.type === 'youtube') {
12343			path = "http://img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
12344			create(path);
12345		} else if (video.type === 'vimeo') {
12346			$.ajax({
12347				type: 'GET',
12348				url: 'http://vimeo.com/api/v2/video/' + video.id + '.json',
12349				jsonp: 'callback',
12350				dataType: 'jsonp',
12351				success: function(data) {
12352					path = data[0].thumbnail_large;
12353					create(path);
12354				}
12355			});
12356		}
12357	};
12358
12359	/**
12360	 * Stops the current video.
12361	 * @public
12362	 */
12363	Video.prototype.stop = function() {
12364		this._core.trigger('stop', null, 'video');
12365		this._playing.find('.owl-video-frame').remove();
12366		this._playing.removeClass('owl-video-playing');
12367		this._playing = null;
12368		this._core.leave('playing');
12369		this._core.trigger('stopped', null, 'video');
12370	};
12371
12372	/**
12373	 * Starts the current video.
12374	 * @public
12375	 * @param {Event} event - The event arguments.
12376	 */
12377	Video.prototype.play = function(event) {
12378		var target = $(event.target),
12379			item = target.closest('.' + this._core.settings.itemClass),
12380			video = this._videos[item.attr('data-video')],
12381			width = video.width || '100%',
12382			height = video.height || this._core.$stage.height(),
12383			html;
12384
12385		if (this._playing) {
12386			return;
12387		}
12388
12389		this._core.enter('playing');
12390		this._core.trigger('play', null, 'video');
12391
12392		item = this._core.items(this._core.relative(item.index()));
12393
12394		this._core.reset(item.index());
12395
12396		if (video.type === 'youtube') {
12397			html = '<iframe width="' + width + '" height="' + height + '" src="http://www.youtube.com/embed/' +
12398				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
12399		} else if (video.type === 'vimeo') {
12400			html = '<iframe src="http://player.vimeo.com/video/' + video.id +
12401				'?autoplay=1" width="' + width + '" height="' + height +
12402				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
12403		}
12404
12405		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
12406
12407		this._playing = item.addClass('owl-video-playing');
12408	};
12409
12410	/**
12411	 * Checks whether an video is currently in full screen mode or not.
12412	 * @todo Bad style because looks like a readonly method but changes members.
12413	 * @protected
12414	 * @returns {Boolean}
12415	 */
12416	Video.prototype.isInFullScreen = function() {
12417		var element = document.fullscreenElement || document.mozFullScreenElement ||
12418				document.webkitFullscreenElement;
12419
12420		return element && $(element).parent().hasClass('owl-video-frame');
12421	};
12422
12423	/**
12424	 * Destroys the plugin.
12425	 */
12426	Video.prototype.destroy = function() {
12427		var handler, property;
12428
12429		this._core.$element.off('click.owl.video');
12430
12431		for (handler in this._handlers) {
12432			this._core.$element.off(handler, this._handlers[handler]);
12433		}
12434		for (property in Object.getOwnPropertyNames(this)) {
12435			typeof this[property] != 'function' && (this[property] = null);
12436		}
12437	};
12438
12439	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
12440
12441})(window.Zepto || window.jQuery, window, document);
12442
12443/**
12444 * Animate Plugin
12445 * @version 2.0.0-beta.3
12446 * @author Bartosz Wojciechowski
12447 * @license The MIT License (MIT)
12448 */
12449;(function($, window, document, undefined) {
12450
12451	/**
12452	 * Creates the animate plugin.
12453	 * @class The Navigation Plugin
12454	 * @param {Owl} scope - The Owl Carousel
12455	 */
12456	var Animate = function(scope) {
12457		this.core = scope;
12458		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
12459		this.swapping = true;
12460		this.previous = undefined;
12461		this.next = undefined;
12462
12463		this.handlers = {
12464			'change.owl.carousel': $.proxy(function(e) {
12465				if (e.namespace && e.property.name == 'position') {
12466					this.previous = this.core.current();
12467					this.next = e.property.value;
12468				}
12469			}, this),
12470			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
12471				if (e.namespace) {
12472					this.swapping = e.type == 'translated';
12473				}
12474			}, this),
12475			'translate.owl.carousel': $.proxy(function(e) {
12476				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
12477					this.swap();
12478				}
12479			}, this)
12480		};
12481
12482		this.core.$element.on(this.handlers);
12483	};
12484
12485	/**
12486	 * Default options.
12487	 * @public
12488	 */
12489	Animate.Defaults = {
12490		animateOut: false,
12491		animateIn: false
12492	};
12493
12494	/**
12495	 * Toggles the animation classes whenever an translations starts.
12496	 * @protected
12497	 * @returns {Boolean|undefined}
12498	 */
12499	Animate.prototype.swap = function() {
12500
12501		if (this.core.settings.items !== 1) {
12502			return;
12503		}
12504
12505		if (!$.support.animation || !$.support.transition) {
12506			return;
12507		}
12508
12509		this.core.speed(0);
12510
12511		var left,
12512			clear = $.proxy(this.clear, this),
12513			previous = this.core.$stage.children().eq(this.previous),
12514			next = this.core.$stage.children().eq(this.next),
12515			incoming = this.core.settings.animateIn,
12516			outgoing = this.core.settings.animateOut;
12517
12518		if (this.core.current() === this.previous) {
12519			return;
12520		}
12521
12522		if (outgoing) {
12523			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
12524			previous.css( { 'left': left + 'px' } )
12525				.addClass('animated owl-animated-out')
12526				.addClass(outgoing)
12527				.on($.support.animation.end, clear);
12528		}
12529
12530		if (incoming) {
12531			next.addClass('animated owl-animated-in')
12532				.addClass(incoming)
12533				.on($.support.animation.end, clear);
12534		}
12535	};
12536
12537	Animate.prototype.clear = function(e) {
12538		if ($(e.target).hasClass('animated')) {
12539			$(e.target).css( { 'left': '' } )
12540				.removeClass('animated owl-animated-out owl-animated-in')
12541				.removeClass(this.core.settings.animateIn)
12542				.removeClass(this.core.settings.animateOut);
12543			this.core.onTransitionEnd();
12544		}
12545	};
12546
12547	/**
12548	 * Destroys the plugin.
12549	 * @public
12550	 */
12551	Animate.prototype.destroy = function() {
12552		var handler, property;
12553
12554		for (handler in this.handlers) {
12555			this.core.$element.off(handler, this.handlers[handler]);
12556		}
12557		for (property in Object.getOwnPropertyNames(this)) {
12558			typeof this[property] != 'function' && (this[property] = null);
12559		}
12560	};
12561
12562	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
12563
12564})(window.Zepto || window.jQuery, window, document);
12565
12566/**
12567 * Autoplay Plugin
12568 * @version 2.0.0-beta.3
12569 * @author Bartosz Wojciechowski
12570 * @author Artus Kolanowski
12571 * @license The MIT License (MIT)
12572 */
12573;(function($, window, document, undefined) {
12574
12575	/**
12576	 * Creates the autoplay plugin.
12577	 * @class The Autoplay Plugin
12578	 * @param {Owl} scope - The Owl Carousel
12579	 */
12580	var Autoplay = function(carousel) {
12581		/**
12582		 * Reference to the core.
12583		 * @protected
12584		 * @type {Owl}
12585		 */
12586		this._core = carousel;
12587
12588		/**
12589		 * The autoplay interval.
12590		 * @type {Number}
12591		 */
12592		this._interval = null;
12593
12594		/**
12595		 * Indicates whenever the autoplay is paused.
12596		 * @type {Boolean}
12597		 */
12598		this._paused = false;
12599
12600		/**
12601		 * All event handlers.
12602		 * @protected
12603		 * @type {Object}
12604		 */
12605		this._handlers = {
12606			'changed.owl.carousel': $.proxy(function(e) {
12607				if (e.namespace && e.property.name === 'settings') {
12608					if (this._core.settings.autoplay) {
12609						this.play();
12610					} else {
12611						this.stop();
12612					}
12613				}
12614			}, this),
12615			'initialized.owl.carousel': $.proxy(function(e) {
12616				if (e.namespace && this._core.settings.autoplay) {
12617					this.play();
12618				}
12619			}, this),
12620			'play.owl.autoplay': $.proxy(function(e, t, s) {
12621				if (e.namespace) {
12622					this.play(t, s);
12623				}
12624			}, this),
12625			'stop.owl.autoplay': $.proxy(function(e) {
12626				if (e.namespace) {
12627					this.stop();
12628				}
12629			}, this),
12630			'mouseover.owl.autoplay': $.proxy(function() {
12631				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
12632					this.pause();
12633				}
12634			}, this),
12635			'mouseleave.owl.autoplay': $.proxy(function() {
12636				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
12637					this.play();
12638				}
12639			}, this)
12640		};
12641
12642		// register event handlers
12643		this._core.$element.on(this._handlers);
12644
12645		// set default options
12646		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
12647	};
12648
12649	/**
12650	 * Default options.
12651	 * @public
12652	 */
12653	Autoplay.Defaults = {
12654		autoplay: false,
12655		autoplayTimeout: 5000,
12656		autoplayHoverPause: false,
12657		autoplaySpeed: false
12658	};
12659
12660	/**
12661	 * Starts the autoplay.
12662	 * @public
12663	 * @param {Number} [timeout] - The interval before the next animation starts.
12664	 * @param {Number} [speed] - The animation speed for the animations.
12665	 */
12666	Autoplay.prototype.play = function(timeout, speed) {
12667		this._paused = false;
12668
12669		if (this._core.is('rotating')) {
12670			return;
12671		}
12672
12673		this._core.enter('rotating');
12674
12675		this._interval = window.setInterval($.proxy(function() {
12676			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
12677				return;
12678			}
12679			this._core.next(speed || this._core.settings.autoplaySpeed);
12680		}, this), timeout || this._core.settings.autoplayTimeout);
12681	};
12682
12683	/**
12684	 * Stops the autoplay.
12685	 * @public
12686	 */
12687	Autoplay.prototype.stop = function() {
12688		if (!this._core.is('rotating')) {
12689			return;
12690		}
12691
12692		window.clearInterval(this._interval);
12693		this._core.leave('rotating');
12694	};
12695
12696	/**
12697	 * Stops the autoplay.
12698	 * @public
12699	 */
12700	Autoplay.prototype.pause = function() {
12701		if (!this._core.is('rotating')) {
12702			return;
12703		}
12704
12705		this._paused = true;
12706	};
12707
12708	/**
12709	 * Destroys the plugin.
12710	 */
12711	Autoplay.prototype.destroy = function() {
12712		var handler, property;
12713
12714		this.stop();
12715
12716		for (handler in this._handlers) {
12717			this._core.$element.off(handler, this._handlers[handler]);
12718		}
12719		for (property in Object.getOwnPropertyNames(this)) {
12720			typeof this[property] != 'function' && (this[property] = null);
12721		}
12722	};
12723
12724	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
12725
12726})(window.Zepto || window.jQuery, window, document);
12727
12728/**
12729 * Navigation Plugin
12730 * @version 2.0.0-beta.3
12731 * @author Artus Kolanowski
12732 * @license The MIT License (MIT)
12733 */
12734;(function($, window, document, undefined) {
12735	'use strict';
12736
12737	/**
12738	 * Creates the navigation plugin.
12739	 * @class The Navigation Plugin
12740	 * @param {Owl} carousel - The Owl Carousel.
12741	 */
12742	var Navigation = function(carousel) {
12743		/**
12744		 * Reference to the core.
12745		 * @protected
12746		 * @type {Owl}
12747		 */
12748		this._core = carousel;
12749
12750		/**
12751		 * Indicates whether the plugin is initialized or not.
12752		 * @protected
12753		 * @type {Boolean}
12754		 */
12755		this._initialized = false;
12756
12757		/**
12758		 * The current paging indexes.
12759		 * @protected
12760		 * @type {Array}
12761		 */
12762		this._pages = [];
12763
12764		/**
12765		 * All DOM elements of the user interface.
12766		 * @protected
12767		 * @type {Object}
12768		 */
12769		this._controls = {};
12770
12771		/**
12772		 * Markup for an indicator.
12773		 * @protected
12774		 * @type {Array.<String>}
12775		 */
12776		this._templates = [];
12777
12778		/**
12779		 * The carousel element.
12780		 * @type {jQuery}
12781		 */
12782		this.$element = this._core.$element;
12783
12784		/**
12785		 * Overridden methods of the carousel.
12786		 * @protected
12787		 * @type {Object}
12788		 */
12789		this._overrides = {
12790			next: this._core.next,
12791			prev: this._core.prev,
12792			to: this._core.to
12793		};
12794
12795		/**
12796		 * All event handlers.
12797		 * @protected
12798		 * @type {Object}
12799		 */
12800		this._handlers = {
12801			'prepared.owl.carousel': $.proxy(function(e) {
12802				if (e.namespace && this._core.settings.dotsData) {
12803					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
12804						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
12805				}
12806			}, this),
12807			'added.owl.carousel': $.proxy(function(e) {
12808				if (e.namespace && this._core.settings.dotsData) {
12809					this._templates.splice(e.position, 0, this._templates.pop());
12810				}
12811			}, this),
12812			'remove.owl.carousel': $.proxy(function(e) {
12813				if (e.namespace && this._core.settings.dotsData) {
12814					this._templates.splice(e.position, 1);
12815				}
12816			}, this),
12817			'changed.owl.carousel': $.proxy(function(e) {
12818				if (e.namespace && e.property.name == 'position') {
12819					this.draw();
12820				}
12821			}, this),
12822			'initialized.owl.carousel': $.proxy(function(e) {
12823				if (e.namespace && !this._initialized) {
12824					this._core.trigger('initialize', null, 'navigation');
12825					this.initialize();
12826					this.update();
12827					this.draw();
12828					this._initialized = true;
12829					this._core.trigger('initialized', null, 'navigation');
12830				}
12831			}, this),
12832			'refreshed.owl.carousel': $.proxy(function(e) {
12833				if (e.namespace && this._initialized) {
12834					this._core.trigger('refresh', null, 'navigation');
12835					this.update();
12836					this.draw();
12837					this._core.trigger('refreshed', null, 'navigation');
12838				}
12839			}, this)
12840		};
12841
12842		// set default options
12843		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
12844
12845		// register event handlers
12846		this.$element.on(this._handlers);
12847	};
12848
12849	/**
12850	 * Default options.
12851	 * @public
12852	 * @todo Rename `slideBy` to `navBy`
12853	 */
12854	Navigation.Defaults = {
12855		nav: false,
12856		navText: [ 'prev', 'next' ],
12857		navSpeed: false,
12858		navElement: 'div',
12859		navContainer: false,
12860		navContainerClass: 'owl-nav',
12861		navClass: [ 'owl-prev', 'owl-next' ],
12862		slideBy: 1,
12863		dotClass: 'owl-dot',
12864		dotsClass: 'owl-dots',
12865		dots: true,
12866		dotsEach: false,
12867		dotsData: false,
12868		dotsSpeed: false,
12869		dotsContainer: false
12870	};
12871
12872	/**
12873	 * Initializes the layout of the plugin and extends the carousel.
12874	 * @protected
12875	 */
12876	Navigation.prototype.initialize = function() {
12877		var override,
12878			settings = this._core.settings;
12879
12880		// create DOM structure for relative navigation
12881		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
12882			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
12883
12884		this._controls.$previous = $('<' + settings.navElement + '>')
12885			.addClass(settings.navClass[0])
12886			.html(settings.navText[0])
12887			.prependTo(this._controls.$relative)
12888			.on('click', $.proxy(function(e) {
12889				this.prev(settings.navSpeed);
12890			}, this));
12891		this._controls.$next = $('<' + settings.navElement + '>')
12892			.addClass(settings.navClass[1])
12893			.html(settings.navText[1])
12894			.appendTo(this._controls.$relative)
12895			.on('click', $.proxy(function(e) {
12896				this.next(settings.navSpeed);
12897			}, this));
12898
12899		// create DOM structure for absolute navigation
12900		if (!settings.dotsData) {
12901			this._templates = [ $('<div>')
12902				.addClass(settings.dotClass)
12903				.append($('<span>'))
12904				.prop('outerHTML') ];
12905		}
12906
12907		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
12908			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
12909
12910		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
12911			var index = $(e.target).parent().is(this._controls.$absolute)
12912				? $(e.target).index() : $(e.target).parent().index();
12913
12914			e.preventDefault();
12915
12916			this.to(index, settings.dotsSpeed);
12917		}, this));
12918
12919		// override public methods of the carousel
12920		for (override in this._overrides) {
12921			this._core[override] = $.proxy(this[override], this);
12922		}
12923	};
12924
12925	/**
12926	 * Destroys the plugin.
12927	 * @protected
12928	 */
12929	Navigation.prototype.destroy = function() {
12930		var handler, control, property, override;
12931
12932		for (handler in this._handlers) {
12933			this.$element.off(handler, this._handlers[handler]);
12934		}
12935		for (control in this._controls) {
12936			this._controls[control].remove();
12937		}
12938		for (override in this.overides) {
12939			this._core[override] = this._overrides[override];
12940		}
12941		for (property in Object.getOwnPropertyNames(this)) {
12942			typeof this[property] != 'function' && (this[property] = null);
12943		}
12944	};
12945
12946	/**
12947	 * Updates the internal state.
12948	 * @protected
12949	 */
12950	Navigation.prototype.update = function() {
12951		var i, j, k,
12952			lower = this._core.clones().length / 2,
12953			upper = lower + this._core.items().length,
12954			maximum = this._core.maximum(true),
12955			settings = this._core.settings,
12956			size = settings.center || settings.autoWidth || settings.dotsData
12957				? 1 : settings.dotsEach || settings.items;
12958
12959		if (settings.slideBy !== 'page') {
12960			settings.slideBy = Math.min(settings.slideBy, settings.items);
12961		}
12962
12963		if (settings.dots || settings.slideBy == 'page') {
12964			this._pages = [];
12965
12966			for (i = lower, j = 0, k = 0; i < upper; i++) {
12967				if (j >= size || j === 0) {
12968					this._pages.push({
12969						start: Math.min(maximum, i - lower),
12970						end: i - lower + size - 1
12971					});
12972					if (Math.min(maximum, i - lower) === maximum) {
12973						break;
12974					}
12975					j = 0, ++k;
12976				}
12977				j += this._core.mergers(this._core.relative(i));
12978			}
12979		}
12980	};
12981
12982	/**
12983	 * Draws the user interface.
12984	 * @todo The option `dotsData` wont work.
12985	 * @protected
12986	 */
12987	Navigation.prototype.draw = function() {
12988		var difference,
12989			settings = this._core.settings,
12990			disabled = this._core.items().length <= settings.items,
12991			index = this._core.relative(this._core.current()),
12992			loop = settings.loop || settings.rewind;
12993
12994		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
12995
12996		if (settings.nav) {
12997			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
12998			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
12999		}
13000
13001		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
13002
13003		if (settings.dots) {
13004			difference = this._pages.length - this._controls.$absolute.children().length;
13005
13006			if (settings.dotsData && difference !== 0) {
13007				this._controls.$absolute.html(this._templates.join(''));
13008			} else if (difference > 0) {
13009				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
13010			} else if (difference < 0) {
13011				this._controls.$absolute.children().slice(difference).remove();
13012			}
13013
13014			this._controls.$absolute.find('.active').removeClass('active');
13015			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
13016		}
13017	};
13018
13019	/**
13020	 * Extends event data.
13021	 * @protected
13022	 * @param {Event} event - The event object which gets thrown.
13023	 */
13024	Navigation.prototype.onTrigger = function(event) {
13025		var settings = this._core.settings;
13026
13027		event.page = {
13028			index: $.inArray(this.current(), this._pages),
13029			count: this._pages.length,
13030			size: settings && (settings.center || settings.autoWidth || settings.dotsData
13031				? 1 : settings.dotsEach || settings.items)
13032		};
13033	};
13034
13035	/**
13036	 * Gets the current page position of the carousel.
13037	 * @protected
13038	 * @returns {Number}
13039	 */
13040	Navigation.prototype.current = function() {
13041		var current = this._core.relative(this._core.current());
13042		return $.grep(this._pages, $.proxy(function(page, index) {
13043			return page.start <= current && page.end >= current;
13044		}, this)).pop();
13045	};
13046
13047	/**
13048	 * Gets the current succesor/predecessor position.
13049	 * @protected
13050	 * @returns {Number}
13051	 */
13052	Navigation.prototype.getPosition = function(successor) {
13053		var position, length,
13054			settings = this._core.settings;
13055
13056		if (settings.slideBy == 'page') {
13057			position = $.inArray(this.current(), this._pages);
13058			length = this._pages.length;
13059			successor ? ++position : --position;
vendor: 5,678 bytes, lines 13060-13284
13060			position = this._pages[((position % length) + length) % length].start;
13061		} else {
13062			position = this._core.relative(this._core.current());
13063			length = this._core.items().length;
13064			successor ? position += settings.slideBy : position -= settings.slideBy;
13065		}
13066
13067		return position;
13068	};
13069
13070	/**
13071	 * Slides to the next item or page.
13072	 * @public
13073	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
13074	 */
13075	Navigation.prototype.next = function(speed) {
13076		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
13077	};
13078
13079	/**
13080	 * Slides to the previous item or page.
13081	 * @public
13082	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
13083	 */
13084	Navigation.prototype.prev = function(speed) {
13085		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
13086	};
13087
13088	/**
13089	 * Slides to the specified item or page.
13090	 * @public
13091	 * @param {Number} position - The position of the item or page.
13092	 * @param {Number} [speed] - The time in milliseconds for the transition.
13093	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
13094	 */
13095	Navigation.prototype.to = function(position, speed, standard) {
13096		var length;
13097
13098		if (!standard) {
13099			length = this._pages.length;
13100			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
13101		} else {
13102			$.proxy(this._overrides.to, this._core)(position, speed);
13103		}
13104	};
13105
13106	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
13107
13108})(window.Zepto || window.jQuery, window, document);
13109
13110/**
13111 * Hash Plugin
13112 * @version 2.0.0-beta.3
13113 * @author Artus Kolanowski
13114 * @license The MIT License (MIT)
13115 */
13116;(function($, window, document, undefined) {
13117	'use strict';
13118
13119	/**
13120	 * Creates the hash plugin.
13121	 * @class The Hash Plugin
13122	 * @param {Owl} carousel - The Owl Carousel
13123	 */
13124	var Hash = function(carousel) {
13125		/**
13126		 * Reference to the core.
13127		 * @protected
13128		 * @type {Owl}
13129		 */
13130		this._core = carousel;
13131
13132		/**
13133		 * Hash index for the items.
13134		 * @protected
13135		 * @type {Object}
13136		 */
13137		this._hashes = {};
13138
13139		/**
13140		 * The carousel element.
13141		 * @type {jQuery}
13142		 */
13143		this.$element = this._core.$element;
13144
13145		/**
13146		 * All event handlers.
13147		 * @protected
13148		 * @type {Object}
13149		 */
13150		this._handlers = {
13151			/*'initialized.owl.carousel': $.proxy(function(e) {
13152				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
13153					$(window).trigger('hashchange.owl.navigation');
13154				}
13155			}, this),*/
13156			'prepared.owl.carousel': $.proxy(function(e) {
13157				if (e.namespace) {
13158					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
13159
13160					if (!hash) {
13161						return;
13162					}
13163
13164					this._hashes[hash] = e.content;
13165				}
13166			}, this),
13167			'changed.owl.carousel': $.proxy(function(e) {
13168				if (e.namespace && e.property.name === 'position') {
13169					var current = this._core.items(this._core.relative(this._core.current())),
13170						hash = $.map(this._hashes, function(item, hash) {
13171							return item === current ? hash : null;
13172						}).join();
13173
13174					if (!hash || window.location.hash.slice(1) === hash) {
13175						return;
13176					}
13177
13178					window.location.hash = hash;
13179				}
13180			}, this)
13181		};
13182
13183		// set default options
13184		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
13185
13186		// register the event handlers
13187		this.$element.on(this._handlers);
13188
13189		// register event listener for hash navigation
13190		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
13191			var hash = window.location.hash.substring(1),
13192				items = this._core.$stage.children(),
13193				position = this._hashes[hash] && items.index(this._hashes[hash]);
13194
13195			if (position === undefined || position === this._core.current()) {
13196				return;
13197			}
13198
13199			this._core.to(this._core.relative(position), false, true);
13200		}, this));*/
13201	};
13202
13203	/**
13204	 * Default options.
13205	 * @public
13206	 */
13207	Hash.Defaults = {
13208		URLhashListener: false
13209	};
13210
13211	/**
13212	 * Destroys the plugin.
13213	 * @public
13214	 */
13215	Hash.prototype.destroy = function() {
13216		var handler, property;
13217
13218		$(window).off('hashchange.owl.navigation');
13219
13220		for (handler in this._handlers) {
13221			this._core.$element.off(handler, this._handlers[handler]);
13222		}
13223		for (property in Object.getOwnPropertyNames(this)) {
13224			typeof this[property] != 'function' && (this[property] = null);
13225		}
13226	};
13227
13228	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
13229
13230})(window.Zepto || window.jQuery, window, document);
13231
13232/**
13233 * Support Plugin
13234 *
13235 * @version 2.0.0-beta.3
13236 * @author Vivid Planet Software GmbH
13237 * @author Artus Kolanowski
13238 * @license The MIT License (MIT)
13239 */
13240;(function($, window, document, undefined) {
13241
13242	var style = $('<support>').get(0).style,
13243		prefixes = 'Webkit Moz O ms'.split(' '),
13244		events = {
13245			transition: {
13246				end: {
13247					WebkitTransition: 'webkitTransitionEnd',
13248					MozTransition: 'transitionend',
13249					OTransition: 'oTransitionEnd',
13250					transition: 'transitionend'
13251				}
13252			},
13253			animation: {
13254				end: {
13255					WebkitAnimation: 'webkitAnimationEnd',
13256					MozAnimation: 'animationend',
13257					OAnimation: 'oAnimationEnd',
13258					animation: 'animationend'
13259				}
13260			}
13261		},
13262		tests = {
13263			csstransforms: function() {
13264				return !!test('transform');
13265			},
13266			csstransforms3d: function() {
13267				return !!test('perspective');
13268			},
13269			csstransitions: function() {
13270				return !!test('transition');
13271			},
13272			cssanimations: function() {
13273				return !!test('animation');
13274			}
13275		};
13276
13277	function test(property, prefixed) {
13278		var result = false,
13279			upper = property.charAt(0).toUpperCase() + property.slice(1);
13280
13281		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
13282			if (style[property] !== undefined) {
13283				result = prefixed ? property : true;
13284				return false;
13285			}
13286		});
13287
13288		return result;
13289	}
13290
13291	function prefixed(property) {
13292		return test(property, true);
13293	}
13294
13295	if (tests.csstransitions()) {
13296		/* jshint -W053 */
13297		$.support.transition = new String(prefixed('transition'))
13298		$.support.transition.end = events.transition.end[ $.support.transition ];
13299	}
13300
13301	if (tests.cssanimations()) {
13302		/* jshint -W053 */
13303		$.support.animation = new String(prefixed('animation'))
13304		$.support.animation.end = events.animation.end[ $.support.animation ];
13305	}
13306
13307	if (tests.csstransforms()) {
13308		/* jshint -W053 */
13309		$.support.transform = new String(prefixed('transform'));
13310		$.support.transform3d = tests.csstransforms3d();
13311	}
13312
13313})(window.Zepto || window.jQuery, window, document);
13314
13315(function(window, document, undefined) {
13316
13317    /**
13318     * Find the absolute position of an element
13319     */
13320    var absPos = function(element) {
13321        var offsetLeft, offsetTop;
13322        offsetLeft = offsetTop = 0;
13323        if (element.offsetParent) {
13324            do {
13325                offsetLeft += element.offsetLeft;
13326                offsetTop += element.offsetTop;
13327            } while (element = element.offsetParent);
13328        }
13329        return [offsetLeft, offsetTop];
13330    };
13331
13332    /**
13333     * @constructor Progress Circle class
13334     * @param params.canvas Canvas on which the circles will be drawn.
13335     * @param params.minRadius Inner radius of the innermost circle, in px.
13336     * @param params.arcWidth Width of each circle(to be more accurate, ring).
13337     * @param params.gapWidth Space between each circle.
13338     * @param params.centerX X coordinate of the center of circles.
13339     * @param params.centerY Y coordinate of the center of circles.
13340     * @param params.infoLineBaseAngle Base angle of the info line.
13341     * @param params.infoLineAngleInterval Angles between the info lines.
13342     */
13343    var ProgressCircle = function(params) {
13344        this.canvas = params.canvas;
13345        this.minRadius = params.minRadius || 15;
13346        this.arcWidth = params.arcWidth || 5;
13347        this.gapWidth = params.gapWidth || 3;
13348        this.centerX = params.centerX || this.canvas.width / 2;
13349        this.centerY = params.centerY || this.canvas.height / 2;
13350        this.infoLineLength = params.infoLineLength || 60;
13351        this.horizLineLength = params.horizLineLength || 10;
13352        this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
13353        this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
13354
13355        this.context = this.canvas.getContext('2d');
13356
13357        this.width = this.canvas.width;
13358        this.height = this.canvas.height;
13359
13360        this.circles = [];
13361        this.runningCount = 0;
13362    };
13363
13364    ProgressCircle.prototype = {
13365        constructor: ProgressCircle,
13366
13367        /**
13368         * @method Adds an progress monitor entry.
13369         * @param params.fillColor Color to fill in the circle.
13370         * @param params.outlineColor Color to outline the circle.
13371         * @param params.progressListener Callback function to fetch the progress.
13372         * @param params.infoListener Callback function to fetch the info.
13373         * @returns this
13374         */
13375        addEntry: function(params) {
13376            this.circles.push(new Circle({
13377                canvas: this.canvas,
13378                context: this.context,
13379                centerX: this.centerX,
13380                centerY: this.centerY,
13381                innerRadius: this.minRadius + this.circles.length *
13382                    (this.gapWidth + this.arcWidth),
13383                arcWidth: this.arcWidth,
13384                infoLineLength: this.infoLineLength,
13385                horizLineLength: this.horizLineLength,
13386
13387                id: this.circles.length,
13388                fillColor: params.fillColor,
13389                outlineColor: params.outlineColor,
13390                progressListener: params.progressListener,
13391                infoListener: params.infoListener,
13392                infoLineAngle: this.infoLineBaseAngle +
13393                    this.circles.length * this.infoLineAngleInterval,
13394            }));
13395
13396            return this;
13397        },
13398
13399        /**
13400         * @method Starts the monitor and updates with the given interval.
13401         * @param interval Interval between updates, in millisecond.
13402         * @returns this
13403         */
13404        start: function(interval) {
13405            var self = this;
13406            this.timer = setInterval(function() {
13407                self._update();
13408            }, interval || 33);
13409
13410            return this;
13411        },
13412
13413        /**
13414         * @method Stop the animation.
13415         */
13416        stop: function() {
13417            clearTimeout(this.timer);
13418        },
13419
13420        /**
13421         * @private
13422         * @method Call update on each circle and redraw them.
13423         * @returns this
13424         */
13425        _update: function() {
13426            this._clear();
13427            this.circles.forEach(function(circle, idx, array) {
13428                circle.update();
13429            });
13430
13431            return this;
13432        },
13433
13434        /**
13435         * @private
13436         * @method Clear the canvas.
13437         * @returns this
13438         */
13439        _clear: function() {
13440            this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
13441
13442            return this;
13443        },
13444
13445    };
13446
13447    /**
13448     * @private
13449     * @class Individual progress circle.
13450     * @param params.canvas Canvas on which the circle will be drawn.
13451     * @param params.context Context of the canvas.
13452     * @param params.innerRadius Inner radius of the circle, in px.
13453     * @param params.arcWidth Width of each arc(circle).
13454     * @param params.gapWidth Distance between each arc.
13455     * @param params.centerX X coordinate of the center of circles.
13456     * @param params.centerY Y coordinate of the center of circles.
13457     * @param params.fillColor Color to fill in the circle.
13458     * @param params.outlineColor Color to outline the circle.
13459     * @param params.progressListener Callback function to fetch the progress.
13460     * @param params.infoListener Callback function to fetch the info.
13461     * @param params.infoLineAngle Angle of info line.
13462     */
13463    var Circle = function(params) {
13464        this.id = params.id;
13465        this.canvas = params.canvas;
13466        this.context = params.context;
13467        this.centerX = params.centerX;
13468        this.centerY = params.centerY;
13469        this.arcWidth = params.arcWidth;
13470        this.innerRadius = params.innerRadius || 0;
13471        this.fillColor = params.fillColor || '#fff';
13472        this.outlineColor = params.outlineColor || this.fillColor;
13473        this.progressListener = params.progressListener;
13474        this.infoLineLength = params.infoLineLength || 250;
13475        this.horizLineLength = params.horizLineLength || 50;
13476        this.infoListener = params.infoListener;
13477        this.infoLineAngle = params.infoLineAngle;
13478
13479        this.outerRadius = this.innerRadius + this.arcWidth;
13480
13481        // If the info listener is not registered, then don't calculate
13482        // the related coordinates
13483        if (!this.infoListener) return;
13484
13485        // calculate the info-line turning points
13486        var angle = this.infoLineAngle,
13487            arcDistance = (this.innerRadius + this.outerRadius) / 2,
13488
13489            sinA = Math.sin(angle),
13490            cosA = Math.cos(angle);
13491
13492        this.infoLineStartX = this.centerX + sinA * arcDistance;
13493        this.infoLineStartY = this.centerY - cosA * arcDistance;
13494
13495        this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
13496        this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
13497
13498        this.infoLineEndX = this.infoLineMidX +
13499             (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
13500        this.infoLineEndY = this.infoLineMidY;
13501
13502        var infoText = document.createElement('div'),
13503            style = infoText.style;
13504
13505        style.color = this.fillColor;
13506        style.position = 'absolute';
13507        style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
13508        // style.top will be calculated in the `drawInfo` method. Since
13509        // user may want to change the size of the font, so the top offset
13510        // must be updated in each loop.
13511        infoText.className = 'ProgressCircleInfo'; // For css styling
13512        infoText.id = 'progress_circle_info_' + this.id;
13513        document.body.appendChild(infoText);
13514        this.infoText = infoText;
13515    };
13516
13517    Circle.prototype = {
13518        constructor: Circle,
13519
13520        update: function() {
13521            this.progress = this.progressListener();
13522            this._draw();
13523
13524            if (this.infoListener) {
13525                this.info = this.infoListener();
13526                this._drawInfo();
13527            }
13528        },
13529
13530        /**
13531         * @private
13532         * @method Draw the circle on the canvas.
13533         * @returns this
13534         */
13535        _draw: function() {
13536            var ctx = this.context,
13537
13538                ANGLE_OFFSET = -Math.PI / 2,
13539
13540                startAngle = 0 + ANGLE_OFFSET,
13541                endAngle= startAngle + this.progress * Math.PI * 2,
13542
13543                x = this.centerX,
13544                y = this.centerY,
13545
13546                innerRadius = this.innerRadius - this.arcWidth - 1,
13547                outerRadius = this.outerRadius - this.arcWidth - 1;
13548
13549            ctx.fillStyle = this.fillColor;
13550            ctx.strokeStyle = this.outlineColor;
13551
13552            ctx.beginPath();
13553            ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
13554            ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
13555            ctx.closePath();
13556            ctx.stroke();
13557            ctx.fill();
13558
13559            return this;
13560        },
13561
13562        /**
13563         * @private
13564         * @method Draw the info lines and info text.
13565         * @returns this
13566         */
13567        _drawInfo: function() {
13568
13569            var pointList, lineHeight;
13570
13571            pointList = [
13572                [this.infoLineStartX, this.infoLineStartY],
13573                [this.infoLineMidX, this.infoLineMidY],
13574                [this.infoLineEndX, this.infoLineEndY],
13575            ];
13576            this._drawSegments(pointList, false);
13577
13578            this.infoText.innerHTML = this.info;
13579
13580            lineHeight = this.infoText.offsetHeight;
13581            this.infoText.style.top = this.infoLineEndY +
13582                absPos(this.canvas)[1] - lineHeight / 2 + 'px';
13583
13584            return this;
13585        },
13586
13587        /**
13588         * @private
13589         * @method Helper function to draw the segments
13590         * @param pointList An array of points in the form of [x, y].
13591         * @param close Whether to connect the first and last point.
13592         */
13593        _drawSegments: function(pointList, close) {
13594            var ctx = this.context;
13595
13596            ctx.beginPath();
13597            ctx.moveTo(pointList[0][0], pointList[0][1]);
13598            for (var i = 1; i < pointList.length; ++i) {
13599                ctx.lineTo(pointList[i][0], pointList[i][1]);
13600            }
13601
13602            if (close) {
13603                ctx.closePath();
13604            }
13605            ctx.stroke();
13606        },
13607    };
13608
13609    window.ProgressCircle = ProgressCircle;
13610
13611})(window, document);
13612
13613
13614
13615
13616/* =========================================================
13617 * jquery.vc_chart.js v1.0
13618 * =========================================================
13619 * Copyright 2013 Wpbakery
13620 *
13621 * Jquery chart plugin for the Visual Composer.
13622 * ========================================================= */
13623(function($){
13624    /**
13625     * Pie chart animated.
13626     * @param element - DOM element
13627     * @param options - settings object.
13628     * @constructor
13629     */
13630    var VcChart = function(element, options) {
13631        this.el = element;
13632        this.$el = $(this.el);
13633        this.options = $.extend({
13634            color: 'wpb_button',
13635            units: '',
13636            width: '',
13637            label_selector: '.vc_pie_chart_value',
13638            back_selector: '.vc_pie_chart_back',
13639            responsive: true
13640        }, options);
13641        this.init();
13642    };
13643    VcChart.prototype = {
13644        constructor: VcChart,
13645        _progress_v: 0,
13646        animated: false,
13647        colors: {
13648            'wpb_button': 'rgba(247, 247, 247, 1)',
13649            'btn-primary': 'rgba(0, 136, 204, 1)',
13650            'btn-info': 'rgba(88, 185, 218, 1)',
13651            'btn-success': 'rgba(106, 177, 101, 1)',
13652            'btn-warning': 'rgba(255, 153, 0, 1)',
13653            'btn-danger': 'rgba(255, 103, 91, 1)',
13654            'btn-inverse': 'rgba(85, 85, 85, 1)'
13655        },
13656        init: function() {
13657            this.setupColor();
13658            this.value = this.$el.data('pie-value')/100;
13659            this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
13660            this.$wrapper = $('.vc_pie_wrapper', this.$el);
13661            this.$label = $(this.options.label_selector, this.$el);
13662            this.$back = $(this.options.back_selector, this.$el);
13663            this.$canvas = this.$el.find('canvas');
13664            this.arcWidth = this.$el.data('pie-width') * 2;
13665            this.draw();
13666            this.setWayPoint();
13667            if(this.options.responsive === true) this.setResponsive();
13668            if (UNCODE.isMobile) this._progress_v = this.value;
13669        },
13670        setupColor: function() {
13671            // if(typeof this.colors[this.options.color] !== 'undefined') {
13672            //     this.color = this.colors[this.options.color];
13673            // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
13674            //     this.color = this.options.color;
13675            // } else {
13676            //     this.color = 'rgba(247, 247, 247, 0.2)';
13677            // }
13678            if(typeof this.options.color !== 'undefined') {
13679                this.color = this.options.color;
13680            } else this.color = 'rgba(247, 247, 247, 0.2)';
13681
13682        },
13683        setResponsive: function() {
13684            var that = this;
13685            if (!UNCODE.isMobile) {
13686                $(window).resize(function(){
13687                    if(that.animated === true) that.circle.stop();
13688                    that.draw(true);
13689                });
13690            }
13691        },
13692          draw: function(redraw) {
13693            var w = this.$el.addClass('vc_ready').width() * 2,
13694                border_w = this.arcWidth,
13695                radius;
13696            if(!w) w = this.$el.parents(':visible').first().width()-2;
13697            //w = Math.round(w/100*80);
13698            //if (w < 250) w = 250;
13699            radius = w/2;
13700            this.$wrapper.css({"width" : (w / 2) + "px"});
13701            this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
13702            this.$back.css({"width" : (w / 2), "height" : (w / 2)});
13703            this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
13704            this.$el.addClass('vc_ready');
13705            this.circle = new ProgressCircle({
13706                canvas: this.$canvas.get(0),
13707                minRadius: radius,
13708                arcWidth: border_w
13709            });
13710            if(redraw === true && this.animated === true) {
13711                this._progress_v = this.value;
13712                this.circle.addEntry({
13713                    fillColor: this.color,
13714                    progressListener: $.proxy(this.setProgress, this)
13715                }).start();
13716            }
13717        },
13718        setProgress: function() {
13719            if (this._progress_v >= this.value) {
13720                this.circle.stop();
13721                this.$label.html(this.label_value + this.options.units);
13722                return this._progress_v;
13723            }
13724            this._progress_v += 0.01;
13725            if (!isNaN(this.label_value)) {
13726                var label_value = this._progress_v/this.value*this.label_value;
13727                var val = Math.round(label_value) + this.options.units;
13728                this.$label.html(val);
13729            } else this.$label.html(this.label_value + this.options.units);
13730            return this._progress_v;
13731        },
13732        animate: function() {
13733            if(this.animated !== true) {
13734                this.animated = true;
13735                this.circle.addEntry({
13736                    fillColor: this.color,
13737                    progressListener: $.proxy(this.setProgress, this)
13738                }).start(5);
13739            }
13740        },
13741        setWayPoint: function() {
13742            if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
13743                this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
13744            } else {
13745                this.animate();
13746            }
13747        }
13748    };
13749    /**
13750     * jQuery plugin
13751     * @param option - object with settings
13752     * @return {*}
13753     */
13754    $.fn.vcChat = function(option, value) {
13755        return this.each(function () {
13756            var $this = $(this),
13757                data = $this.data('vc_chart'),
13758                options = typeof option === 'object' ? option : {
13759                    color: $this.data('pie-color'),
13760                    units: $this.data('pie-units')
13761                };
13762            if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
13763            if (typeof option == 'string') data[option](value);
13764        });
13765    };
13766    /**
13767     * Allows users to rewrite function inside theme.
13768     */
13769    if ( typeof window['vc_pieChart'] !== 'function' ) {
13770        window.vc_pieChart = function() {
13771            $('.vc_pie_chart:visible').vcChat();
13772        }
13773    }
13774    $(document).ready(function(){
13775        !window.vc_iframe && vc_pieChart();
13776    });
13777
13778})(window.jQuery);
13779
13780
13781/* Progress bar
13782 ---------------------------------------------------------- */
13783function uncode_progress_bar() {    
13784	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
13785		if (!UNCODE.isMobile) {
13786			new Waypoint({
13787				element: val,
13788				handler: function() {
13789					var element = jQuery(this.element);
13790					element.find('.vc_single_bar').each(function(index) {          
13791						var $this = jQuery(this),
13792							            bar = $this.find('.vc_bar'),
13793							            val = bar.data('percentage-value');          
13794						setTimeout(function() {            
13795							bar.css({
13796								"width": val + '%'
13797							});          
13798						}, index * 200);        
13799					});
13800				},
13801				offset: '80%'
13802			});
13803		} else {
13804			var element = jQuery(val);
13805			element.find('.vc_single_bar').each(function(index) {          
13806				var $this = jQuery(this),
13807					            bar = $this.find('.vc_bar'),
13808					            val = bar.data('percentage-value');          
13809				setTimeout(function() {            
13810					bar.css({
13811						"width": val + '%'
13812					});          
13813				}, index * 200);        
13814			});
13815		}
13816	});
13817};
13818uncode_progress_bar();
13819
13820/*!
13821 * jquery.counterup.js 1.0
13822 *
13823 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
13824 * Released under the GPL v2 License
13825 *
13826 * Date: Nov 26, 2013
13827 */
13828(function($) {
13829	"use strict";
13830	$.fn.counterUp = function(options) {
13831		// Defaults
13832		var settings = $.extend({
13833			'time': 400,
13834			'delay': 10
13835		}, options);
13836		return this.each(function() {
13837			// Store the object
13838			var $this = $(this);
13839			var $settings = settings;
13840			var counterUpper = function() {
13841				var nums = [];
13842				var divisions = $settings.time / $settings.delay;
13843				var numReal = $this.text(),
13844				num = numReal;
13845				var isComma = /[0-9]+,[0-9]+/.test(num);
13846				num = num.replace(/,/g, '');
13847				var isInt = /^[0-9]+$/.test(num);
13848				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
13849				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
13850				// Generate list of incremental numbers to display
13851				for (var i = divisions; i >= 1; i--) {
13852					// Preserve as int if input was int
13853					var newNum = parseInt(num / divisions * i);
13854					// Preserve float if input was float
13855					if (isFloat) {
13856						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
13857					}
13858					// Preserve commas if input had commas
13859					if (isComma) {
13860						while (/(\d+)(\d{3})/.test(newNum.toString())) {
13861							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
13862						}
13863					}
13864					nums.unshift(newNum);
13865				}
13866				nums.push(numReal);
13867				$this.data('counterup-nums', nums);
13868				$this.text('0');
13869				// Updates the number until we're done
13870				var f = function() {
13871					if ($this.data('counterup-nums') != null) {
13872						$this.text($this.data('counterup-nums').shift());
13873						if ($this.data('counterup-nums').length) {
13874							setTimeout($this.data('counterup-func'), $settings.delay);
13875						} else {
13876							delete $this.data('counterup-nums');
13877							$this.data('counterup-nums', null);
13878							$this.data('counterup-func', null);
13879						}
13880					}
13881				};
13882				$this.data('counterup-func', f);
13883				// Start the count up
13884				setTimeout($this.data('counterup-func'), $settings.delay);
13885			};
13886			// Perform counts when the element gets into view
13887			new Waypoint({
13888				element: this,
13889				handler: function() {
13890					counterUpper();
13891					this.destroy();
13892				},
13893				offset: '80%'
13894			});
13895		});
13896	};
13897})(jQuery);
13898
13899/*!
13900 * The Final Countdown for jQuery v2.0.4 (http://hilios.github.io/jQuery.countdown/)
13901 * Copyright (c) 2014 Edson Hilios
13902 * 
13903 * Permission is hereby granted, free of charge, to any person obtaining a copy of
13904 * this software and associated documentation files (the "Software"), to deal in
13905 * the Software without restriction, including without limitation the rights to
13906 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13907 * the Software, and to permit persons to whom the Software is furnished to do so,
13908 * subject to the following conditions:
13909 * 
13910 * The above copyright notice and this permission notice shall be included in all
13911 * copies or substantial portions of the Software.
13912 * 
13913 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13914 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
13915 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13916 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13917 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
13918 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13919 */
13920!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){"use strict";function b(a){if(a instanceof Date)return a;
13920if(String(a).match(h))return String(a).match(/^[0-9]*$/)&&(a=Number(a)),String(a).match(/\-/)&&(a=String(a).replace(/\-/g,"/")),new Date(a);throw new Error("Couldn't cast `"+a+"` to a date object.")}function c(a){var b=a.toString().replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1");return new RegExp(b)}function d(a){return function(b){var d=b.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi);if(d)for(var f=0,g=d.length;g>f;++f){var h=d[f].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/),j=c(h[0]),k=h[1]||"",l=h[3]||"",m=null;h=h[2],i.hasOwnProperty(h)&&(m=i[h],m=Number(a[m])),null!==m&&("!"===k&&(m=e(l,m)),""===k&&10>m&&(m="0"+m.toString()),b=b.replace(j,m.toString()))}return b=b.replace(/%%/,"%")}}function e(a,b){var c="s",d="";return a&&(a=a.replace(/(:|;|\s)/gi,"").split(/\,/),1===a.length?c=a[0]:(d=a[0],c=a[1])),1===Math.abs(b)?d:c}var f=100,g=[],h=[];h.push(/^[0-9]*$/.source),h.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source),h.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source),h=new RegExp(h.join("|"));var i={Y:"years",m:"months",w:"weeks",d:"days",D:"totalDays",H:"hours",M:"minutes",S:"seconds"},j=function(b,c,d){this.el=b,this.$el=a(b),this.interval=null,this.offset={},this.instanceNumber=g.length,g.push(this),this.$el.data("countdown-instance",this.instanceNumber),d&&(this.$el.on("update.countdown",d),this.$el.on("stoped.countdown",d),this.$el.on("finish.countdown",d)),this.setFinalDate(c),this.start()};a.extend(j.prototype,{start:function(){null!==this.interval&&clearInterval(this.interval);var a=this;this.update(),this.interval=setInterval(function(){a.update.call(a)},f)},stop:function(){clearInterval(this.interval),this.interval=null,this.dispatchEvent("stoped")},toggle:function(){this.interval?this.stop():this.start()},pause:function(){this.stop()},resume:function(){this.start()},remove:function(){this.stop.call(this),g[this.instanceNumber]=null,delete this.$el.data().countdownInstance},setFinalDate:function(a){this.finalDate=b(a)},update:function(){return 0===this.$el.closest("html").length?void this.remove():(this.totalSecsLeft=this.finalDate.getTime()-(new Date).getTime(),this.totalSecsLeft=Math.ceil(this.totalSecsLeft/1e3),this.totalSecsLeft=this.totalSecsLeft<0?0:this.totalSecsLeft,this.offset={seconds:this.totalSecsLeft%60,minutes:Math.floor(this.totalSecsLeft/60)%60,hours:Math.floor(this.totalSecsLeft/60/60)%24,days:Math.floor(this.totalSecsLeft/60/60/24)%7,totalDays:Math.floor(this.totalSecsLeft/60/60/24),weeks:Math.floor(this.totalSecsLeft/60/60/24/7),months:Math.floor(this.totalSecsLeft/60/60/24/30),years:Math.floor(this.totalSecsLeft/60/60/24/365)},void(0===this.totalSecsLeft?(this.stop(),this.dispatchEvent("finish")):this.dispatchEvent("update")))},dispatchEvent:function(b){var c=a.Event(b+".countdown");c.finalDate=this.finalDate,c.offset=a.extend({},this.offset),c.strftime=d(this.offset),this.$el.trigger(c)}}),a.fn.countdown=function(){var b=Array.prototype.slice.call(arguments,0);return this.each(function(){var c=a(this).data("countdown-instance");if(void 0!==c){var d=g[c],e=b[0];j.prototype.hasOwnProperty(e)?d[e].apply(d,b.slice(1)):null===String(e).match(/^[$A-Z_][0-9A-Z_$]*$/i)?(d.setFinalDate.call(d,e),d.start()):a.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi,e))}else new j(this,b[0],b[1])})}});
13921
13922/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05
13923* https://github.com/alexanderdickson/waitForImages
13924* Copyright (c) 2015 Alex Dickson; Licensed MIT */
13925;(function (factory) {
13926    if (typeof define === 'function' && define.amd) {
13927        // AMD. Register as an anonymous module.
13928        define(['jquery'], factory);
13929    } else if (typeof exports === 'object') {
13930        // CommonJS / nodejs module
13931        module.exports = factory(require('jquery'));
13932    } else {
13933        // Browser globals
13934        factory(jQuery);
13935    }
13936}(function ($) {
13937    // Namespace all events.
13938    var eventNamespace = 'waitForImages';
13939
13940    // CSS properties which contain references to images.
13941    $.waitForImages = {
13942        hasImageProperties: [
13943            'backgroundImage',
13944            'listStyleImage',
13945            'borderImage',
13946            'borderCornerImage',
13947            'cursor'
13948        ],
13949        hasImageAttributes: ['srcset']
13950    };
13951
13952    // Custom selector to find `img` elements that have a valid `src`
13953    // attribute and have not already loaded.
13954    $.expr[':'].uncached = function (obj) {
13955        // Ensure we are dealing with an `img` element with a valid
13956        // `src` attribute.
13957        if (!$(obj).is('img[src][src!=""]')) {
13958            return false;
13959        }
13960
13961        return !obj.complete;
13962    };
13963
13964    $.fn.waitForImages = function () {
13965
13966        var allImgsLength = 0;
13967        var allImgsLoaded = 0;
13968        var deferred = $.Deferred();
13969
13970        var finishedCallback;
13971        var eachCallback;
13972        var waitForAll;
13973
13974        // Handle options object (if passed).
13975        if ($.isPlainObject(arguments[0])) {
13976
13977            waitForAll = arguments[0].waitForAll;
13978            eachCallback = arguments[0].each;
13979            finishedCallback = arguments[0].finished;
13980
13981        } else {
13982
13983            // Handle if using deferred object and only one param was passed in.
13984            if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
13985                waitForAll = arguments[0];
13986            } else {
13987                finishedCallback = arguments[0];
13988                eachCallback = arguments[1];
13989                waitForAll = arguments[2];
13990            }
13991
13992        }
13993
13994        // Handle missing callbacks.
13995        finishedCallback = finishedCallback || $.noop;
13996        eachCallback = eachCallback || $.noop;
13997
13998        // Convert waitForAll to Boolean
13999        waitForAll = !! waitForAll;
14000
14001        // Ensure callbacks are functions.
14002        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
14003            throw new TypeError('An invalid callback was supplied.');
14004        }
14005
14006        this.each(function () {
14007            // Build a list of all imgs, dependent on what images will
14008            // be considered.
14009            var obj = $(this);
14010            var allImgs = [];
14011            // CSS properties which may contain an image.
14012            var hasImgProperties = $.waitForImages.hasImageProperties || [];
14013            // Element attributes which may contain an image.
14014            var hasImageAttributes = $.waitForImages.hasImageAttributes || [];
14015            // To match `url()` references.
14016            // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
14017            var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
14018
14019            if (waitForAll) {
14020
14021                // Get all elements (including the original), as any one of
14022                // them could have a background image.
14023                obj.find('*').addBack().each(function () {
14024                    var element = $(this);
14025
14026                    // If an `img` element, add it. But keep iterating in
14027                    // case it has a background image too.
14028                    if (element.is('img:uncached')) {
14029                        allImgs.push({
14030                            src: element.attr('src'),
14031                            element: element[0]
14032                        });
14033                    }
14034
14035                    $.each(hasImgProperties, function (i, property) {
14036                        var propertyValue = element.css(property);
14037                        var match;
14038
14039                        // If it doesn't contain this property, skip.
14040                        if (!propertyValue) {
14041                            return true;
14042                        }
14043
14044                        // Get all url() of this element.
14045                        while (match = matchUrl.exec(propertyValue)) {
14046                            allImgs.push({
14047                                src: match[2],
14048                                element: element[0]
14049                            });
14050                        }
14051                    });
14052
14053                    $.each(hasImageAttributes, function (i, attribute) {
14054                        var attributeValue = element.attr(attribute);
14055                        var attributeValues;
14056
14057                        // If it doesn't contain this property, skip.
14058                        if (!attributeValue) {
14059                            return true;
14060                        }
14061
14062                        // Check for multiple comma separated images
14063                        attributeValues = attributeValue.split(',');
14064
14065                        $.each(attributeValues, function(i, value) {
14066                            // Trim value and get string before first
14067                            // whitespace (for use with srcset).
14068                            value = $.trim(value).split(' ')[0];
14069                            allImgs.push({
14070                                src: value,
14071                                element: element[0]
14072                            });
14073                        });
14074                    });
14075                });
14076            } else {
14077                // For images only, the task is simpler.
14078                obj.find('img:uncached')
14079                    .each(function () {
14080                    allImgs.push({
14081                        src: this.src,
14082                        element: this
14083                    });
14084                });
14085            }
14086
14087            allImgsLength = allImgs.length;
14088            allImgsLoaded = 0;
14089
14090            // If no images found, don't bother.
14091            if (allImgsLength === 0) {
14092                finishedCallback.call(obj[0]);
14093                deferred.resolveWith(obj[0]);
14094            }
14095
14096            $.each(allImgs, function (i, img) {
14097
14098                var image = new Image();
14099                var events =
14100                  'load.' + eventNamespace + ' error.' + eventNamespace;
14101
14102                // Handle the image loading and error with the same callback.
14103                $(image).one(events, function me (event) {
14104                    // If an error occurred with loading the image, set the
14105                    // third argument accordingly.
14106                    var eachArguments = [
14107                        allImgsLoaded,
14108                        allImgsLength,
14109                        event.type == 'load'
14110                    ];
14111                    allImgsLoaded++;
14112
14113                    eachCallback.apply(img.element, eachArguments);
14114                    deferred.notifyWith(img.element, eachArguments);
14115
14116                    // Unbind the event listeners. I use this in addition to
14117                    // `one` as one of those events won't be called (either
14118                    // 'load' or 'error' will be called).
14119                    $(this).off(events, me);
14120
14121                    if (allImgsLoaded == allImgsLength) {
14122                        finishedCallback.call(obj[0]);
14123                        deferred.resolveWith(obj[0]);
14124                        return false;
14125                    }
14126
14127                });
14128
14129                image.src = img.src;
14130            });
14131        });
14132
14133        return deferred.promise();
14134
14135    };
14136}));
14137
14138/**
14139 * @preserve  textfill
14140 * @name      jquery.textfill.js
14141 * @author    Russ Painter
14142 * @author    Yu-Jie Lin
14143 * @author    Alexandre Dantas
14144 * @version   0.6.0
14145 * @date      2014-08-19
14146 * @copyright (c) 2014 Alexandre Dantas
14147 * @copyright (c) 2012-2013 Yu-Jie Lin
14148 * @copyright (c) 2009 Russ Painter
14149 * @license   MIT License
14150 * @homepage  https://github.com/jquery-textfill/jquery-textfill
14151 * @example   http://jquery-textfill.github.io/jquery-textfill/index.html
14152 */
14153; (function($) {
14154
14155	/**
14156	 * Resizes an inner element's font so that the
14157	 * inner element completely fills the outer element.
14158	 *
14159	 * @param {Object} options User options that take
14160	 *                         higher precedence when
14161	 *                         merging with the default ones.
14162	 *
14163	 * @return All outer elements processed
14164	 */
14165	$.fn.textfill = function(options) {
14166
14167		// ______  _______ _______ _______ _     _        _______ _______
14168		// |     \ |______ |______ |_____| |     | |         |    |______
14169		// |_____/ |______ |       |     | |_____| |_____    |    ______|
14170        //
14171		// Merging user options with the default values
14172
14173		var defaults = {
14174			debug            : false,
14175			maxFontPixels    : 40,
14176			minFontPixels    : 4,
14177			innerTag         : 'span',
14178			widthOnly        : false,
14179			success          : null, // callback when a resizing is done
14180			callback         : null, // callback when a resizing is done (deprecated, use success)
14181			fail             : null, // callback when a resizing is failed
14182			complete         : null, // callback when all is done
14183			explicitWidth    : null,
14184			explicitHeight   : null,
14185			changeLineHeight : false
14186		};
14187
14188		var Opts = $.extend(defaults, options);
14189
14190		// _______ _     _ __   _ _______ _______ _____  _____  __   _ _______
14191		// |______ |     | | \  | |          |      |   |     | | \  | |______
14192		// |       |_____| |  \_| |_____     |    __|__ |_____| |  \_| ______|
14193		//
14194		// Predefining the awesomeness
14195
14196		// Output arguments to the Debug console
14197		// if "Debug Mode" is enabled
14198		function _debug() {
14199			if (!Opts.debug
14200				||  typeof console       == 'undefined'
14201				||  typeof console.debug == 'undefined') {
14202				return;
14203			}
14204			console.debug.apply(console, arguments);
14205		}
14206
14207		// Output arguments to the Warning console
14208		function _warn() {
14209			if (typeof console      == 'undefined' ||
14210				typeof console.warn == 'undefined') {
14211				return;
14212			}
14213			console.warn.apply(console, arguments);
14214		}
14215
14216		// Outputs all information on the current sizing
14217		// of the font.
14218		function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
14219
14220			function _m(v1, v2) {
14221
14222				var marker = ' / ';
14223
14224				if (v1 > v2)
14225					marker = ' > ';
14226
14227				else if (v1 == v2)
14228					marker = ' = ';
14229
14230				return marker;
14231			}
14232
14233			_debug(
14234				'[TextFill] '  + prefix + ' { ' +
14235				'font-size: ' + ourText.css('font-size') + ',' +
14236				'Height: '    + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' +
14237				'Width: '     + ourText.width()  + _m(ourText.width() , maxWidth)  + maxWidth + ',' +
14238				'minFontPixels: ' + minFontPixels + 'px, ' +
14239				'maxFontPixels: ' + maxFontPixels + 'px }'
14240			);
14241		}
14242
14243		/**
14244		 * Calculates which size the font can get resized,
14245		 * according to constrains.
14246		 *
14247		 * @param {String} prefix Gets shown on the console before
14248		 *                        all the arguments, if debug mode is on.
14249		 * @param {Object} ourText The DOM element to resize,
14250		 *                         that contains the text.
14251		 * @param {function} func Function called on `ourText` that's
14252		 *                        used to compare with `max`.
14253		 * @param {number} max Maximum value, that gets compared with
14254		 *                     `func` called on `ourText`.
14255		 * @param {number} minFontPixels Minimum value the font can
14256		 *                               get resized to (in pixels).
14257		 * @param {number} maxFontPixels Maximum value the font can
14258		 *                               get resized to (in pixels).
14259		 *
14260		 * @return Size (in pixels) that the font can be resized.
14261		 */
14262		function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
14263
14264			_debug_sizing(
14265				prefix, ourText,
14266				maxHeight, maxWidth,
14267				minFontPixels, maxFontPixels
14268			);
14269
14270			// The kernel of the whole plugin, take most attention
14271			// on this part.
14272			//
14273			// This is a loop that keeps increasing the `font-size`
14274			// until it fits the parent element.
14275			//
14276			// - Start from the minimal allowed value (`minFontPixels`)
14277			// - Guesses an average font size (in pixels) for the font,
14278			// - Resizes the text and sees if its size is within the
14279			//   boundaries (`minFontPixels` and `maxFontPixels`).
14280			//   - If so, keep guessing until we break.
14281			//   - If not, return the last calculated size.
14282			//
14283			// I understand this is not optimized and we should
14284			// consider implementing something akin to
14285			// Daniel Hoffmann's answer here:
14286			//
14287			//     http://stackoverflow.com/a/17433451/1094964
14288			//
14289
14290			while (minFontPixels < (maxFontPixels - 1)) {
14291
14292				var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2);
14293				ourText.css('font-size', fontSize);
14294
14295				if (func.call(ourText) <= max) {
14296					minFontPixels = fontSize;
14297
14298					if (func.call(ourText) == max)
14299						break;
14300				}
14301				else
14302					maxFontPixels = fontSize;
14303
14304				_debug_sizing(
14305					prefix, ourText,
14306					maxHeight, maxWidth,
14307					minFontPixels, maxFontPixels
14308				);
14309			}
14310
14311			ourText.css('font-size', maxFontPixels);
14312
14313			if (func.call(ourText) <= max) {
14314				minFontPixels = maxFontPixels;
14315
14316				_debug_sizing(
14317					prefix + '* ', ourText,
14318					maxHeight, maxWidth,
14319					minFontPixels, maxFontPixels
14320				);
14321			}
14322			return minFontPixels;
14323		}
14324
14325		// _______ _______ _______  ______ _______
14326		// |______    |    |_____| |_____/    |
14327		// ______|    |    |     | |    \_    |
14328        //
14329		// Let's get it started (yeah)!
14330
14331		_debug('[TextFill] Start Debug');
14332
14333		this.each(function() {
14334
14335			// Contains the child element we will resize.
14336			// $(this) means the parent container
14337			var ourText = $(Opts.innerTag + ':visible:first', this);
14338
14339			// Will resize to this dimensions.
14340			// Use explicit dimensions when specified
14341			var maxHeight = Opts.explicitHeight || $(this).height();
14342			var maxWidth  = Opts.explicitWidth  || $(this).width();
14343
14344			var oldFontSize = ourText.css('font-size');
14345
14346			var lineHeight  = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize);
14347
14348			_debug('[TextFill] Inner text: ' + ourText.text());
14349			_debug('[TextFill] All options: ', Opts);
14350			_debug('[TextFill] Maximum sizes: { ' +
14351				   'Height: ' + maxHeight + 'px, ' +
14352				   'Width: '  + maxWidth  + 'px' + ' }'
14353				  );
14354
14355			var minFontPixels = Opts.minFontPixels;
14356
14357			// Remember, if this `maxFontPixels` is negative,
14358			// the text will resize to as long as the container
14359			// can accomodate
14360			var maxFontPixels = (Opts.maxFontPixels <= 0 ?
14361								 maxHeight :
14362								 Opts.maxFontPixels);
14363
14364
14365			// Let's start it all!
14366
14367			// 1. Calculate which `font-size` would
14368			//    be best for the Height
14369			var fontSizeHeight = undefined;
14370
14371			if (! Opts.widthOnly)
14372				fontSizeHeight = _sizing(
14373					'Height', ourText,
14374					$.fn.height, maxHeight,
14375					maxHeight, maxWidth,
14376					minFontPixels, maxFontPixels
14377				);
14378
14379			// 2. Calculate which `font-size` would
14380			//    be best for the Width
14381			var fontSizeWidth = undefined;
14382
14383			fontSizeWidth = _sizing(
14384				'Width', ourText,
14385				$.fn.width, maxWidth,
14386				maxHeight, maxWidth,
14387				minFontPixels, maxFontPixels
14388			);
14389
14390			// 3. Actually resize the text!
14391
14392			if (Opts.widthOnly) {
14393				ourText.css({
14394					'font-size'  : fontSizeWidth,
14395					'white-space': 'nowrap'
14396				});
14397
14398				if (Opts.changeLineHeight)
14399					ourText.parent().css(
14400						'line-height',
14401						(lineHeight * fontSizeWidth + 'px')
14402					);
14403			}
14404			else {
14405				var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth);
14406
14407				ourText.css('font-size', fontSizeFinal);
14408
14409				if (Opts.changeLineHeight)
14410					ourText.parent().css(
14411						'line-height',
14412						(lineHeight * fontSizeFinal) + 'px'
14413					);
14414			}
14415
14416			_debug(
14417				'[TextFill] Finished { ' +
14418				'Old font-size: ' + oldFontSize              + ', ' +
14419				'New font-size: ' + ourText.css('font-size') + ' }'
14420			);
14421
14422			// Oops, something wrong happened!
14423			// We weren't supposed to exceed the original size
14424			if ((ourText.width()  > maxWidth) ||
14425				(ourText.height() > maxHeight && !Opts.widthOnly)) {
14426
14427				ourText.css('font-size', oldFontSize);
14428
14429				// Failure callback
14430				if (Opts.fail)
14431					Opts.fail(this);
14432
14433				_debug(
14434					'[TextFill] Failure { ' +
14435					'Current Width: '  + ourText.width()  + ', ' +
14436					'Maximum Width: '  + maxWidth         + ', ' +
14437					'Current Height: ' + ourText.height() + ', ' +
14438					'Maximum Height: ' + maxHeight        + ' }'
14439				);
14440			}
14441			else if (Opts.success) {
14442				Opts.success(this);
14443			}
14444			else if (Opts.callback) {
14445				_warn('callback is deprecated, use success, instead');
14446
14447				// Success callback
14448				Opts.callback(this);
14449			}
14450		});
14451
14452		// Complete callback
14453		if (Opts.complete)
14454			Opts.complete(this);
14455
14456		_debug('[TextFill] End Debug');
14457		return this;
14458	};
14459
14460})(window.jQuery);
14461
14462
14463!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;
14464function getStyles(config){
14465  // 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;
14465left: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+"}"
14466};
14467  var ShareUtils;
14468
14469if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
14470  Object.defineProperty(HTMLElement.prototype, "classList", {
14471    get: function() {
14472      var ret, self, update;
14473      update = function(fn) {
14474        return function(value) {
14475          var classes, index;
14476          classes = self.className.split(/\s+/);
14477          index = classes.indexOf(value);
14478          fn(classes, index, value);
14479          self.className = classes.join(" ");
14480        };
14481      };
14482      self = this;
14483      ret = {
14484        add: update(function(classes, index, value) {
14485          ~index || classes.push(value);
14486        }),
14487        remove: update(function(classes, index) {
14488          ~index && classes.splice(index, 1);
14489        }),
14490        toggle: update(function(classes, index, value) {
14491          if (~index) {
14492            classes.splice(index, 1);
14493          } else {
14494            classes.push(value);
14495          }
14496        }),
14497        contains: function(value) {
14498          return !!~self.className.split(/\s+/).indexOf(value);
14499        },
14500        item: function(i) {
14501          return self.className.split(/\s+/)[i] || null;
14502        }
14503      };
14504      Object.defineProperty(ret, "length", {
14505        get: function() {
14506          return self.className.split(/\s+/).length;
14507        }
14508      });
14509      return ret;
14510    }
14511  });
14512}
14513
14514String.prototype.to_rfc3986 = function() {
14515  var tmp;
14516  tmp = encodeURIComponent(this);
14517  return tmp.replace(/[!'()*]/g, function(c) {
14518    return "%" + c.charCodeAt(0).toString(16);
14519  });
14520};
14521
14522ShareUtils = (function() {
14523  function ShareUtils() {}
14524
14525  ShareUtils.prototype.extend = function(to, from, overwrite) {
14526    var hasProp, prop;
14527    for (prop in from) {
14528      hasProp = to[prop] !== undefined;
14529      if (hasProp && typeof from[prop] === "object") {
14530        this.extend(to[prop], from[prop], overwrite);
14531      } else {
14532        if (overwrite || !hasProp) {
14533          to[prop] = from[prop];
14534        }
14535      }
14536    }
14537  };
14538
14539  ShareUtils.prototype.hide = function(el) {
14540    return el.style.display = "none";
14541  };
14542
14543  ShareUtils.prototype.show = function(el) {
14544    return el.style.display = "block";
14545  };
14546
14547  ShareUtils.prototype.has_class = function(el, class_name) {
14548    return el.classList.contains(class_name);
14549  };
14550
14551  ShareUtils.prototype.add_class = function(el, class_name) {
14552    return el.classList.add(class_name);
14553  };
14554
14555  ShareUtils.prototype.remove_class = function(el, class_name) {
14556    return el.classList.remove(class_name);
14557  };
14558
14559  ShareUtils.prototype.is_encoded = function(str) {
14560    str = str.to_rfc3986();
14561    return decodeURIComponent(str) !== str;
14562  };
14563
14564  ShareUtils.prototype.encode = function(str) {
14565    if (typeof str === "undefined" || this.is_encoded(str)) {
14566      return str;
14567    } else {
14568      return str.to_rfc3986();
14569    }
14570  };
14571
14572  ShareUtils.prototype.popup = function(url, params) {
14573    var k, popup, qs, v;
14574    if (params == null) {
14575      params = {};
14576    }
14577    popup = {
14578      width: 500,
14579      height: 350
14580    };
14581    popup.top = (screen.height / 2) - (popup.height / 2);
14582    popup.left = (screen.width / 2) - (popup.width / 2);
14583    qs = ((function() {
14584      var _results;
14585      _results = [];
14586      for (k in params) {
14587        v = params[k];
14588        _results.push("" + k + "=" + (this.encode(v)));
14589      }
14590      return _results;
14591    }).call(this)).join('&');
14592    if (qs) {
14593      qs = "?" + qs;
14594    }
14595    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=" 
14595+ popup.width + ",height=" + popup.height);
14596  };
14597
14598  return ShareUtils;
14599
14600})();
14601var Share,
14602  __hasProp = {}.hasOwnProperty,
14603  __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; };
14604
14605Share = (function(_super) {
14606  __extends(Share, _super);
14607
14608  function Share(element, options) {
14609    this.element = element;
14610    this.el = {
14611      head: document.getElementsByTagName('head')[0],
14612      body: document.getElementsByTagName('body')[0]
14613    };
14614    this.config = {
14615      enabled_networks: 0,
14616      protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
14617      url: window.location.href,
14618      caption: null,
14619      title: this.default_title(),
14620      image: this.default_image(),
14621      description: this.default_description(),
14622      ui: {
14623        flyout: 'top center',
14624        button_text: 'Share',
14625        button_font: true,
14626        icon_font: true
14627      },
14628      networks: {
14629        google_plus: {
14630          enabled: true,
14631          url: null
14632        },
14633        twitter: {
14634          enabled: true,
14635          url: null,
14636          title: null,
14637          description: null
14638        },
14639        facebook: {
14640          enabled: true,
14641          load_sdk: true,
14642          url: null,
14643          app_id: null,
14644          title: null,
14645          caption: null,
14646          description: null,
14647          image: null
14648        },
14649        pinterest: {
14650          enabled: true,
14651          url: null,
14652          image: null,
14653          description: null
14654        },
14655        reddit: {
14656          enabled: true,
14657          url: null,
14658          title: null
14659        },
14660        linkedin: {
14661          enabled: true,
14662          url: null,
14663          title: null,
14664          description: null
14665        },
14666        xing: {
14667          enabled: true,
14668          url: null,
14669          title: null,
14670          image: null,
14671          description: null
14672        },
14673        whatsapp: {
14674          enabled: true,
14675          description: null,
14676          url: null
14677        },
14678        email: {
14679          enabled: true,
14680          title: null,
14681          description: null,
14682          url: null
14683        }
14684      }
14685    };
14686    this.setup(element, options);
14687    return this;
14688  }
14689
14690  Share.prototype.setup = function(element, opts) {
14691    var index, instance, instances, _i, _len;
14692    instances = document.querySelectorAll(element);
14693    this.extend(this.config, opts, true);
14694    this.set_global_configuration();
14695    this.normalize_network_configuration();
14696    if (this.config.ui.icon_font) {
14697      this.inject_icons();
14698    }
14699    if (this.config.ui.button_font) {
14700      this.inject_fonts();
14701    }
14702    if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
14703      this.inject_facebook_sdk();
14704    }
14705    for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
14706      instance = instances[index];
14707      this.setup_instance(element, index);
14708    }
14709  };
14710
14711  Share.prototype.setup_instance = function(element, index) {
14712    var button, instance, label, network, networks, _i, _len, _results,
14713      _this = this;
14714    instance = document.querySelectorAll(element)[index];
14715    this.hide(instance);
14716    this.add_class(instance, "sharer-" + index);
14717    instance = document.querySelectorAll(element)[index];
14718    this.inject_css(instance);
14719    this.inject_html(instance);
14720    this.show(instance);
14721    label = instance.getElementsByTagName("label")[0];
14722    button = instance.getElementsByClassName("social")[0];
14723    networks = instance.getElementsByTagName('li');
14724    this.add_class(button, "networks-" + this.config.enabled_networks);
14725    label.addEventListener("click", function() {
14726      return _this.event_toggle(button);
14727    });
14728    _this = this;
14729    _results = [];
14730    for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
14731      network = networks[index];
14732      _results.push(network.addEventListener("click", function() {
14733        _this.event_network(instance, this);
14734        return _this.event_close(button);
14735      }));
14736    }
14737    return _results;
14738  };
14739
14740  Share.prototype.event_toggle = function(button) {
14741    if (this.has_class(button, "active")) {
14742      return this.event_close(button);
14743    } else {
14744      return this.event_open(button);
14745    }
14746  };
14747
14748  Share.prototype.event_open = function(button) {
14749    if (this.has_class(button, "load")) {
14750      this.remove_class(button, "load");
14751    }
14752    return this.add_class(button, "active");
14753  };
14754
14755  Share.prototype.event_close = function(button) {
14756    return this.remove_class(button, "active");
14757  };
14758
14759  Share.prototype.event_network = function(instance, network) {
14760    var name;
14761    name = network.getAttribute("data-network");
14762    this.hook("before", name, instance);
14763    this["network_" + name]();
14764    return this.hook("after", name, instance);
14765  };
14766
14767  Share.prototype.open = function() {
14768    return this["public"]("open");
14769  };
14770
14771  Share.prototype.close = function() {
14772    return this["public"]("close");
14773  };
14774
14775  Share.prototype.toggle = function() {
14776    return this["public"]("toggle");
14777  };
14778
14779  Share.prototype["public"] = function(action) {
14780    var button, index, instance, _i, _len, _ref, _results;
14781    _ref = document.querySelectorAll(this.element);
14782    _results = [];
14783    for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
14784      instance = _ref[index];
14785      button = instance.getElementsByClassName("social")[0];
14786      _results.push(this["event_" + action](button));
14787    }
14788    return _results;
14789  };
14790
14791  Share.prototype.network_facebook = function() {
14792    if (this.config.networks.facebook.load_sdk) {
14793      if (!window.FB) {
14794        return console.error("The Facebook JS SDK hasn't loaded yet.");
14795      }
14796      return FB.ui({
14797        method: 'feed',
14798        name: this.config.networks.facebook.title,
14799        link: this.config.networks.facebook.url,
14800        picture: this.config.networks.facebook.image,
14801        caption: this.config.networks.facebook.caption,
14802        description: this.config.networks.facebook.description
14803      });
14804    } else {
14805      return this.popup('https://www.facebook.com/sharer/sharer.php', {
14806        u: this.config.networks.facebook.url
14807      });
14808    }
14809  };
14810
14811  Share.prototype.network_twitter = function() {
14812    return this.popup('https://twitter.com/intent/tweet', {
14813      text: this.config.networks.twitter.title,
14814      url: this.config.networks.twitter.url
14815    });
14816  };
14817
14818  Share.prototype.network_google_plus = function() {
14819    return this.popup('https://plus.google.com/share', {
14820      url: this.config.networks.google_plus.url
14821    });
14822  };
14823
14824  Share.prototype.network_pinterest = function() {
14825    return this.popup('https://www.pinterest.com/pin/create/button', {
14826      url: this.config.networks.pinterest.url,
14827      media: this.config.networks.pinterest.image,
14828      description: this.config.networks.pinterest.description
14829    });
14830  };
14831
14832  Share.prototype.network_linkedin = function() {
14833    return this.popup('https://www.linkedin.com/shareArticle', {
14834      url: this.config.networks.linkedin.url,
14835      title: this.config.networks.linkedin.title,
14836      summary: this.config.networks.linkedin.description
14837    });
14838  }
14839
14840  Share.prototype.network_xing = function() {
14841    return this.popup('https://www.xing.com/spi/shares/new', {
14842      url: this.config.networks.xing.url,
14843      image: this.config.networks.xing.image,
14844      title: this.config.networks.xing.title,
14845      summary: this.config.networks.xing.description
14846    });
14847  }
14848
14849  Share.prototype.network_email = function() {
14850    return this.popup('mailto:', {
14851      subject: this.config.networks.email.title,
14852      body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
14853    });
14854  };
14855
14856  Share.prototype.inject_icons = function() {
14857  //  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
14858  };
14859
14860  Share.prototype.inject_fonts = function() {
14861   // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
14862  };
14863
14864  Share.prototype.inject_stylesheet = function(url) {
14865    var link;
14866    if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
14867      link = document.createElement("link");
14868      link.setAttribute("rel", "stylesheet");
14869      link.setAttribute("href", url);
14870      return this.el.head.appendChild(link);
14871    }
14872  };
14873
14874  Share.prototype.inject_css = function(instance) {
14875    var css, meta, selector, style;
14876    selector = "." + (instance.getAttribute('class').split(" ").join("."));
14877    if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
14878      this.config.selector = selector;
14879      css = getStyles(this.config);
14880      style = document.createElement("style");
14881      style.type = "text/css";
14882      if (style.styleSheet) {
14883        style.styleSheet.cssText = css;
14884      } else {
14885        style.appendChild(document.createTextNode(css));
14886      }
14887      this.el.head.appendChild(style);
14888      delete this.config.selector;
14889      meta = document.createElement("meta");
14890      meta.setAttribute("name", "sharer" + selector);
14891      return this.el.head.appendChild(meta);
14892    }
14893  };
14894
14895  Share.prototype.inject_html = function(instance) {
14896    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>";
14897  };
14898
14899  Share.prototype.inject_facebook_sdk = function() {
14900    var fb_root, script;
14901    if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
14902      script = document.createElement("script");
14903      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')";
14904      fb_root = document.createElement("div");
14905      fb_root.id = "fb-root";
14906      this.el.body.appendChild(fb_root);
14907      return this.el.body.appendChild(script);
14908    }
14909  };
14910
14911  Share.prototype.hook = function(type, network, instance) {
14912    var fn, opts;
14913    fn = this.config.networks[network][type];
14914    if (typeof fn === "function") {
14915      opts = fn.call(this.config.networks[network], instance);
14916      if (opts !== void 0) {
14917        opts = this.normalize_filter_config_updates(opts);
14918        this.extend(this.config.networks[network], opts, true);
14919        this.normalize_network_configuration();
14920      }
14921    }
14922  };
14923
14924  Share.prototype.default_title = function() {
14925    var content;
14926    if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
14927      return encodeURIComponent(content.getAttribute('content'));
14928    } else if (content = document.querySelector('title')) {
14929      return encodeURIComponent(content.innerText);
14930    }
14931  };
14932
14933  Share.prototype.default_image = function() {
14934    var content;
14935    if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
14936      return content.getAttribute('content');
14937    }
14938  };
14939
14940  Share.prototype.default_description = function() {
14941    var content;
14942    if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
14943      return encodeURIComponent(content.getAttribute('content'));
14944    } else {
14945      return '';
14946    }
14947  };
14948
14949  Share.prototype.set_global_configuration = function() {
14950    var display, network, option, options, _ref, _results;
14951    _ref = this.config.networks;
14952    _results = [];
14953    for (network in _ref) {
14954      options = _ref[network];
14955      for (option in options) {
14956        if (this.config.networks[network][option] == null) {
14957          this.config.networks[network][option] = this.config[option];
14958        }
14959      }
14960      if (this.config.networks[network].enabled) {
14961        display = 'block';
14962        this.config.enabled_networks += 1;
14963      } else {
14964        display = 'none';
14965      }
14966      _results.push(this.config.networks[network].display = display);
14967    }
14968    return _results;
14969  };
14970
14971  Share.prototype.normalize_network_configuration = function() {
14972    if (!this.config.networks.facebook.app_id) {
14973      this.config.networks.facebook.load_sdk = false;
14974    }
14975    if (!this.is_encoded(this.config.networks.twitter.description)) {
14976      this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
14977    }
14978    if (typeof this.config.networks.facebook.app_id === 'number') {
14979      return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
14980    }
14981  };
14982
14983  Share.prototype.normalize_filter_config_updates = function(opts) {
14984    if (this.config.networks.facebook.app_id !== opts.app_id) {
14985      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.");
14986      delete opts.app_id;
14987    }
14988    if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
14989      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.");
14990      delete opts.app_id;
14991    }
14992    return opts;
14993  };
14994
14995  return Share;
14996
14997})(ShareUtils);
14998 return Share;
14999});
15000
15001
15002// Generated by CoffeeScript 1.9.2
15003
15004// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
15005
15006(function() {
15007  var $, win;
15008
15009  $ = this.jQuery || window.jQuery;
15010
15011  win = $(window);
15012
15013  $.fn.stick_in_parent = function(opts) {
15014    var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
15015    if (opts == null) {
15016      opts = {};
15017    }
15018    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;
15019    if (offset_top == null) {
15020      offset_top = 0;
15021    }
15022    if (parent_selector == null) {
15023      parent_selector = void 0;
15024    }
15025    if (inner_scrolling == null) {
15026      inner_scrolling = true;
15027    }
15028    if (sticky_class == null) {
15029      sticky_class = "is_stuck";
15030    }
15031    doc = $(document);
15032    if (enable_bottoming == null) {
15033      enable_bottoming = true;
15034    }
15035    outer_width = function(el) {
15036      var _el, computed, w;
15037      if (window.getComputedStyle) {
15038        _el = el[0];
15039        computed = window.getComputedStyle(el[0]);
15040        w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
15041        if (computed.getPropertyValue("box-sizing") !== "border-box") {
15042          w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
15043        }
15044        return w;
15045      } else {
15046        return el.outerWidth(true);
15047      }
15048    };
15049    fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
15050      var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
15051      if (elm.data("sticky_kit")) {
15052        return;
15053      }
15054      elm.data("sticky_kit", true);
15055      last_scroll_height = doc.height();
15056      parent = elm.parent();
15057      if (parent_selector != null) {
15058        parent = parent.closest(parent_selector);
15059      }
15060      if (!parent.length) {
15061        throw "failed to find stick parent";
15062      }
15063      fixed = false;
15064      bottomed = false;
15065      spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
15066      if (spacer) {
15067        spacer.css('position', elm.css('position'));
15068      }
15069      recalc = function() {
15070        var border_top, padding_top, restore;
15071        if (detached) {
15072          return;
15073        }
15074        last_scroll_height = doc.height();
15075        border_top = parseInt(parent.css("border-top-width"), 10);
15076        padding_top = parseInt(parent.css("padding-top"), 10);
15077        padding_bottom = parseInt(parent.css("padding-bottom"), 10);
15078        parent_top = parent.offset().top + border_top + padding_top;
15079        parent_height = parent.height();
15080        if (fixed) {
15081          fixed = false;
vendor: 6,069 bytes, lines 15082-15277
15082          bottomed = false;
15083          if (manual_spacer == null) {
15084            elm.insertAfter(spacer);
15085            spacer.detach();
15086          }
15087          elm.css({
15088            position: "",
15089            top: "",
15090            width: "",
15091            bottom: ""
15092          }).removeClass(sticky_class);
15093          restore = true;
15094        }
15095        top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
15096        height = elm.outerHeight(true);
15097        el_float = elm.css("float");
15098        if (spacer) {
15099          spacer.css({
15100            width: outer_width(elm),
15101            height: height,
15102            display: elm.css("display"),
15103            "vertical-align": elm.css("vertical-align"),
15104            "float": el_float
15105          });
15106        }
15107        if (restore) {
15108          return tick();
15109        }
15110      };
15111      recalc();
15112      if (height === parent_height) {
15113        return;
15114      }
15115      last_pos = void 0;
15116      offset = offset_top;
15117      recalc_counter = recalc_every;
15118      tick = function() {
15119        var css, delta, recalced, scroll, will_bottom, win_height;
15120        if (detached) {
15121          return;
15122        }
15123        recalced = false;
15124        if (recalc_counter != null) {
15125          recalc_counter -= 1;
15126          if (recalc_counter <= 0) {
15127            recalc_counter = recalc_every;
15128            recalc();
15129            recalced = true;
15130          }
15131        }
15132        if (!recalced && doc.height() !== last_scroll_height) {
15133          recalc();
15134          recalced = true;
15135        }
15136        scroll = win.scrollTop();
15137        if (last_pos != null) {
15138          delta = scroll - last_pos;
15139        }
15140        last_pos = scroll;
15141        if (fixed) {
15142          if (enable_bottoming) {
15143            will_bottom = scroll + height + offset > parent_height + parent_top;
15144            if (bottomed && !will_bottom) {
15145              bottomed = false;
15146              elm.css({
15147                position: "fixed",
15148                bottom: "",
15149                top: offset
15150              }).trigger("sticky_kit:unbottom");
15151            }
15152          }
15153          if (scroll < top) {
15154            fixed = false;
15155            offset = offset_top;
15156            if (manual_spacer == null) {
15157              if (el_float === "left" || el_float === "right") {
15158                elm.insertAfter(spacer);
15159              }
15160              spacer.detach();
15161            }
15162            css = {
15163              position: "",
15164              width: "",
15165              top: ""
15166            };
15167            elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
15168          }
15169          if (inner_scrolling) {
15170            win_height = win.height();
15171            if (height + offset_top > win_height) {
15172              if (!bottomed) {
15173                offset -= delta;
15174                offset = Math.max(win_height - height, offset);
15175                offset = Math.min(offset_top, offset);
15176                if (fixed) {
15177                  elm.css({
15178                    top: offset + "px"
15179                  });
15180                }
15181              }
15182            }
15183          }
15184        } else {
15185          if (scroll > top) {
15186            fixed = true;
15187            css = {
15188              position: "fixed",
15189              top: offset
15190            };
15191            css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
15192            elm.css(css).addClass(sticky_class);
15193            if (manual_spacer == null) {
15194              elm.after(spacer);
15195              if (el_float === "left" || el_float === "right") {
15196                spacer.append(elm);
15197              }
15198            }
15199            elm.trigger("sticky_kit:stick");
15200          }
15201        }
15202        if (fixed && enable_bottoming) {
15203          if (will_bottom == null) {
15204            will_bottom = scroll + height + offset > parent_height + parent_top;
15205          }
15206          if (!bottomed && will_bottom) {
15207            bottomed = true;
15208            if (parent.css("position") === "static") {
15209              parent.css({
15210                position: "relative"
15211              });
15212            }
15213            return elm.css({
15214              position: "absolute",
15215              bottom: padding_bottom,
15216              top: "auto"
15217            }).trigger("sticky_kit:bottom");
15218          }
15219        }
15220      };
15221      recalc_and_tick = function() {
15222        recalc();
15223        return tick();
15224      };
15225      detach = function() {
15226        detached = true;
15227        win.off("touchmove", tick);
15228        win.off("scroll", tick);
15229        win.off("resize", recalc_and_tick);
15230        $(document.body).off("sticky_kit:recalc", recalc_and_tick);
15231        elm.off("sticky_kit:detach", detach);
15232        elm.removeData("sticky_kit");
15233        elm.css({
15234          position: "",
15235          bottom: "",
15236          top: "",
15237          width: ""
15238        });
15239        parent.position("position", "");
15240        if (fixed) {
15241          if (manual_spacer == null) {
15242            if (el_float === "left" || el_float === "right") {
15243              elm.insertAfter(spacer);
15244            }
15245            spacer.remove();
15246          }
15247          return elm.removeClass(sticky_class);
15248        }
15249      };
15250      win.on("touchmove", tick);
15251      win.on("scroll", tick);
15252      win.on("resize", recalc_and_tick);
15253      $(document.body).on("sticky_kit:recalc", recalc_and_tick);
15254      elm.on("sticky_kit:detach", detach);
15255      return setTimeout(tick, 0);
15256    };
15257    for (i = 0, len = this.length; i < len; i++) {
15258      elm = this[i];
15259      fn($(elm));
15260    }
15261    return this;
15262  };
15263
15264}).call(this);
15265
15266/* ==========================================================================
15267 * bootstrap-tab-history.js
15268 * Author: Michael Narayan <[email protected]>
15269 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
15270 * ==========================================================================
15271 * Licensed under the Apache License, Version 2.0 (the "License"); you may
15272 * not use this file except in compliance with the License. You may obtain a
15273 * copy of the License at
15274 *
15275 * http://www.apache.org/licenses/LICENSE-2.0
15276 *
15277 * Unless required by applicable law or agreed to in writing, softw
15277are
15278 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15279 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15280 * License for the specific language governing permissions and limitations
15281 * under the License.
15282 * ========================================================================== */
15283
15284/* ========================================================================== */
15285/* JSHint directives                                                          */
15286/*                                                                            */
15287/* global BootstrapTabHistory: true                                           */
15288/*                                                                            */
15289/* global document                                                            */
15290/* global jQuery                                                              */
15291/* global history                                                             */
15292/* global window                                                              */
15293/* ========================================================================== */
15294
15295/**
15296 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
15297 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
15298 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
15299 *
15300 * See the README for additional information.
15301 *
15302 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
15303 */
15304
15305BootstrapTabHistory = {
15306  options: {
15307    /**
15308     * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
15309     * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
15310     *
15311     * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
15312     *
15313     * @public
15314     * @type {?number}
15315     */
15316    defaultAnchorYOffset: 0,
15317    /**
15318     * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
15319     *
15320     * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
15321     *
15322     * @public
15323     * @type {string}
15324     */
15325    defaultChanger: 'replace',
15326    /**
15327     * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
15328     * `null` is passed as the third parameter to these calls.
15329     *
15330     * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
15331     *
15332     * @public
15333     * @type {boolean}
15334     */
15335    defaultUpdateURL: false,
15336    /**
15337     * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
15338     * load.
15339     *
15340     * @public
15341     * @type {boolean}
15342     */
15343    showTabsBasedOnAnchor: true
15344  }
15345};
15346
15347(function () {
15348  'use strict';
15349
15350  jQuery(function () {
15351    if(history && history.pushState && history.replaceState) {
15352      var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
15353
15354      if(bootstrapTabHistory) {
15355        showTabsBasedOnState(bootstrapTabHistory);
15356      } else {
15357        showTabsBasedOnAnchor();
15358      }
15359
15360      backfillHistoryState();
15361
15362      jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
15363      jQuery(window).on('popstate', onPopState);
15364    } else {
15365      showTabsBasedOnAnchor();
15366    }
15367  });
15368
15369  /**
15370   * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
15371   *
15372   * @type {boolean}
15373   */
15374  var showingTabsBasedOnState = false;
15375
15376  /**
15377   * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
15378   * `history.back` handling when `data-tab-history-update-url` is true.
15379   */
15380  function backfillHistoryState() {
15381    var newState = null;
15382
15383    jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
15384      var $activeTabElement = jQuery(this);
15385      var selector = getTabSelector($activeTabElement);
15386
15387      if(selector) {
15388        var tabGroup = getTabGroup($activeTabElement);
15389
15390        if(tabGroup) {
15391          newState = createNewHistoryState(newState || history.state, tabGroup, selector);
15392        }
15393      }
15394    });
15395
15396    if(newState) {
15397      history.replaceState(newState, '', null);
15398    }
15399  }
15400
15401  /**
15402   * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
15403   * said bootstrapTabHistory attribute.
15404   *
15405   * @param {?object} existingState
15406   * @param {!string} tabGroup
15407   * @param {!string} selector
15408   * @returns {!object}
15409   */
15410  function createNewHistoryState(existingState, tabGroup, selector) {
15411    // Clone history.state and ensure it has a bootstrapTabHistory entry.
15412    var newState = jQuery.extend(true, {}, existingState, {
15413      bootstrapTabHistory: {}
15414    });
15415
15416    newState.bootstrapTabHistory[tabGroup] = selector;
15417
15418    return newState;
15419  }
15420
15421  /**
15422   * @param {jQuery} $tab
15423   * @returns {?string}
15424   */
15425  function getTabGroup($tab) {
15426    return parseTruthyAttributeValue($tab.data('tab-history'));
15427  }
15428
15429  /**
15430   * @param {jQuery} $tab
15431   * @returns {?string}
15432   */
15433  function getTabSelector($tab) {
15434    return $tab.data('target') || $tab.attr('href');
15435  }
15436
15437  /**
15438   * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
15439   *
15440   * @param {jQuery.Event} shownEvt
15441   */
15442  function onShownTab(shownEvt) {
15443    if(!showingTabsBasedOnState) {
15444      var $activatedTab = jQuery(shownEvt.target);
15445      if ( $activatedTab.hasClass('panel-collapse') )
15446        $activatedTab = $activatedTab.closest('.panel').find('a');
15447      var selector = getTabSelector($activatedTab);
15448
15449      if(selector) {
15450        var tabGroup = getTabGroup($activatedTab);
15451
15452        if(tabGroup) {
15453          var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
15454          var newState = createNewHistoryState(history.state, tabGroup, selector);
15455          var updateURL = (function ($activatedTab) {
15456            if(selector[0] === '#') {
15457              var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
15458
15459              if(elementUpdateURLOption === undefined) {
15460                return BootstrapTabHistory.options.defaultUpdateURL;
15461              } else {
15462                return elementUpdateURLOption;
15463              }
15464            } else {
15465              return false;
15466            }
15467          })($activatedTab);
15468
15469          switch(historyChanger) {
15470            case 'push':
15471              history.pushState(newState, '', updateURL ? selector : null);
15472              break;
15473            case 'replace':
15474              history.replaceState(newState, '', updateURL ? selector : null);
15475              break;
15476            default:
15477              throw new Error('Unknown tab-history-changer: ' + historyChanger);
15478          }
15479        }
15480      }
15481    }
15482  }
15483
15484  /**
15485   * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
15486   */
15487  function onPopState() {
15488    var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
15489
15490    if(bootstrapTabHistory) {
15491      showTabsBasedOnState(bootstrapTabHistory);
15492    }
15493  }
15494
15495  /**
15496   * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
15497   *
15498   * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
15499   *
15500   * @param {*} value
15501   * @returns {*}
15502   */
15503  function parseTruthyAttributeValue(value) {
15504    if(value) {
15505      return value;
15506    } else if(value === '') {
15507      return true;
15508    } else {
15509      return value;
15510    }
15511  }
15512
15513  /**
15514   * Show tabs based upon the anchor component of `window.location`.
15515   */
15516  function showTabsBasedOnAnchor() {
15517    if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
15518      var anchor = window.location && window.location.hash;
15519
15520      if(anchor) {
15521        var $tabElement = showTabForSelector(anchor);
15522
15523        if($tabElement && window.addEventListener && window.removeEventListener) {
15524          var anchorYOffset = (function ($tabElement) {
15525            var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
15526
15527            if(elementSetting === undefined) {
15528              return BootstrapTabHistory.options.defaultAnchorYOffset;
15529            } else {
15530              return elementSetting;
15531            }
15532          })($tabElement);
15533
15534          // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
15535          //   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
15536          //   `history.state` object should have been used (unless the browser did not support the modern History API).
15537          if(anchorYOffset || anchorYOffset === 0) {
15538            var scrollListener = function resetAnchorScroll () {
15539              window.removeEventListener('scroll', scrollListener);
15540              window.scrollTo(0, anchorYOffset);
15541            };
15542
15543            window.addEventListener('scroll', scrollListener);
15544          }
15545        }
15546      }
15547    }
15548  }
15549
15550  /**
15551   * Show a tab which corresponds to the provided selector.
15552   *
15553   * @param {string} selector - A CSS selector.
15554   * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
15555   */
15556  function showTabForSelector(selector) {
15557    var $tabElement = (function (selector) {
15558      var $ret = null;
15559
15560      jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
15561        var $potentialTab = jQuery(this);
15562
15563        if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
15564          $ret = $potentialTab;
15565          return false;
vendor: 4,523 bytes, lines 15566-15716
15566        } else {
15567         return null;
15568        }
15569      });
15570
15571      return $ret;
15572    })(selector);
15573
15574    if($tabElement) {
15575      $tabElement.trigger('click');
15576      //$tabElement.tab('show');
15577    }
15578
15579    return $tabElement;
15580  }
15581
15582  /**
15583   * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
15584   *
15585   * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
15586   */
15587  function showTabsBasedOnState(bootstrapTabHistory) {
15588    showingTabsBasedOnState = true;
15589
15590    try {
15591      for(var k in bootstrapTabHistory) {
15592        if(bootstrapTabHistory.hasOwnProperty(k)) {
15593          showTabForSelector(bootstrapTabHistory[k]);
15594        }
15595      }
15596    } finally {
15597      showingTabsBasedOnState = false;
15598    }
15599  }
15600})();
15601
15602
15603/*!
15604 * Justified Gallery - v3.6.3
15605 * http://miromannino.github.io/Justified-Gallery/
15606 * Copyright (c) 2016 Miro Mannino
15607 * Licensed under the MIT license.
15608 */
15609(function($) {
15610
15611  function hasScrollBar() {
15612    return $("body").height() > $(window).height();
15613  }
15614  /**
15615   * Justified Gallery controller constructor
15616   *
15617   * @param $gallery the gallery to build
15618   * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults)
15619   * @constructor
15620   */
15621  var JustifiedGallery = function ($gallery, settings) {
15622    
15623    this.settings = settings;
15624    this.checkSettings();
15625
15626    this.imgAnalyzerTimeout = null;
15627    this.entries = null;
15628    this.buildingRow = {
15629      entriesBuff : [],
15630      width : 0,
15631      height : 0,
15632      aspectRatio : 0
15633    };
15634    this.lastFetchedEntry = null;
15635    this.lastAnalyzedIndex = -1;
15636    this.yield = {
15637      every : 2, // do a flush every n flushes (must be greater than 1)
15638      flushed : 0 // flushed rows without a yield
15639    };
15640    this.border = settings.border >= 0 ? settings.border : settings.margins;
15641    this.maxRowHeight = this.retrieveMaxRowHeight();
15642    this.suffixRanges = this.retrieveSuffixRanges();
15643    this.offY = this.border;
15644    this.rows = 0;
15645    this.spinner = {
15646      phase : 0,
15647      timeSlot : 150,
15648      $el : $('<div class="spinner"><span></span><span></span><span></span></div>'),
15649      intervalId : null
15650    };
15651    this.checkWidthIntervalId = null;
15652    this.galleryWidth = $gallery.width();
15653    this.$gallery = $gallery;
15654
15655  };
15656
15657  /** @returns {String} the best suffix given the width and the height */
15658  JustifiedGallery.prototype.getSuffix = function (width, height) {
15659    var longestSide, i;
15660    longestSide = (width > height) ? width : height;
15661    for (i = 0; i < this.suffixRanges.length; i++) {
15662      if (longestSide <= this.suffixRanges[i]) {
15663        return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
15664      }
15665    }
15666    return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
15667  };
15668
15669  /**
15670   * Remove the suffix from the string
15671   *
15672   * @returns {string} a new string without the suffix
15673   */
15674  JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
15675    return str.substring(0, str.length - suffix.length);
15676  };
15677
15678  /**
15679   * @returns {boolean} a boolean to say if the suffix is contained in the str or not
15680   */
15681  JustifiedGallery.prototype.endsWith = function (str, suffix) {
15682    return str.indexOf(suffix, str.length - suffix.length) !== -1;
15683  };
15684
15685  /**
15686   * Get the used suffix of a particular url
15687   *
15688   * @param str
15689   * @returns {String} return the used suffix
15690   */
15691  JustifiedGallery.prototype.getUsedSuffix = function (str) {
15692    for (var si in this.settings.sizeRangeSuffixes) {
15693      if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
15694        if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
15695        if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
15696      }
15697    }
15698    return '';
15699  };
15700
15701  /**
15702   * Given an image src, with the width and the height, returns the new image src with the
15703   * best suffix to show the best quality thumbnail.
15704   *
15705   * @returns {String} the suffix to use
15706   */
15707  JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
15708    var newImageSrc;
15709
15710    if (this.settings.thumbnailPath) {
15711      newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
15712    } else {
15713      var matchRes = imageSrc.match(this.settings.extension);
15714      var ext = (matchRes !== null) ? matchRes[0] : '';
15715      newImageSrc = imageSrc.replace(this.settings.extension, '');
15716      newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
15717      newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
15718    }
15719
15720    return newImageSrc;
15721  };
15722
15723  /**
15724   * Shows the images that is in the given entry
15725   *
15726   * @param $entry the entry
15727   * @param callback the callback that is called when the show animation is finished
15728   */
15729  JustifiedGallery.prototype.showImg = function ($entry, callback) {
15730    if (this.settings.cssAnimation) {
15731      $entry.addClass('entry-visible');
15732      if (callback) callback();
15733    } else {
15734      $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
15735      $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
15736    }
15737  };
15738
15739  /**
15740   * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
15741   * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
15742   *
15743   * @param $image the image to analyze
15744   * @returns {String} the extracted src
15745   */
15746  JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
15747    var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src');
15748    $image.data('jg.originalSrc', imageSrc);
15749    return imageSrc;
15750  };
15751
15752  /** @returns {jQuery} the image in the given entry */
15753  JustifiedGallery.prototype.imgFromEntry = function ($entry) {
15754    var $img = $entry.find('> img');
15755    if ($img.length === 0) $img = $entry.find('> a > img');
15756    if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
15757    return $img.length === 0 ? null : $img;
15758  };
15759
15760  /** @returns {jQuery} the caption in the given entry */
15761  JustifiedGallery.prototype.captionFromEntry = function ($entry) {
15762    var $caption = $entry.find('> .caption');
15763    return $caption.length === 0 ? null : $caption;
15764  };
15765
15766  /**
15767   * Display the entry
15768   *
15769   * @param {jQuery} $entry the entry to display
15770   * @param {int} x the x position where the entry must be positioned
15771   * @param y the y position where the entry must be positioned
15772   * @param imgWidth the image width
15773   * @param imgHeight the image height
15774   * @param rowHeight the row height of the row that owns the entry
15775   */
15776  JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
15777    $entry.width(imgWidth);
15778    $entry.height(Math.floor(rowHeight));//hacked by Uncode
15779    $entry.css('top', Math.floor(y));//hacked by Uncode
15780    $entry.css('left', x);
15781
15782    var $image = this.imgFromEntry($entry);
15783    if ($image !== null) {
15784      $image.css('width', imgWidth);
15785      $image.css('height', imgHeight);
15786      $image.css('margin-left', - imgWidth / 2);
15787      $image.css('margin-top', - imgHeight / 2);
15788
15789      // Image reloading for an high quality of thumbnails
15790      var imageSrc = $image.attr('src');
15791      var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
15792
15793      $image.one('error', function () {
15794        $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it.
15795      });
15796
15797      var loadNewImage = function () {
15798        if (imageSrc !== newImageSrc) { //load the new image after the fadeIn
15799          $image.attr('src', newImageSrc);
15800        }
15801      };
15802
15803      if ($entry.data('jg.loaded') === 'skipped') {
15804        this.onImageEvent(imageSrc, $.proxy(function() {
15805          this.showImg($entry, loadNewImage);
15806          $entry.data('jg.loaded', true);
15807        }, this));
15808      } else {
15809        this.showImg($entry, loadNewImage);
15810      }
15811
15812    } else {
15813      this.showImg($entry);
15814    }
15815
15816    this.displayEntryCaption($entry);
15817  };
15818
15819  /**
15820   * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
15821   * or the 'title' attributes.
15822   *
15823   * @param {jQuery} $entry the entry to process
15824   */
15825  JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
15826    var $image = this.imgFromEntry($entry);
15827    if ($image !== null && this.settings.captions) {
15828      var $imgCaption = this.captionFromEntry($entry);
15829
15830      // Create it if it doesn't exists
15831      if ($imgCaption === null) {
15832        var caption = $image.attr('alt');
15833        if (!this.isValidCaption(caption)) caption = $entry.attr('title');
15834        if (this.isValidCaption(caption)) { // Create only we found something
15835          $imgCaption = $('<div class="caption">' + caption + '</div>');
15836          $entry.append($imgCaption);
15837          $entry.data('jg.createdCaption', true);
15838        }
15839      }
15840
15841      // Create events (we check again the $imgCaption because it can be still inexistent)
15842      if ($imgCaption !== null) {
15843        if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
15844        this.addCaptionEventsHandlers($entry);
15845      }
15846    } else {
15847      this.removeCaptionEventsHandlers($entry);
15848    }
15849  };
15850
15851  /**
15852   * Validates the caption
15853   *
15854   * @param caption The caption that should be validated
15855   * @return {boolean} Validation result
15856   */
15857  JustifiedGallery.prototype.isValidCaption = function (caption) {
15858    return (typeof caption !== 'undefined' && caption.length > 0);
15859  };
15860
15861  /**
15862   * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
15863   * It shows the caption using jQuery (or using CSS if it is configured so)
15864   *
15865   * @param {Event} eventObject the event object
15866   */
15867  JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
15868    var $caption = this.captionFromEntry($(eventObject.currentTarget));
15869    if (this.settings.cssAnimation) {
15870      $caption.addClass('caption-visible').removeClass('caption-hidden');
15871    } else {
15872      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
15873          this.settings.captionSettings.visibleOpacity);
15874    }
15875  };
15876
15877  /**
15878   * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
15879   * It hides the caption using jQuery (or using CSS if it is configured so)
15880   *
15881   * @param {Event} eventObject the event object
15882   */
15883  JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
15884    var $caption = this.captionFromEntry($(eventObject.currentTarget));
15885    if (this.settings.cssAnimation) {
15886      $caption.removeClass('caption-visible').removeClass('caption-hidden');
15887    } else {
15888      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
15889          this.settings.captionSettings.nonVisibleOpacity);
15890    }
15891  };
15892
15893  /**
15894   * Add the handlers of the entry for the caption
15895   *
15896   * @param $entry the entry to modify
15897   */
15898  JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
15899    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
15900    if (typeof captionMouseEvents === 'undefined') {
15901      captionMouseEvents = {
15902        mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
15903        mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
15904      };
15905      $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
15906      $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
15907      $entry.data('jg.captionMouseEvents', captionMouseEvents);
15908    }
15909  };
15910
15911  /**
15912   * Remove the handlers of the entry for the caption
15913   *
15914   * @param $entry the entry to modify
15915   */
15916  JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
15917    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
15918    if (typeof captionMouseEvents !== 'undefined') {
15919      $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
15920      $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
15921      $entry.removeData('jg.captionMouseEvents');
15922    }
15923  };
15924
15925  /**
15926   * Justify the building row, preparing it to
15927   *
15928   * @param isLastRow
15929   * @returns a boolean to know if the row has been justified or not
15930   */
15931  JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) {
15932    var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
15933    var minHeight = 0;
15934    var availableWidth = this.galleryWidth - 2 * this.border - (
15935        (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
15936    var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
15937    var defaultRowHeight = this.settings.rowHeight;
15938    var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
15939
15940    //Skip the last row if we can't justify it and the lastRow == 'hide'
15941    if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) {
15942      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
15943        $entry = this.buildingRow.entriesBuff[i];
15944        if (this.settings.cssAnimation)
15945          $entry.removeClass('entry-visible');
15946        else {
15947          $entry.stop().fadeTo(0, 0.1);
15948          $entry.find('> img, > a > img').fadeTo(0, 0);
15949        }
15950      }
15951      return -1;
15952    }
15953
15954    // With lastRow = nojustify, justify if is justificable (the images will not become too big)
15955    if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
15956      justify = false;
15957
15958      if (this.rows > 0) {
15959        defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
15960        justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
15961      }
15962    }
15963
15964    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
15965      $entry = this.buildingRow.entriesBuff[i];
15966      imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
15967
15968      if (justify) {
15969        newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
15970        newImgH = rowHeight;
15971      } else {
15972        newImgW = defaultRowHeight * imgAspectRatio;
15973        newImgH = defaultRowHeight;
15974      }
15975
15976      availableWidth -= Math.round(newImgW);
15977      $entry.data('jg.jwidth', Math.round(newImgW));
15978      $entry.data('jg.jheight', Math.ceil(newImgH));
15979      if (i === 0 || minHeight > newImgH) minHeight = newImgH;
15980    }
15981
15982    this.buildingRow.height = minHeight;
15983    return justify;
15984  };
15985
15986  /**
15987   * Clear the building row data to be used for a new row
15988   */
15989  JustifiedGallery.prototype.clearBuildingRow = function () {
15990    this.buildingRow.entriesBuff = [];
15991    this.buildingRow.aspectRatio = 0;
15992    this.buildingRow.width = 0;
15993  };
15994
15995  /**
15996   * Flush a row: justify it, modify the gallery height accordingly to the row height
15997   *
15998   * @param isLastRow
15999   */
16000  JustifiedGallery.prototype.flushRow = function (isLastRow) {
16001    var settings = this.settings;
16002    var $entry, buildingRowRes, offX = this.border, i;
16003
16004    buildingRowRes = this.prepareBuildingRow(isLastRow);
16005    if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) {
16006      this.clearBuildingRow();
16007      return;
16008    }
16009
16010    if (this.maxRowHeight) {
16011      if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) {
16012        this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight;
16013      } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) {
16014        this.buildingRow.height = this.maxRowHeight.value;
16015      }
16016    }
16017
16018    //Align last (unjustified) row
16019    if (settings.lastRow === 'center' || settings.lastRow === 'right') {
16020      var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
16021
16022      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
16023        $entry = this.buildingRow.entriesBuff[i];
16024        availableWidth -= $entry.data('jg.jwidth');
16025      }
16026
16027      if (settings.lastRow === 'center')
16028        offX += availableWidth / 2;
16029      else if (settings.lastRow === 'right')
16030        offX += availableWidth;
16031    }
16032
16033    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
16034      $entry = this.buildingRow.entriesBuff[i];
16035      this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
16036      offX += $entry.data('jg.jwidth') + settings.margins;
16037    }
16038
16039    //Gallery Height
16040    this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
16041    this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight());
16042
16043    if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
16044      //Ready for a new row
16045      this.offY += this.buildingRow.height + settings.margins;
16046      this.rows += 1;
16047      this.clearBuildingRow();
16048      this.$gallery.trigger('jg.rowflush');
16049    }
16050  };
16051
16052  /**
16053   * Checks the width of the gallery container, to know if a new justification is needed
16054   */
16055  var scrollBarOn = false;
16056  JustifiedGallery.prototype.checkWidth = function () {
16057    this.checkWidthIntervalId = setInterval($.proxy(function () {
16058      var galleryWidth = parseFloat(this.$gallery.width());
16059      if (hasScrollBar() === scrollBarOn) {
16060        if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
16061          this.galleryWidth = galleryWidth;
16062          this.rewind();
16063
16064          // Restart to analyze
16065          this.startImgAnalyzer(true);
16066        }
16067      } else {
16068        scrollBarOn = hasScrollBar();
16069        this.galleryWidth = galleryWidth;
16070      }
16071    }, this), this.settings.refreshTime);
16072  };
16073
16074  /**
16075   * @returns {boolean} a boolean saying if the spinner is active or not
16076   */
16077  JustifiedGallery.prototype.isSpinnerActive = function () {
16078    return this.spinner.intervalId !== null;
16079  };
16080
16081  /**
16082   * @returns {int} the spinner height
16083   */
16084  JustifiedGallery.prototype.getSpinnerHeight = function () {
16085    return this.spinner.$el.innerHeight();
16086  };
16087
16088  /**
16089   * Stops the spinner animation and modify the gallery height to exclude the spinner
16090   */
16091  JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
16092    clearInterval(this.spinner.intervalId);
16093    this.spinner.intervalId = null;
16094    this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight());
16095    this.spinner.$el.detach();
16096  };
16097
16098  /**
16099   * Starts the spinner animation
16100   */
16101  JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
16102    var spinnerContext = this.spinner;
16103    var $spinnerPoints = spinnerContext.$el.find('span');
16104    clearInterval(spinnerContext.intervalId);
16105    this.$gallery.append(spinnerContext.$el);
16106    this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight());
16107    spinnerContext.intervalId = setInterval(function () {
16108      if (spinnerContext.phase < $spinnerPoints.length) {
16109        $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
16110      } else {
vendor: 4,333 bytes, lines 16111-16255
16111        $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
16112      }
16113      spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
16114    }, spinnerContext.timeSlot);
16115  };
16116
16117  /**
16118   * Rewind the image analysis to start from the first entry.
16119   */
16120  JustifiedGallery.prototype.rewind = function () {
16121    this.lastFetchedEntry = null;
16122    this.lastAnalyzedIndex = -1;
16123    this.offY = this.border;
16124    this.rows = 0;
16125    this.clearBuildingRow();
16126  };
16127
16128  /**
16129   * Update the entries searching it from the justified gallery HTML element
16130   *
16131   * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
16132   * @returns {boolean} true if some entries has been founded
16133   */
16134  JustifiedGallery.prototype.updateEntries = function (norewind) {
16135    var newEntries;
16136
16137    if (norewind && this.lastFetchedEntry != null) {
16138      newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray();
16139    } else {
16140      this.entries = [];
16141      newEntries = this.$gallery.children(this.settings.selector).toArray();
16142    }
16143
16144    if (newEntries.length > 0) {
16145
16146      // Sort or randomize
16147      if ($.isFunction(this.settings.sort)) {
16148        newEntries = this.sortArray(newEntries);
16149      } else if (this.settings.randomize) {
16150        newEntries = this.shuffleArray(newEntries);
16151      }
16152      this.lastFetchedEntry = newEntries[newEntries.length - 1];
16153
16154      // Filter
16155      if (this.settings.filter) {
16156        newEntries = this.filterArray(newEntries);
16157      } else {
16158        this.resetFilters(newEntries);
16159      }
16160
16161    }
16162
16163    this.entries = this.entries.concat(newEntries);
16164    return true;
16165  };
16166
16167  /**
16168   * Apply the entries order to the DOM, iterating the entries and appending the images
16169   *
16170   * @param entries the entries that has been modified and that must be re-ordered in the DOM
16171   */
16172  JustifiedGallery.prototype.insertToGallery = function (entries) {
16173    var that = this;
16174    $.each(entries, function () {
16175      $(this).appendTo(that.$gallery);
16176    });
16177  };
16178
16179  /**
16180   * Shuffle the array using the Fisher-Yates shuffle algorithm
16181   *
16182   * @param a the array to shuffle
16183   * @return the shuffled array
16184   */
16185  JustifiedGallery.prototype.shuffleArray = function (a) {
16186    var i, j, temp;
16187    for (i = a.length - 1; i > 0; i--) {
16188      j = Math.floor(Math.random() * (i + 1));
16189      temp = a[i];
16190      a[i] = a[j];
16191      a[j] = temp;
16192    }
16193    this.insertToGallery(a);
16194    return a;
16195  };
16196
16197  /**
16198   * Sort the array using settings.comparator as comparator
16199   *
16200   * @param a the array to sort (it is sorted)
16201   * @return the sorted array
16202   */
16203  JustifiedGallery.prototype.sortArray = function (a) {
16204    a.sort(this.settings.sort);
16205    this.insertToGallery(a);
16206    return a;
16207  };
16208
16209  /**
16210   * Reset the filters removing the 'jg-filtered' class from all the entries
16211   *
16212   * @param a the array to reset
16213   */
16214  JustifiedGallery.prototype.resetFilters = function (a) {
16215    for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
16216  };
16217
16218  /**
16219   * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
16220   *
16221   * @param a the array to filter
16222   * @return the filtered array
16223   */
16224  JustifiedGallery.prototype.filterArray = function (a) {
16225    var settings = this.settings;
16226    if ($.type(settings.filter) === 'string') {
16227      // Filter only keeping the entries passed in the string
16228      return a.filter(function (el) {
16229        var $el = $(el);
16230        if ($el.is(settings.filter)) {
16231          $el.removeClass('jg-filtered');
16232          return true;
16233        } else {
16234          $el.addClass('jg-filtered').removeClass('jg-visible');
16235          return false;
16236        }
16237      });
16238    } else if ($.isFunction(settings.filter)) {
16239      // Filter using the passed function
16240      var filteredArr = a.filter(settings.filter);
16241      for (var i = 0; i < a.length; i++) {
16242        if (filteredArr.indexOf(a[i]) == -1) {
16243          $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
16244        } else {
16245          $(a[i]).removeClass('jg-filtered');
16246        }
16247      }
16248      return filteredArr;
16249    }
16250  };
16251
16252  /**
16253   * Destroy the Justified Gallery instance.
16254   *
16255   * It clears all the css properties added in the style attributes. We doesn't backup the original
16256   * values for those css attributes, because it costs (performance) and because in general one
16257   * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
16258   * classes). Creating a backup is also difficult because JG could be called multiple times and
16259   * with different style attributes.
16260   */
16261  JustifiedGallery.prototype.destroy = function () {
16262    clearInterval(this.checkWidthIntervalId);
16263
16264    $.each(this.entries, $.proxy(function(_, entry) {
16265      var $entry = $(entry);
16266
16267      // Reset entry style
16268      $entry.css('width', '');
16269      $entry.css('height', '');
16270      $entry.css('top', '');
16271      $entry.css('left', '');
16272      $entry.data('jg.loaded', undefined);
16273      $entry.removeClass('jg-entry');
16274
16275      // Reset image style
16276      var $img = this.imgFromEntry($entry);
16277      $img.css('width', '');
16278      $img.css('height', '');
16279      $img.css('margin-left', '');
16280      $img.css('margin-top', '');
16281      $img.attr('src', $img.data('jg.originalSrc'));
16282      $img.data('jg.originalSrc', undefined);
16283
16284      // Remove caption
16285      this.removeCaptionEventsHandlers($entry);
16286      var $caption = this.captionFromEntry($entry);
16287      if ($entry.data('jg.createdCaption')) {
16288        // remove also the caption element (if created by jg)
16289        $entry.data('jg.createdCaption', undefined);
16290        if ($caption !== null) $caption.remove();
16291      } else {
16292        if ($caption !== null) $caption.fadeTo(0, 1);
16293      }
16294
16295    }, this));
16296
16297    this.$gallery.css('height', '');
16298    this.$gallery.removeClass('justified-gallery');
16299    this.$gallery.data('jg.controller', undefined);
16300  };
16301
16302  /**
16303   * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
16304   *
16305   * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
16306   */
16307  JustifiedGallery.prototype.analyzeImages = function (isForResize) {
16308    for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
16309      var $entry = $(this.entries[i]);
16310      if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
16311        var availableWidth = this.galleryWidth - 2 * this.border - (
16312            (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
16313        var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
16314        if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
16315          this.flushRow(false);
16316          if(++this.yield.flushed >= this.yield.every) {
16317            this.startImgAnalyzer(isForResize);
16318            return;
16319          }
16320        }
16321
16322        this.buildingRow.entriesBuff.push($entry);
16323        this.buildingRow.aspectRatio += imgAspectRatio;
16324        this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
16325        this.lastAnalyzedIndex = i;
16326
16327      } else if ($entry.data('jg.loaded') !== 'error') {
16328        return;
16329      }
16330    }
16331
16332    // Last row flush (the row is not full)
16333    if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true);
16334
16335    if (this.isSpinnerActive()) {
16336      this.stopLoadingSpinnerAnimation();
16337    }
16338
16339    /* Stop, if there is, the timeout to start the analyzeImages.
16340     This is because an image can be set loaded, and the timeout can be set,
16341     but this image can be analyzed yet.
16342     */
16343    this.stopImgAnalyzerStarter();
16344
16345    //On complete callback
16346    this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete');
16347    this.$gallery.height(this.galleryHeightToSet);
16348  };
16349
16350  /**
16351   * Stops any ImgAnalyzer starter (that has an assigned timeout)
16352   */
16353  JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
16354    this.yield.flushed = 0;
16355    if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout);
16356  };
16357
16358  /**
16359   * Starts the image analyzer. It is not immediately called to let the browser to update the view
16360   *
16361   * @param isForResize specifies if the image analyzer must be called for resizing or not
16362   */
16363  JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
16364    var that = this;
16365    this.stopImgAnalyzerStarter();
16366    this.imgAnalyzerTimeout = setTimeout(function () {
16367      that.analyzeImages(isForResize);
16368    }, 0.001); // we can't start it immediately due to a IE different behaviour
16369  };
16370
16371  /**
16372   * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
16373   * because some browsers, with a 404 set complete = true.
16374   *
16375   * @param imageSrc the image src to load
16376   * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 16377-16727
16377   * @param onError callback that is called in case of an error
16378   */
16379  JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
16380    if (!onLoad && !onError) return;
16381
16382    var memImage = new Image();
16383    var $memImage = $(memImage);
16384    if (onLoad) {
16385      $memImage.one('load', function () {
16386        $memImage.off('load error');
16387        onLoad(memImage);
16388      });
16389    }
16390    if (onError) {
16391      $memImage.one('error', function() {
16392        $memImage.off('load error');
16393        onError(memImage);
16394      });
16395    }
16396    memImage.src = imageSrc;
16397  };
16398
16399  /**
16400   * Init of Justified Gallery controlled
16401   * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
16402   */
16403  JustifiedGallery.prototype.init = function () {
16404    var imagesToLoad = false, skippedImages = false, that = this;
16405    $.each(this.entries, function (index, entry) {
16406      var $entry = $(entry);
16407      var $image = that.imgFromEntry($entry);
16408
16409      $entry.addClass('jg-entry');
16410
16411      if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
16412
16413        // Link Rel global overwrite
16414        if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
16415
16416        // Link Target global overwrite
16417        if (that.settings.target !== null) $entry.attr('target', that.settings.target);
16418
16419        if ($image !== null) {
16420
16421          // Image src
16422          var imageSrc = that.extractImgSrcFromImage($image);
16423          $image.attr('src', imageSrc);
16424
16425          /* If we have the height and the width, we don't wait that the image is loaded, but we start directly
16426           * with the justification */
16427          if (that.settings.waitThumbnailsLoad === false) {
16428            var width = parseFloat($image.attr('width'));
16429            var height = parseFloat($image.attr('height'));
16430            if (!isNaN(width) && !isNaN(height)) {
16431              $entry.data('jg.width', width);
16432              $entry.data('jg.height', height);
16433              $entry.data('jg.loaded', 'skipped');
16434              skippedImages = true;
16435              that.startImgAnalyzer(false);
16436              return true; // continue
16437            }
16438          }
16439
16440          $entry.data('jg.loaded', false);
16441          imagesToLoad = true;
16442
16443          // Spinner start
16444          if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
16445
16446          that.onImageEvent(imageSrc, function (loadImg) { // image loaded
16447            $entry.data('jg.width', loadImg.width);
16448            $entry.data('jg.height', loadImg.height);
16449            $entry.data('jg.loaded', true);
16450            that.startImgAnalyzer(false);
16451          }, function () { // image load error
16452            $entry.data('jg.loaded', 'error');
16453            that.startImgAnalyzer(false);
16454          });
16455
16456        } else {
16457          $entry.data('jg.loaded', true);
16458          $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
16459          $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
16460        }
16461
16462      }
16463
16464    });
16465
16466    if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
16467    this.checkWidth();
16468  };
16469
16470  /**
16471   * Checks that it is a valid number. If a string is passed it is converted to a number
16472   *
16473   * @param settingContainer the object that contains the setting (to allow the conversion)
16474   * @param settingName the setting name
16475   */
16476  JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
16477    if ($.type(settingContainer[settingName]) === 'string') {
16478      settingContainer[settingName] = parseFloat(settingContainer[settingName]);
16479    }
16480
16481    if ($.type(settingContainer[settingName]) === 'number') {
16482      if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
16483    } else {
16484      throw settingName + ' must be a number';
16485    }
16486  };
16487
16488  /**
16489   * Checks the sizeRangeSuffixes and, if necessary, converts
16490   * its keys from string (e.g. old settings with 'lt100') to int.
16491   */
16492  JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
16493    if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
16494      throw 'sizeRangeSuffixes must be defined and must be an object';
16495    }
16496
16497    var suffixRanges = [];
16498    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
16499      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
16500    }
16501
16502    var newSizeRngSuffixes = {0: ''};
16503    for (var i = 0; i < suffixRanges.length; i++) {
16504      if ($.type(suffixRanges[i]) === 'string') {
16505        try {
16506          var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
16507          newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
16508        } catch (e) {
16509          throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
16510        }
16511      } else {
16512        newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
16513      }
16514    }
16515
16516    this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
16517  };
16518
16519  /**
16520   * check and convert the maxRowHeight setting
16521   */
16522  JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
16523    var newMaxRowHeight = { };
16524
16525    if ($.type(this.settings.maxRowHeight) === 'string') {
16526      if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
16527        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
16528        newMaxRowHeight.isPercentage = false;
16529      } else {
16530        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight);
16531        newMaxRowHeight.isPercentage = true;
16532      }
16533    } else if ($.type(this.settings.maxRowHeight) === 'number') {
16534      newMaxRowHeight.value = this.settings.maxRowHeight;
16535      newMaxRowHeight.isPercentage = false;
16536    } else if (this.settings.maxRowHeight === false ||
16537        this.settings.maxRowHeight === null ||
16538        typeof this.settings.maxRowHeight == 'undefined') {
16539      return null;
16540    } else {
16541      throw 'maxRowHeight must be a number or a percentage';
16542    }
16543
16544    // check if the converted value is not a number
16545    if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight';
16546
16547    // check values
16548    if (newMaxRowHeight.isPercentage) {
16549      if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100;
16550    }
16551
16552    return newMaxRowHeight;
16553  };
16554
16555  /**
16556   * Checks the settings
16557   */
16558  JustifiedGallery.prototype.checkSettings = function () {
16559    this.checkSizeRangesSuffixes();
16560
16561    this.checkOrConvertNumber(this.settings, 'rowHeight');
16562    this.checkOrConvertNumber(this.settings, 'margins');
16563    this.checkOrConvertNumber(this.settings, 'border');
16564
16565    var lastRowModes = [
16566      'justify',
16567      'nojustify',
16568      'left',
16569      'center',
16570      'right',
16571      'hide'
16572    ];
16573    if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
16574      throw 'lastRow must be one of: ' + lastRowModes.join(', ');
16575    }
16576
16577    this.checkOrConvertNumber(this.settings, 'justifyThreshold');
16578    if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
16579      throw 'justifyThreshold must be in the interval [0,1]';
16580    }
16581    if ($.type(this.settings.cssAnimation) !== 'boolean') {
16582      throw 'cssAnimation must be a boolean';
16583    }
16584
16585    if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
16586    this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
16587
16588    this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
16589    if (this.settings.captionSettings.visibleOpacity < 0 ||
16590        this.settings.captionSettings.visibleOpacity > 1) {
16591      throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
16592    }
16593
16594    this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
16595    if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
16596        this.settings.captionSettings.nonVisibleOpacity > 1) {
16597      throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
16598    }
16599
16600    this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
16601    this.checkOrConvertNumber(this.settings, 'refreshTime');
16602    this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
16603    if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
16604    if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
16605
16606    if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
16607      throw 'sort must be false or a comparison function';
16608    }
16609
16610    if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
16611        $.type(this.settings.filter) !== 'string') {
16612      throw 'filter must be false, a string or a filter function';
16613    }
16614  };
16615
16616  /**
16617   * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
16618   * @returns {Array} sorted suffix ranges
16619   */
16620  JustifiedGallery.prototype.retrieveSuffixRanges = function () {
16621    var suffixRanges = [];
16622    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
16623      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
16624    }
16625    suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
16626    return suffixRanges;
16627  };
16628
16629  /**
16630   * Update the existing settings only changing some of them
16631   *
16632   * @param newSettings the new settings (or a subgroup of them)
16633   */
16634  JustifiedGallery.prototype.updateSettings = function (newSettings) {
16635    // In this case Justified Gallery has been called again changing only some options
16636    this.settings = $.extend({}, this.settings, newSettings);
16637    this.checkSettings();
16638
16639    // As reported in the settings: negative value = same as margins, 0 = disabled
16640    this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
16641
16642    this.maxRowHeight = this.retrieveMaxRowHeight();
16643    this.suffixRanges = this.retrieveSuffixRanges();
16644  };
16645
16646  /**
16647   * Justified Gallery plugin for jQuery
16648   *
16649   * Events
16650   *  - jg.complete : called when all the gallery has been created
16651   *  - jg.resize : called when the gallery has been resized
16652   *  - jg.rowflush : when a new row appears
16653   *
16654   * @param arg the action (or the settings) passed when the plugin is called
16655   * @returns {*} the object itself
16656   */
16657  $.fn.justifiedGallery = function (arg) {
16658    return this.each(function (index, gallery) {
16659
16660      var $gallery = $(gallery);
16661      $gallery.addClass('justified-gallery');
16662
16663      var controller = $gallery.data('jg.controller');
16664      if (typeof controller === 'undefined') {
16665        // Create controller and assign it to the object data
16666        if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
16667          if (arg === 'destroy') return; // Just a call to an unexisting object
16668          throw 'The argument must be an object';
16669        }
16670        controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg));
16671        $gallery.data('jg.controller', controller);
16672      } else if (arg === 'norewind') {
16673        // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
16674        // ... left to be more readable
16675      } else if (arg === 'destroy') {
16676        controller.destroy();
16677        return;
16678      } else {
16679        // In this case Justified Gallery has been called again changing only some options
16680        controller.updateSettings(arg);
16681        controller.rewind();
16682      }
16683
16684      // Update the entries list
16685      if (!controller.updateEntries(arg === 'norewind')) return;
16686
16687      // Init justified gallery
16688      controller.init();
16689
16690    });
16691  };
16692
16693  // Default options
16694  $.fn.justifiedGallery.defaults = {
16695    sizeRangeSuffixes: { }, /* e.g. Flickr configuration
16696        {
16697          100: '_t',  // used when longest is less than 100px
16698          240: '_m',  // used when longest is between 101px and 240px
16699          320: '_n',  // ...
16700          500: '',
16701          640: '_z',
16702          1024: '_b'  // used as else case because it is the last
16703        }
16704    */
16705    thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
16706    path relative to a specific thumbnail size. The function should accept respectively three arguments:
16707    current path, width and height */
16708    rowHeight: 120,
16709    maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
16710                         // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
16711                         // can't exceed 3 * rowHeight)
16712    margins: 1,
16713    border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
16714
16715    lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
16716
16717    justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
16718                             * (i.e. lastRow setting is not considered) */
16719    waitThumbnailsLoad: true,
16720    captions: true,
16721    cssAnimation: true,
16722    imagesAnimationDuration: 500, // ignored with css animations
16723    captionSettings: { // ignored with css animations
16724      animationDuration: 500,
16725      visibleOpacity: 0.7,
16726      nonVisibleOpacity: 0.0
16727    },
vendor: 5,760 bytes, lines 16728-16871
16728    rel: null, // rewrite the rel of each analyzed links
16729    target: null, // rewrite the target of all links
16730    extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
16731    refreshTime: 200, // time interval (in ms) to check if the page changes its width
16732    refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
16733    randomize: false,
16734    sort: false, /*
16735      - false: to do not sort
16736      - function: to sort them using the function as comparator (see Array.prototype.sort())
16737    */
16738    filter: false, /*
16739      - false, null or undefined: for a disabled filter
16740      - a string: an entry is kept if entry.is(filter string) returns true
16741                  see jQuery's .is() function for further information
16742      - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
16743                    It follows the specifications of the Array.prototype.filter() function of JavaScript.
16744    */
16745    selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery
16746  };
16747
16748}(jQuery));
16749
16750/*!
16751* Customized version of iScroll.js 0.0.1
16752* It fixes bugs affecting its integration with fullpage.js
16753*/
16754/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
16755(function (window, document, Math) {
16756var rAF = window.requestAnimationFrame  ||
16757    window.webkitRequestAnimationFrame  ||
16758    window.mozRequestAnimationFrame     ||
16759    window.oRequestAnimationFrame       ||
16760    window.msRequestAnimationFrame      ||
16761    function (callback) { window.setTimeout(callback, 1000 / 60); };
16762
16763var utils = (function () {
16764    var me = {};
16765
16766    var _elementStyle = document.createElement('div').style;
16767    var _vendor = (function () {
16768        var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
16769            transform,
16770            i = 0,
16771            l = vendors.length;
16772
16773        for ( ; i < l; i++ ) {
16774            transform = vendors[i] + 'ransform';
16775            if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
16776        }
16777
16778        return false;
16779    })();
16780
16781    function _prefixStyle (style) {
16782        if ( _vendor === false ) return false;
16783        if ( _vendor === '' ) return style;
16784        return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
16785    }
16786
16787    me.getTime = Date.now || function getTime () { return new Date().getTime(); };
16788
16789    me.extend = function (target, obj) {
16790        for ( var i in obj ) {
16791            target[i] = obj[i];
16792        }
16793    };
16794
16795    me.addEvent = function (el, type, fn, capture) {
16796        el.addEventListener(type, fn, !!capture);
16797    };
16798
16799    me.removeEvent = function (el, type, fn, capture) {
16800        el.removeEventListener(type, fn, !!capture);
16801    };
16802
16803    me.prefixPointerEvent = function (pointerEvent) {
16804        return window.MSPointerEvent ?
16805            'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
16806            pointerEvent;
16807    };
16808
16809    me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
16810        var distance = current - start,
16811            speed = Math.abs(distance) / time,
16812            destination,
16813            duration;
16814
16815        deceleration = deceleration === undefined ? 0.0006 : deceleration;
16816
16817        destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
16818        duration = speed / deceleration;
16819
16820        if ( destination < lowerMargin ) {
16821            destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
16822            distance = Math.abs(destination - current);
16823            duration = distance / speed;
16824        } else if ( destination > 0 ) {
16825            destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
16826            distance = Math.abs(current) + destination;
16827            duration = distance / speed;
16828        }
16829
16830        return {
16831            destination: Math.round(destination),
16832            duration: duration
16833        };
16834    };
16835
16836    var _transform = _prefixStyle('transform');
16837
16838    me.extend(me, {
16839        hasTransform: _transform !== false,
16840        hasPerspective: _prefixStyle('perspective') in _elementStyle,
16841        hasTouch: 'ontouchstart' in window,
16842        hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
16843        hasTransition: _prefixStyle('transition') in _elementStyle
16844    });
16845
16846    /*
16847    This should find all Android browsers lower than build 535.19 (both stock browser and webview)
16848    - galaxy S2 is ok
16849    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
16850    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16851   - galaxy S3 is badAndroid (stock brower, webview)
16852     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16853   - galaxy S4 is badAndroid (stock brower, webview)
16854     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16855   - galaxy S5 is OK
16856     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
16857   - galaxy S6 is OK
16858     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
16859  */
16860    me.isBadAndroid = (function() {
16861        var appVersion = window.navigator.appVersion;
16862        // Android browser is not a chrome browser.
16863        if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
16864            var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
16865            if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
16866                return parseFloat(safariVersion[1]) < 535.19;
16867            } else {
16868                return true;
16869            }
16870        } else {
16871            return false;
vendor: 5,536 bytes, lines 16872-17064
16872        }
16873    })();
16874
16875    me.extend(me.style = {}, {
16876        transform: _transform,
16877        transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
16878        transitionDuration: _prefixStyle('transitionDuration'),
16879        transitionDelay: _prefixStyle('transitionDelay'),
16880        transformOrigin: _prefixStyle('transformOrigin')
16881    });
16882
16883    me.hasClass = function (e, c) {
16884        var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
16885        return re.test(e.className);
16886    };
16887
16888    me.addClass = function (e, c) {
16889        if ( me.hasClass(e, c) ) {
16890            return;
16891        }
16892
16893        var newclass = e.className.split(' ');
16894        newclass.push(c);
16895        e.className = newclass.join(' ');
16896    };
16897
16898    me.removeClass = function (e, c) {
16899        if ( !me.hasClass(e, c) ) {
16900            return;
16901        }
16902
16903        var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
16904        e.className = e.className.replace(re, ' ');
16905    };
16906
16907    me.offset = function (el) {
16908        var left = -el.offsetLeft,
16909            top = -el.offsetTop;
16910
16911        // jshint -W084
16912        while (el = el.offsetParent) {
16913            left -= el.offsetLeft;
16914            top -= el.offsetTop;
16915        }
16916        // jshint +W084
16917
16918        return {
16919            left: left,
16920            top: top
16921        };
16922    };
16923
16924    me.preventDefaultException = function (el, exceptions) {
16925        for ( var i in exceptions ) {
16926            if ( exceptions[i].test(el[i]) ) {
16927                return true;
16928            }
16929        }
16930
16931        return false;
16932    };
16933
16934    me.extend(me.eventType = {}, {
16935        touchstart: 1,
16936        touchmove: 1,
16937        touchend: 1,
16938
16939        mousedown: 2,
16940        mousemove: 2,
16941        mouseup: 2,
16942
16943        pointerdown: 3,
16944        pointermove: 3,
16945        pointerup: 3,
16946
16947        MSPointerDown: 3,
16948        MSPointerMove: 3,
16949        MSPointerUp: 3
16950    });
16951
16952    me.extend(me.ease = {}, {
16953        quadratic: {
16954            style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
16955            fn: function (k) {
16956                return k * ( 2 - k );
16957            }
16958        },
16959        circular: {
16960            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)
16961            fn: function (k) {
16962                return Math.sqrt( 1 - ( --k * k ) );
16963            }
16964        },
16965        back: {
16966            style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
16967            fn: function (k) {
16968                var b = 4;
16969                return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
16970            }
16971        },
16972        bounce: {
16973            style: '',
16974            fn: function (k) {
16975                if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
16976                    return 7.5625 * k * k;
16977                } else if ( k < ( 2 / 2.75 ) ) {
16978                    return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
16979                } else if ( k < ( 2.5 / 2.75 ) ) {
16980                    return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
16981                } else {
16982                    return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
16983                }
16984            }
16985        },
16986        elastic: {
16987            style: '',
16988            fn: function (k) {
16989                var f = 0.22,
16990                    e = 0.4;
16991
16992                if ( k === 0 ) { return 0; }
16993                if ( k == 1 ) { return 1; }
16994
16995                return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
16996            }
16997        }
16998    });
16999
17000    me.tap = function (e, eventName) {
17001        var ev = document.createEvent('Event');
17002        ev.initEvent(eventName, true, true);
17003        ev.pageX = e.pageX;
17004        ev.pageY = e.pageY;
17005        e.target.dispatchEvent(ev);
17006    };
17007
17008    me.click = function (e) {
17009        var target = e.target,
17010            ev;
17011
17012        if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
17013            // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
17014            // initMouseEvent is deprecated.
17015            ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
17016            ev.initEvent('click', true, true);
17017            ev.view = e.view || window;
17018            ev.detail = 1;
17019            ev.screenX = target.screenX || 0;
17020            ev.screenY = target.screenY || 0;
17021            ev.clientX = target.clientX || 0;
17022            ev.clientY = target.clientY || 0;
17023            ev.ctrlKey = !!e.ctrlKey;
17024            ev.altKey = !!e.altKey;
17025            ev.shiftKey = !!e.shiftKey;
17026            ev.metaKey = !!e.metaKey;
17027            ev.button = 0;
17028            ev.relatedTarget = null;
17029            ev._constructed = true;
17030            target.dispatchEvent(ev);
17031        }
17032    };
17033
17034    return me;
17035})();
17036function IScroll (el, options) {
17037    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
17038    this.scroller = this.wrapper.children[0];
17039    this.scrollerStyle = this.scroller.style;       // cache style for better performance
17040
17041    this.options = {
17042
17043        resizeScrollbars: true,
17044
17045        mouseWheelSpeed: 20,
17046
17047        snapThreshold: 0.334,
17048
17049// INSERT POINT: OPTIONS
17050        disablePointer : !utils.hasPointer,
17051        disableTouch : utils.hasPointer || !utils.hasTouch,
17052        disableMouse : utils.hasPointer || utils.hasTouch,
17053        startX: 0,
17054        startY: 0,
17055        scrollY: true,
17056        directionLockThreshold: 5,
17057        momentum: true,
17058
17059        bounce: true,
17060        bounceTime: 600,
17061        bounceEasing: '',
17062
17063        preventDefault: true,
17064        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
vendor: 4,420 bytes, lines 17064-17208
17064SELECT|LABEL)$/ },
17065
17066        HWCompositing: true,
17067        useTransition: true,
17068        useTransform: true,
17069        bindToWrapper: typeof window.onmousedown === "undefined"
17070    };
17071
17072    for ( var i in options ) {
17073        this.options[i] = options[i];
17074    }
17075
17076    // Normalize options
17077    this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
17078
17079    this.options.useTransition = utils.hasTransition && this.options.useTransition;
17080    this.options.useTransform = utils.hasTransform && this.options.useTransform;
17081
17082    this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
17083    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
17084
17085    // If you want eventPassthrough I have to lock one of the axes
17086    this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
17087    this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
17088
17089    // With eventPassthrough we also need lockDirection mechanism
17090    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
17091    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
17092
17093    this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
17094
17095    this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
17096
17097    if ( this.options.tap === true ) {
17098        this.options.tap = 'tap';
17099    }
17100
17101    // https://github.com/cubiq/iscroll/issues/1029
17102    if (!this.options.useTransition && !this.options.useTransform) {
17103        if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
17104            this.scrollerStyle.position = "relative";
17105        }
17106    }
17107
17108    if ( this.options.shrinkScrollbars == 'scale' ) {
17109        this.options.useTransition = false;
17110    }
17111
17112    this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
17113
17114// INSERT POINT: NORMALIZATION
17115
17116    // Some defaults
17117    this.x = 0;
17118    this.y = 0;
17119    this.directionX = 0;
17120    this.directionY = 0;
17121    this._events = {};
17122
17123// INSERT POINT: DEFAULTS
17124
17125    this._init();
17126    this.refresh();
17127
17128    this.scrollTo(this.options.startX, this.options.startY);
17129    this.enable();
17130}
17131
17132IScroll.prototype = {
17133    version: '5.2.0',
17134
17135    _init: function () {
17136        this._initEvents();
17137
17138        if ( this.options.scrollbars || this.options.indicators ) {
17139            this._initIndicators();
17140        }
17141
17142        if ( this.options.mouseWheel ) {
17143            this._initWheel();
17144        }
17145
17146        if ( this.options.snap ) {
17147            this._initSnap();
17148        }
17149
17150        if ( this.options.keyBindings ) {
17151            this._initKeys();
17152        }
17153
17154// INSERT POINT: _init
17155
17156    },
17157
17158    destroy: function () {
17159        this._initEvents(true);
17160        clearTimeout(this.resizeTimeout);
17161        this.resizeTimeout = null;
17162        this._execEvent('destroy');
17163    },
17164
17165    _transitionEnd: function (e) {
17166        if ( e.target != this.scroller || !this.isInTransition ) {
17167            return;
17168        }
17169
17170        this._transitionTime();
17171        if ( !this.resetPosition(this.options.bounceTime) ) {
17172            this.isInTransition = false;
17173            this._execEvent('scrollEnd');
17174        }
17175    },
17176
17177    _start: function (e) {
17178        // React to left mouse button only
17179        if ( utils.eventType[e.type] != 1 ) {
17180          // for button property
17181          // http://unixpapa.com/js/mouse.html
17182          var button;
17183        if (!e.which) {
17184          /* IE case */
17185          button = (e.button < 2) ? 0 :
17186                   ((e.button == 4) ? 1 : 2);
17187        } else {
17188          /* All others */
17189          button = e.button;
17190        }
17191            if ( button !== 0 ) {
17192                return;
17193            }
17194        }
17195
17196        if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
17197            return;
17198        }
17199
17200        if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
17201            e.preventDefault();
17202        }
17203
17204        var point = e.touches ? e.touches[0] : e,
17205            pos;
17206
17207        this.initiated  = utils.eventType[e.type];
17208        this.moved      = false;
vendor: 5,928 bytes, lines 17209-17387
17209        this.distX      = 0;
17210        this.distY      = 0;
17211        this.directionX = 0;
17212        this.directionY = 0;
17213        this.directionLocked = 0;
17214
17215        this.startTime = utils.getTime();
17216
17217        if ( this.options.useTransition && this.isInTransition ) {
17218            this._transitionTime();
17219            this.isInTransition = false;
17220            pos = this.getComputedPosition();
17221            this._translate(Math.round(pos.x), Math.round(pos.y));
17222            this._execEvent('scrollEnd');
17223        } else if ( !this.options.useTransition && this.isAnimating ) {
17224            this.isAnimating = false;
17225            this._execEvent('scrollEnd');
17226        }
17227
17228        this.startX    = this.x;
17229        this.startY    = this.y;
17230        this.absStartX = this.x;
17231        this.absStartY = this.y;
17232        this.pointX    = point.pageX;
17233        this.pointY    = point.pageY;
17234
17235        this._execEvent('beforeScrollStart');
17236    },
17237
17238    _move: function (e) {
17239        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
17240            return;
17241        }
17242
17243        if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
17244            e.preventDefault();
17245        }
17246
17247        var point       = e.touches ? e.touches[0] : e,
17248            deltaX      = point.pageX - this.pointX,
17249            deltaY      = point.pageY - this.pointY,
17250            timestamp   = utils.getTime(),
17251            newX, newY,
17252            absDistX, absDistY;
17253
17254        this.pointX     = point.pageX;
17255        this.pointY     = point.pageY;
17256
17257        this.distX      += deltaX;
17258        this.distY      += deltaY;
17259        absDistX        = Math.abs(this.distX);
17260        absDistY        = Math.abs(this.distY);
17261
17262        // We need to move at least 10 pixels for the scrolling to initiate
17263        if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
17264            return;
17265        }
17266
17267        // If you are scrolling in one direction lock the other
17268        if ( !this.directionLocked && !this.options.freeScroll ) {
17269            if ( absDistX > absDistY + this.options.directionLockThreshold ) {
17270                this.directionLocked = 'h';     // lock horizontally
17271            } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
17272                this.directionLocked = 'v';     // lock vertically
17273            } else {
17274                this.directionLocked = 'n';     // no lock
17275            }
17276        }
17277
17278        if ( this.directionLocked == 'h' ) {
17279            if ( this.options.eventPassthrough == 'vertical' ) {
17280                e.preventDefault();
17281            } else if ( this.options.eventPassthrough == 'horizontal' ) {
17282                this.initiated = false;
17283                return;
17284            }
17285
17286            deltaY = 0;
17287        } else if ( this.directionLocked == 'v' ) {
17288            if ( this.options.eventPassthrough == 'horizontal' ) {
17289                e.preventDefault();
17290            } else if ( this.options.eventPassthrough == 'vertical' ) {
17291                this.initiated = false;
17292                return;
17293            }
17294
17295            deltaX = 0;
17296        }
17297
17298        deltaX = this.hasHorizontalScroll ? deltaX : 0;
17299        deltaY = this.hasVerticalScroll ? deltaY : 0;
17300
17301        newX = this.x + deltaX;
17302        newY = this.y + deltaY;
17303
17304        // Slow down if outside of the boundaries
17305        if ( newX > 0 || newX < this.maxScrollX ) {
17306            newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
17307        }
17308        if ( newY > 0 || newY < this.maxScrollY ) {
17309            newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
17310        }
17311
17312        this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
17313        this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
17314
17315        if ( !this.moved ) {
17316            this._execEvent('scrollStart');
17317        }
17318
17319        this.moved = true;
17320
17321        this._translate(newX, newY);
17322
17323/* REPLACE START: _move */
17324
17325        if ( timestamp - this.startTime > 300 ) {
17326            this.startTime = timestamp;
17327            this.startX = this.x;
17328            this.startY = this.y;
17329        }
17330
17331/* REPLACE END: _move */
17332
17333    },
17334
17335    _end: function (e) {
17336        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
17337            return;
17338        }
17339
17340        if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
17341            e.preventDefault();
17342        }
17343
17344        var point = e.changedTouches ? e.changedTouches[0] : e,
17345            momentumX,
17346            momentumY,
17347            duration = utils.getTime() - this.startTime,
17348            newX = Math.round(this.x),
17349            newY = Math.round(this.y),
17350            distanceX = Math.abs(newX - this.startX),
17351            distanceY = Math.abs(newY - this.startY),
17352            time = 0,
17353            easing = '';
17354
17355        this.isInTransition = 0;
17356        this.initiated = 0;
17357        this.endTime = utils.getTime();
17358
17359        // reset if we are outside of the boundaries
17360        if ( this.resetPosition(this.options.bounceTime) ) {
17361            return;
17362        }
17363
17364        this.scrollTo(newX, newY);  // ensures that the last position is rounded
17365
17366        // we scrolled less than 10 pixels
17367        if ( !this.moved ) {
17368            if ( this.options.tap ) {
17369                utils.tap(e, this.options.tap);
17370            }
17371
17372            if ( this.options.click ) {
17373                utils.click(e);
17374            }
17375
17376            this._execEvent('scrollCancel');
17377            return;
17378        }
17379
17380        if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
17381            this._execEvent('flick');
17382            return;
17383        }
17384
17385        // start momentum animation if needed
17386        if ( this.options.momentum && duration < 300 ) {
17387            momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 7,740 bytes, lines 17387-17660
17387idth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
17388            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 };
17389            newX = momentumX.destination;
17390            newY = momentumY.destination;
17391            time = Math.max(momentumX.duration, momentumY.duration);
17392            this.isInTransition = 1;
17393        }
17394
17395
17396        if ( this.options.snap ) {
17397            var snap = this._nearestSnap(newX, newY);
17398            this.currentPage = snap;
17399            time = this.options.snapSpeed || Math.max(
17400                    Math.max(
17401                        Math.min(Math.abs(newX - snap.x), 1000),
17402                        Math.min(Math.abs(newY - snap.y), 1000)
17403                    ), 300);
17404            newX = snap.x;
17405            newY = snap.y;
17406
17407            this.directionX = 0;
17408            this.directionY = 0;
17409            easing = this.options.bounceEasing;
17410        }
17411
17412// INSERT POINT: _end
17413
17414        if ( newX != this.x || newY != this.y ) {
17415            // change easing function when scroller goes out of the boundaries
17416            if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
17417                easing = utils.ease.quadratic;
17418            }
17419
17420            this.scrollTo(newX, newY, time, easing);
17421            return;
17422        }
17423
17424        this._execEvent('scrollEnd');
17425    },
17426
17427    _resize: function () {
17428        var that = this;
17429
17430        clearTimeout(this.resizeTimeout);
17431
17432        this.resizeTimeout = setTimeout(function () {
17433            that.refresh();
17434        }, this.options.resizePolling);
17435    },
17436
17437    resetPosition: function (time) {
17438        var x = this.x,
17439            y = this.y;
17440
17441        time = time || 0;
17442
17443        if ( !this.hasHorizontalScroll || this.x > 0 ) {
17444            x = 0;
17445        } else if ( this.x < this.maxScrollX ) {
17446            x = this.maxScrollX;
17447        }
17448
17449        if ( !this.hasVerticalScroll || this.y > 0 ) {
17450            y = 0;
17451        } else if ( this.y < this.maxScrollY ) {
17452            y = this.maxScrollY;
17453        }
17454
17455        if ( x == this.x && y == this.y ) {
17456            return false;
17457        }
17458
17459        this.scrollTo(x, y, time, this.options.bounceEasing);
17460
17461        return true;
17462    },
17463
17464    disable: function () {
17465        this.enabled = false;
17466    },
17467
17468    enable: function () {
17469        this.enabled = true;
17470    },
17471
17472    refresh: function () {
17473        var rf = this.wrapper.offsetHeight;     // Force reflow
17474
17475        this.wrapperWidth   = this.wrapper.clientWidth;
17476        this.wrapperHeight  = this.wrapper.clientHeight;
17477
17478/* REPLACE START: refresh */
17479
17480        this.scrollerWidth  = this.scroller.offsetWidth;
17481        this.scrollerHeight = this.scroller.offsetHeight;
17482
17483        this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
17484        this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
17485
17486/* REPLACE END: refresh */
17487
17488        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
17489        this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
17490
17491        if ( !this.hasHorizontalScroll ) {
17492            this.maxScrollX = 0;
17493            this.scrollerWidth = this.wrapperWidth;
17494        }
17495
17496        if ( !this.hasVerticalScroll ) {
17497            this.maxScrollY = 0;
17498            this.scrollerHeight = this.wrapperHeight;
17499        }
17500
17501        this.endTime = 0;
17502        this.directionX = 0;
17503        this.directionY = 0;
17504
17505        this.wrapperOffset = utils.offset(this.wrapper);
17506
17507        this._execEvent('refresh');
17508
17509        this.resetPosition();
17510
17511// INSERT POINT: _refresh
17512
17513    },
17514
17515    on: function (type, fn) {
17516        if ( !this._events[type] ) {
17517            this._events[type] = [];
17518        }
17519
17520        this._events[type].push(fn);
17521    },
17522
17523    off: function (type, fn) {
17524        if ( !this._events[type] ) {
17525            return;
17526        }
17527
17528        var index = this._events[type].indexOf(fn);
17529
17530        if ( index > -1 ) {
17531            this._events[type].splice(index, 1);
17532        }
17533    },
17534
17535    _execEvent: function (type) {
17536        if ( !this._events[type] ) {
17537            return;
17538        }
17539
17540        var i = 0,
17541            l = this._events[type].length;
17542
17543        if ( !l ) {
17544            return;
17545        }
17546
17547        for ( ; i < l; i++ ) {
17548            this._events[type][i].apply(this, [].slice.call(arguments, 1));
17549        }
17550    },
17551
17552    scrollBy: function (x, y, time, easing) {
17553        x = this.x + x;
17554        y = this.y + y;
17555        time = time || 0;
17556
17557        this.scrollTo(x, y, time, easing);
17558    },
17559
17560    scrollTo: function (x, y, time, easing) {
17561        easing = easing || utils.ease.circular;
17562
17563        this.isInTransition = this.options.useTransition && time > 0;
17564        var transitionType = this.options.useTransition && easing.style;
17565        if ( !time || transitionType ) {
17566                if(transitionType) {
17567                    this._transitionTimingFunction(easing.style);
17568                    this._transitionTime(time);
17569                }
17570            this._translate(x, y);
17571        } else {
17572            this._animate(x, y, time, easing.fn);
17573        }
17574    },
17575
17576    scrollToElement: function (el, time, offsetX, offsetY, easing) {
17577        el = el.nodeType ? el : this.scroller.querySelector(el);
17578
17579        if ( !el ) {
17580            return;
17581        }
17582
17583        var pos = utils.offset(el);
17584
17585        pos.left -= this.wrapperOffset.left;
17586        pos.top  -= this.wrapperOffset.top;
17587
17588        // if offsetX/Y are true we center the element to the screen
17589        if ( offsetX === true ) {
17590            offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
17591        }
17592        if ( offsetY === true ) {
17593            offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
17594        }
17595
17596        pos.left -= offsetX || 0;
17597        pos.top  -= offsetY || 0;
17598
17599        pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
17600        pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
17601
17602        time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
17603
17604        this.scrollTo(pos.left, pos.top, time, easing);
17605    },
17606
17607    _transitionTime: function (time) {
17608        if (!this.options.useTransition) {
17609            return;
17610        }
17611        time = time || 0;
17612        var durationProp = utils.style.transitionDuration;
17613        if(!durationProp) {
17614            return;
17615        }
17616
17617        this.scrollerStyle[durationProp] = time + 'ms';
17618
17619        if ( !time && utils.isBadAndroid ) {
17620            this.scrollerStyle[durationProp] = '0.0001ms';
17621            // remove 0.0001ms
17622            var self = this;
17623            rAF(function() {
17624                if(self.scrollerStyle[durationProp] === '0.0001ms') {
17625                    self.scrollerStyle[durationProp] = '0s';
17626                }
17627            });
17628        }
17629
17630
17631        if ( this.indicators ) {
17632            for ( var i = this.indicators.length; i--; ) {
17633                this.indicators[i].transitionTime(time);
17634            }
17635        }
17636
17637
17638// INSERT POINT: _transitionTime
17639
17640    },
17641
17642    _transitionTimingFunction: function (easing) {
17643        this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
17644
17645
17646        if ( this.indicators ) {
17647            for ( var i = this.indicators.length; i--; ) {
17648                this.indicators[i].transitionTimingFunction(easing);
17649            }
17650        }
17651
17652
17653// INSERT POINT: _transitionTimingFunction
17654
17655    },
17656
17657    _translate: function (x, y) {
17658        //Uncode addition
17659        if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
17660            return false;
vendor: 9,940 bytes, lines 17661-17972
17661
17662        if ( this.options.useTransform ) {
17663
17664/* REPLACE START: _translate */
17665
17666            this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
17667
17668/* REPLACE END: _translate */
17669
17670        } else {
17671            x = Math.round(x);
17672            y = Math.round(y);
17673            this.scrollerStyle.left = x + 'px';
17674            this.scrollerStyle.top = y + 'px';
17675        }
17676
17677        this.x = x;
17678        this.y = y;
17679
17680
17681        if ( this.indicators ) {
17682            for ( var i = this.indicators.length; i--; ) {
17683                this.indicators[i].updatePosition();
17684            }
17685        }
17686
17687        //Uncode addition
17688        var uncodevent = new Event('fp-slide-scroll');
17689        window.dispatchEvent(uncodevent);       
17690
17691// INSERT POINT: _translate
17692
17693    },
17694
17695    _initEvents: function (remove) {
17696        var eventType = remove ? utils.removeEvent : utils.addEvent,
17697            target = this.options.bindToWrapper ? this.wrapper : window;
17698
17699        eventType(window, 'orientationchange', this);
17700        eventType(window, 'resize', this);
17701
17702        if ( this.options.click ) {
17703            eventType(this.wrapper, 'click', this, true);
17704        }
17705
17706        if ( !this.options.disableMouse ) {
17707            eventType(this.wrapper, 'mousedown', this);
17708            eventType(target, 'mousemove', this);
17709            eventType(target, 'mousecancel', this);
17710            eventType(target, 'mouseup', this);
17711        }
17712
17713        if ( utils.hasPointer && !this.options.disablePointer ) {
17714            eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
17715            eventType(target, utils.prefixPointerEvent('pointermove'), this);
17716            eventType(target, utils.prefixPointerEvent('pointercancel'), this);
17717            eventType(target, utils.prefixPointerEvent('pointerup'), this);
17718        }
17719
17720        if ( utils.hasTouch && !this.options.disableTouch ) {
17721            eventType(this.wrapper, 'touchstart', this);
17722            eventType(target, 'touchmove', this);
17723            eventType(target, 'touchcancel', this);
17724            eventType(target, 'touchend', this);
17725        }
17726
17727        eventType(this.scroller, 'transitionend', this);
17728        eventType(this.scroller, 'webkitTransitionEnd', this);
17729        eventType(this.scroller, 'oTransitionEnd', this);
17730        eventType(this.scroller, 'MSTransitionEnd', this);
17731    },
17732
17733    getComputedPosition: function () {
17734        var matrix = window.getComputedStyle(this.scroller, null),
17735            x, y;
17736
17737        if ( this.options.useTransform ) {
17738            matrix = matrix[utils.style.transform].split(')')[0].split(', ');
17739            x = +(matrix[12] || matrix[4]);
17740            y = +(matrix[13] || matrix[5]);
17741        } else {
17742            x = +matrix.left.replace(/[^-\d.]/g, '');
17743            y = +matrix.top.replace(/[^-\d.]/g, '');
17744        }
17745
17746        return { x: x, y: y };
17747    },
17748    _initIndicators: function () {
17749        var interactive = this.options.interactiveScrollbars,
17750            customStyle = typeof this.options.scrollbars != 'string',
17751            indicators = [],
17752            indicator;
17753
17754        var that = this;
17755
17756        this.indicators = [];
17757
17758        if ( this.options.scrollbars ) {
17759            // Vertical scrollbar
17760            if ( this.options.scrollY ) {
17761                indicator = {
17762                    el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
17763                    interactive: interactive,
17764                    defaultScrollbars: true,
17765                    customStyle: customStyle,
17766                    resize: this.options.resizeScrollbars,
17767                    shrink: this.options.shrinkScrollbars,
17768                    fade: this.options.fadeScrollbars,
17769                    listenX: false
17770                };
17771
17772                this.wrapper.appendChild(indicator.el);
17773                indicators.push(indicator);
17774            }
17775
17776            // Horizontal scrollbar
17777            if ( this.options.scrollX ) {
17778                indicator = {
17779                    el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
17780                    interactive: interactive,
17781                    defaultScrollbars: true,
17782                    customStyle: customStyle,
17783                    resize: this.options.resizeScrollbars,
17784                    shrink: this.options.shrinkScrollbars,
17785                    fade: this.options.fadeScrollbars,
17786                    listenY: false
17787                };
17788
17789                this.wrapper.appendChild(indicator.el);
17790                indicators.push(indicator);
17791            }
17792        }
17793
17794        if ( this.options.indicators ) {
17795            // TODO: check concat compatibility
17796            indicators = indicators.concat(this.options.indicators);
17797        }
17798
17799        for ( var i = indicators.length; i--; ) {
17800            this.indicators.push( new Indicator(this, indicators[i]) );
17801        }
17802
17803        // TODO: check if we can use array.map (wide compatibility and performance issues)
17804        function _indicatorsMap (fn) {
17805            if (that.indicators) {
17806                for ( var i = that.indicators.length; i--; ) {
17807                    fn.call(that.indicators[i]);
17808                }
17809            }
17810        }
17811
17812        if ( this.options.fadeScrollbars ) {
17813            this.on('scrollEnd', function () {
17814                _indicatorsMap(function () {
17815                    this.fade();
17816                });
17817            });
17818
17819            this.on('scrollCancel', function () {
17820                _indicatorsMap(function () {
17821                    this.fade();
17822                });
17823            });
17824
17825            this.on('scrollStart', function () {
17826                _indicatorsMap(function () {
17827                    this.fade(1);
17828                });
17829            });
17830
17831            this.on('beforeScrollStart', function () {
17832                _indicatorsMap(function () {
17833                    this.fade(1, true);
17834                });
17835            });
17836        }
17837
17838
17839        this.on('refresh', function () {
17840            _indicatorsMap(function () {
17841                this.refresh();
17842            });
17843        });
17844
17845        this.on('destroy', function () {
17846            _indicatorsMap(function () {
17847                this.destroy();
17848            });
17849
17850            delete this.indicators;
17851        });
17852    },
17853
17854    _initWheel: function () {
17855        utils.addEvent(this.wrapper, 'wheel', this);
17856        utils.addEvent(this.wrapper, 'mousewheel', this);
17857        utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
17858
17859        this.on('destroy', function () {
17860            clearTimeout(this.wheelTimeout);
17861            this.wheelTimeout = null;
17862            utils.removeEvent(this.wrapper, 'wheel', this);
17863            utils.removeEvent(this.wrapper, 'mousewheel', this);
17864            utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
17865        });
17866    },
17867
17868    _wheel: function (e) {
17869        if ( !this.enabled ) {
17870            return;
17871        }
17872
17873        var wheelDeltaX, wheelDeltaY,
17874            newX, newY,
17875            that = this;
17876
17877        if ( this.wheelTimeout === undefined ) {
17878            that._execEvent('scrollStart');
17879        }
17880
17881        // Execute the scrollEnd event after 400ms the wheel stopped scrolling
17882        clearTimeout(this.wheelTimeout);
17883        this.wheelTimeout = setTimeout(function () {
17884            if(!that.options.snap) {
17885                that._execEvent('scrollEnd');
17886            }
17887            that.wheelTimeout = undefined;
17888        }, 400);
17889
17890        if ( 'deltaX' in e ) {
17891            if (e.deltaMode === 1) {
17892                wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
17893                wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
17894            } else {
17895                wheelDeltaX = -e.deltaX;
17896                wheelDeltaY = -e.deltaY;
17897            }
17898        } else if ( 'wheelDeltaX' in e ) {
17899            wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
17900            wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
17901        } else if ( 'wheelDelta' in e ) {
17902            wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
17903        } else if ( 'detail' in e ) {
17904            wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
17905        } else {
17906            return;
17907        }
17908
17909        wheelDeltaX *= this.options.invertWheelDirection;
17910        wheelDeltaY *= this.options.invertWheelDirection;
17911
17912        if ( !this.hasVerticalScroll ) {
17913            wheelDeltaX = wheelDeltaY;
17914            wheelDeltaY = 0;
17915        }
17916
17917        if ( this.options.snap ) {
17918            newX = this.currentPage.pageX;
17919            newY = this.currentPage.pageY;
17920
17921            if ( wheelDeltaX > 0 ) {
17922                newX--;
17923            } else if ( wheelDeltaX < 0 ) {
17924                newX++;
17925            }
17926
17927            if ( wheelDeltaY > 0 ) {
17928                newY--;
17929            } else if ( wheelDeltaY < 0 ) {
17930                newY++;
17931            }
17932
17933            this.goToPage(newX, newY);
17934
17935            return;
17936        }
17937
17938        newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
17939        newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
17940
17941        this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
17942        this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
17943
17944        if ( newX > 0 ) {
17945            newX = 0;
17946        } else if ( newX < this.maxScrollX ) {
17947            newX = this.maxScrollX;
17948        }
17949
17950        if ( newY > 0 ) {
17951            newY = 0;
17952        } else if ( newY < this.maxScrollY ) {
17953            newY = this.maxScrollY;
17954        }
17955
17956        this.scrollTo(newX, newY, 0);
17957
17958// INSERT POINT: _wheel
17959    },
17960
17961    _initSnap: function () {
17962        this.currentPage = {};
17963
17964        if ( typeof this.options.snap == 'string' ) {
17965            this.options.snap = this.scroller.querySelectorAll(this.options.snap);
17966        }
17967
17968        this.on('refresh', function () {
17969            var i = 0, l,
17970                m = 0, n,
17971                cx, cy,
17972                x = 0, y,
vendor: 7,339 bytes, lines 17973-18226
17973                stepX = this.options.snapStepX || this.wrapperWidth,
17974                stepY = this.options.snapStepY || this.wrapperHeight,
17975                el;
17976
17977            this.pages = [];
17978
17979            if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
17980                return;
17981            }
17982
17983            if ( this.options.snap === true ) {
17984                cx = Math.round( stepX / 2 );
17985                cy = Math.round( stepY / 2 );
17986
17987                while ( x > -this.scrollerWidth ) {
17988                    this.pages[i] = [];
17989                    l = 0;
17990                    y = 0;
17991
17992                    while ( y > -this.scrollerHeight ) {
17993                        this.pages[i][l] = {
17994                            x: Math.max(x, this.maxScrollX),
17995                            y: Math.max(y, this.maxScrollY),
17996                            width: stepX,
17997                            height: stepY,
17998                            cx: x - cx,
17999                            cy: y - cy
18000                        };
18001
18002                        y -= stepY;
18003                        l++;
18004                    }
18005
18006                    x -= stepX;
18007                    i++;
18008                }
18009            } else {
18010                el = this.options.snap;
18011                l = el.length;
18012                n = -1;
18013
18014                for ( ; i < l; i++ ) {
18015                    if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
18016                        m = 0;
18017                        n++;
18018                    }
18019
18020                    if ( !this.pages[m] ) {
18021                        this.pages[m] = [];
18022                    }
18023
18024                    x = Math.max(-el[i].offsetLeft, this.maxScrollX);
18025                    y = Math.max(-el[i].offsetTop, this.maxScrollY);
18026                    cx = x - Math.round(el[i].offsetWidth / 2);
18027                    cy = y - Math.round(el[i].offsetHeight / 2);
18028
18029                    this.pages[m][n] = {
18030                        x: x,
18031                        y: y,
18032                        width: el[i].offsetWidth,
18033                        height: el[i].offsetHeight,
18034                        cx: cx,
18035                        cy: cy
18036                    };
18037
18038                    if ( x > this.maxScrollX ) {
18039                        m++;
18040                    }
18041                }
18042            }
18043
18044            this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
18045
18046            // Update snap threshold if needed
18047            if ( this.options.snapThreshold % 1 === 0 ) {
18048                this.snapThresholdX = this.options.snapThreshold;
18049                this.snapThresholdY = this.options.snapThreshold;
18050            } else {
18051                this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
18052                this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
18053            }
18054        });
18055
18056        this.on('flick', function () {
18057            var time = this.options.snapSpeed || Math.max(
18058                    Math.max(
18059                        Math.min(Math.abs(this.x - this.startX), 1000),
18060                        Math.min(Math.abs(this.y - this.startY), 1000)
18061                    ), 300);
18062
18063            this.goToPage(
18064                this.currentPage.pageX + this.directionX,
18065                this.currentPage.pageY + this.directionY,
18066                time
18067            );
18068        });
18069    },
18070
18071    _nearestSnap: function (x, y) {
18072        if ( !this.pages.length ) {
18073            return { x: 0, y: 0, pageX: 0, pageY: 0 };
18074        }
18075
18076        var i = 0,
18077            l = this.pages.length,
18078            m = 0;
18079
18080        // Check if we exceeded the snap threshold
18081        if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
18082            Math.abs(y - this.absStartY) < this.snapThresholdY ) {
18083            return this.currentPage;
18084        }
18085
18086        if ( x > 0 ) {
18087            x = 0;
18088        } else if ( x < this.maxScrollX ) {
18089            x = this.maxScrollX;
18090        }
18091
18092        if ( y > 0 ) {
18093            y = 0;
18094        } else if ( y < this.maxScrollY ) {
18095            y = this.maxScrollY;
18096        }
18097
18098        for ( ; i < l; i++ ) {
18099            if ( x >= this.pages[i][0].cx ) {
18100                x = this.pages[i][0].x;
18101                break;
18102            }
18103        }
18104
18105        l = this.pages[i].length;
18106
18107        for ( ; m < l; m++ ) {
18108            if ( y >= this.pages[0][m].cy ) {
18109                y = this.pages[0][m].y;
18110                break;
18111            }
18112        }
18113
18114        if ( i == this.currentPage.pageX ) {
18115            i += this.directionX;
18116
18117            if ( i < 0 ) {
18118                i = 0;
18119            } else if ( i >= this.pages.length ) {
18120                i = this.pages.length - 1;
18121            }
18122
18123            x = this.pages[i][0].x;
18124        }
18125
18126        if ( m == this.currentPage.pageY ) {
18127            m += this.directionY;
18128
18129            if ( m < 0 ) {
18130                m = 0;
18131            } else if ( m >= this.pages[0].length ) {
18132                m = this.pages[0].length - 1;
18133            }
18134
18135            y = this.pages[0][m].y;
18136        }
18137
18138        return {
18139            x: x,
18140            y: y,
18141            pageX: i,
18142            pageY: m
18143        };
18144    },
18145
18146    goToPage: function (x, y, time, easing) {
18147        easing = easing || this.options.bounceEasing;
18148
18149        if ( x >= this.pages.length ) {
18150            x = this.pages.length - 1;
18151        } else if ( x < 0 ) {
18152            x = 0;
18153        }
18154
18155        if ( y >= this.pages[x].length ) {
18156            y = this.pages[x].length - 1;
18157        } else if ( y < 0 ) {
18158            y = 0;
18159        }
18160
18161        var posX = this.pages[x][y].x,
18162            posY = this.pages[x][y].y;
18163
18164        time = time === undefined ? this.options.snapSpeed || Math.max(
18165            Math.max(
18166                Math.min(Math.abs(posX - this.x), 1000),
18167                Math.min(Math.abs(posY - this.y), 1000)
18168            ), 300) : time;
18169
18170        this.currentPage = {
18171            x: posX,
18172            y: posY,
18173            pageX: x,
18174            pageY: y
18175        };
18176
18177        this.scrollTo(posX, posY, time, easing);
18178    },
18179
18180    next: function (time, easing) {
18181        var x = this.currentPage.pageX,
18182            y = this.currentPage.pageY;
18183
18184        x++;
18185
18186        if ( x >= this.pages.length && this.hasVerticalScroll ) {
18187            x = 0;
18188            y++;
18189        }
18190
18191        this.goToPage(x, y, time, easing);
18192    },
18193
18194    prev: function (time, easing) {
18195        var x = this.currentPage.pageX,
18196            y = this.currentPage.pageY;
18197
18198        x--;
18199
18200        if ( x < 0 && this.hasVerticalScroll ) {
18201            x = 0;
18202            y--;
18203        }
18204
18205        this.goToPage(x, y, time, easing);
18206    },
18207
18208    _initKeys: function (e) {
18209        // default key bindings
18210        var keys = {
18211            pageUp: 33,
18212            pageDown: 34,
18213            end: 35,
18214            home: 36,
18215            left: 37,
18216            up: 38,
18217            right: 39,
18218            down: 40
18219        };
18220        var i;
18221
18222        // if you give me characters I give you keycode
18223        if ( typeof this.options.keyBindings == 'object' ) {
18224            for ( i in this.options.keyBindings ) {
18225                if ( typeof this.options.keyBindings[i] == 'string' ) {
18226                    this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 18226-18579
18226deAt(0);
18227                }
18228            }
18229        } else {
18230            this.options.keyBindings = {};
18231        }
18232
18233        for ( i in keys ) {
18234            this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
18235        }
18236
18237        utils.addEvent(window, 'keydown', this);
18238
18239        this.on('destroy', function () {
18240            utils.removeEvent(window, 'keydown', this);
18241        });
18242    },
18243
18244    _key: function (e) {
18245        if ( !this.enabled ) {
18246            return;
18247        }
18248
18249        var snap = this.options.snap,   // we are using this alot, better to cache it
18250            newX = snap ? this.currentPage.pageX : this.x,
18251            newY = snap ? this.currentPage.pageY : this.y,
18252            now = utils.getTime(),
18253            prevTime = this.keyTime || 0,
18254            acceleration = 0.250,
18255            pos;
18256
18257        if ( this.options.useTransition && this.isInTransition ) {
18258            pos = this.getComputedPosition();
18259
18260            this._translate(Math.round(pos.x), Math.round(pos.y));
18261            this.isInTransition = false;
18262        }
18263
18264        this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
18265
18266        switch ( e.keyCode ) {
18267            case this.options.keyBindings.pageUp:
18268                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
18269                    newX += snap ? 1 : this.wrapperWidth;
18270                } else {
18271                    newY += snap ? 1 : this.wrapperHeight;
18272                }
18273                break;
18274            case this.options.keyBindings.pageDown:
18275                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
18276                    newX -= snap ? 1 : this.wrapperWidth;
18277                } else {
18278                    newY -= snap ? 1 : this.wrapperHeight;
18279                }
18280                break;
18281            case this.options.keyBindings.end:
18282                newX = snap ? this.pages.length-1 : this.maxScrollX;
18283                newY = snap ? this.pages[0].length-1 : this.maxScrollY;
18284                break;
18285            case this.options.keyBindings.home:
18286                newX = 0;
18287                newY = 0;
18288                break;
18289            case this.options.keyBindings.left:
18290                newX += snap ? -1 : 5 + this.keyAcceleration>>0;
18291                break;
18292            case this.options.keyBindings.up:
18293                newY += snap ? 1 : 5 + this.keyAcceleration>>0;
18294                break;
18295            case this.options.keyBindings.right:
18296                newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
18297                break;
18298            case this.options.keyBindings.down:
18299                newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
18300                break;
18301            default:
18302                return;
18303        }
18304
18305        if ( snap ) {
18306            this.goToPage(newX, newY);
18307            return;
18308        }
18309
18310        if ( newX > 0 ) {
18311            newX = 0;
18312            this.keyAcceleration = 0;
18313        } else if ( newX < this.maxScrollX ) {
18314            newX = this.maxScrollX;
18315            this.keyAcceleration = 0;
18316        }
18317
18318        if ( newY > 0 ) {
18319            newY = 0;
18320            this.keyAcceleration = 0;
18321        } else if ( newY < this.maxScrollY ) {
18322            newY = this.maxScrollY;
18323            this.keyAcceleration = 0;
18324        }
18325
18326        this.scrollTo(newX, newY, 0);
18327
18328        this.keyTime = now;
18329    },
18330
18331    _animate: function (destX, destY, duration, easingFn) {
18332        var that = this,
18333            startX = this.x,
18334            startY = this.y,
18335            startTime = utils.getTime(),
18336            destTime = startTime + duration;
18337
18338        function step () {
18339            var now = utils.getTime(),
18340                newX, newY,
18341                easing;
18342
18343            if ( now >= destTime ) {
18344                that.isAnimating = false;
18345                that._translate(destX, destY);
18346
18347                if ( !that.resetPosition(that.options.bounceTime) ) {
18348                    that._execEvent('scrollEnd');
18349                }
18350
18351                return;
18352            }
18353
18354            now = ( now - startTime ) / duration;
18355            easing = easingFn(now);
18356            newX = ( destX - startX ) * easing + startX;
18357            newY = ( destY - startY ) * easing + startY;
18358            that._translate(newX, newY);
18359
18360            if ( that.isAnimating ) {
18361                rAF(step);
18362            }
18363        }
18364
18365        this.isAnimating = true;
18366        step();
18367    },
18368    handleEvent: function (e) {
18369        switch ( e.type ) {
18370            case 'touchstart':
18371            case 'pointerdown':
18372            case 'MSPointerDown':
18373            case 'mousedown':
18374                this._start(e);
18375                break;
18376            case 'touchmove':
18377            case 'pointermove':
18378            case 'MSPointerMove':
18379            case 'mousemove':
18380                this._move(e);
18381                break;
18382            case 'touchend':
18383            case 'pointerup':
18384            case 'MSPointerUp':
18385            case 'mouseup':
18386            case 'touchcancel':
18387            case 'pointercancel':
18388            case 'MSPointerCancel':
18389            case 'mousecancel':
18390                this._end(e);
18391                break;
18392            case 'orientationchange':
18393            case 'resize':
18394                this._resize();
18395                break;
18396            case 'transitionend':
18397            case 'webkitTransitionEnd':
18398            case 'oTransitionEnd':
18399            case 'MSTransitionEnd':
18400                this._transitionEnd(e);
18401                break;
18402            case 'wheel':
18403            case 'DOMMouseScroll':
18404            case 'mousewheel':
18405                this._wheel(e);
18406                break;
18407            case 'keydown':
18408                this._key(e);
18409                break;
18410            case 'click':
18411                if ( this.enabled && !e._constructed ) {
18412                    e.preventDefault();
18413                    e.stopPropagation();
18414                }
18415                break;
18416        }
18417    }
18418};
18419function createDefaultScrollbar (direction, interactive, type) {
18420    var scrollbar = document.createElement('div'),
18421        indicator = document.createElement('div');
18422
18423    if ( type === true ) {
18424        scrollbar.style.cssText = 'position:absolute;z-index:9999';
18425        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';
18426    }
18427
18428    indicator.className = 'iScrollIndicator';
18429
18430    if ( direction == 'h' ) {
18431        if ( type === true ) {
18432            scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
18433            indicator.style.height = '100%';
18434        }
18435        scrollbar.className = 'iScrollHorizontalScrollbar';
18436    } else {
18437        if ( type === true ) {
18438            scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
18439            indicator.style.width = '100%';
18440        }
18441        scrollbar.className = 'iScrollVerticalScrollbar';
18442    }
18443
18444    scrollbar.style.cssText += ';overflow:hidden';
18445
18446    if ( !interactive ) {
18447        scrollbar.style.pointerEvents = 'none';
18448    }
18449
18450    scrollbar.appendChild(indicator);
18451
18452    return scrollbar;
18453}
18454
18455function Indicator (scroller, options) {
18456    this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
18457    this.wrapperStyle = this.wrapper.style;
18458    this.indicator = this.wrapper.children[0];
18459    this.indicatorStyle = this.indicator.style;
18460    this.scroller = scroller;
18461
18462    this.options = {
18463        listenX: true,
18464        listenY: true,
18465        interactive: false,
18466        resize: true,
18467        defaultScrollbars: false,
18468        shrink: false,
18469        fade: false,
18470        speedRatioX: 0,
18471        speedRatioY: 0
18472    };
18473
18474    for ( var i in options ) {
18475        this.options[i] = options[i];
18476    }
18477
18478    this.sizeRatioX = 1;
18479    this.sizeRatioY = 1;
18480    this.maxPosX = 0;
18481    this.maxPosY = 0;
18482
18483    if ( this.options.interactive ) {
18484        if ( !this.options.disableTouch ) {
18485            utils.addEvent(this.indicator, 'touchstart', this);
18486            utils.addEvent(window, 'touchend', this);
18487        }
18488        if ( !this.options.disablePointer ) {
18489            utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
18490            utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
18491        }
18492        if ( !this.options.disableMouse ) {
18493            utils.addEvent(this.indicator, 'mousedown', this);
18494            utils.addEvent(window, 'mouseup', this);
18495        }
18496    }
18497
18498    if ( this.options.fade ) {
18499        this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
18500        var durationProp = utils.style.transitionDuration;
18501        if(!durationProp) {
18502            return;
18503        }
18504        this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
18505        // remove 0.0001ms
18506        var self = this;
18507        if(utils.isBadAndroid) {
18508            rAF(function() {
18509                if(self.wrapperStyle[durationProp] === '0.0001ms') {
18510                    self.wrapperStyle[durationProp] = '0s';
18511                }
18512            });
18513        }
18514        this.wrapperStyle.opacity = '0';
18515    }
18516}
18517
18518Indicator.prototype = {
18519    handleEvent: function (e) {
18520        switch ( e.type ) {
18521            case 'touchstart':
18522            case 'pointerdown':
18523            case 'MSPointerDown':
18524            case 'mousedown':
18525                this._start(e);
18526                break;
18527            case 'touchmove':
18528            case 'pointermove':
18529            case 'MSPointerMove':
18530            case 'mousemove':
18531                this._move(e);
18532                break;
18533            case 'touchend':
18534            case 'pointerup':
18535            case 'MSPointerUp':
18536            case 'mouseup':
18537            case 'touchcancel':
18538            case 'pointercancel':
18539            case 'MSPointerCancel':
18540            case 'mousecancel':
18541                this._end(e);
18542                break;
18543        }
18544    },
18545
18546    destroy: function () {
18547        if ( this.options.fadeScrollbars ) {
18548            clearTimeout(this.fadeTimeout);
18549            this.fadeTimeout = null;
18550        }
18551        if ( this.options.interactive ) {
18552            utils.removeEvent(this.indicator, 'touchstart', this);
18553            utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
18554            utils.removeEvent(this.indicator, 'mousedown', this);
18555
18556            utils.removeEvent(window, 'touchmove', this);
18557            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
18558            utils.removeEvent(window, 'mousemove', this);
18559
18560            utils.removeEvent(window, 'touchend', this);
18561            utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
18562            utils.removeEvent(window, 'mouseup', this);
18563        }
18564
18565        if ( this.options.defaultScrollbars ) {
18566            this.wrapper.parentNode.removeChild(this.wrapper);
18567        }
18568    },
18569
18570    _start: function (e) {
18571        var point = e.touches ? e.touches[0] : e;
18572
18573        e.preventDefault();
18574        e.stopPropagation();
18575
18576        this.transitionTime();
18577
18578        this.initiated = true;
18579        this.moved = false;
vendor: 9,615 bytes, lines 18580-18838
18580        this.lastPointX = point.pageX;
18581        this.lastPointY = point.pageY;
18582
18583        this.startTime  = utils.getTime();
18584
18585        if ( !this.options.disableTouch ) {
18586            utils.addEvent(window, 'touchmove', this);
18587        }
18588        if ( !this.options.disablePointer ) {
18589            utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
18590        }
18591        if ( !this.options.disableMouse ) {
18592            utils.addEvent(window, 'mousemove', this);
18593        }
18594
18595        this.scroller._execEvent('beforeScrollStart');
18596    },
18597
18598    _move: function (e) {
18599        var point = e.touches ? e.touches[0] : e,
18600            deltaX, deltaY,
18601            newX, newY,
18602            timestamp = utils.getTime();
18603
18604        if ( !this.moved ) {
18605            this.scroller._execEvent('scrollStart');
18606        }
18607
18608        this.moved = true;
18609
18610        deltaX = point.pageX - this.lastPointX;
18611        this.lastPointX = point.pageX;
18612
18613        deltaY = point.pageY - this.lastPointY;
18614        this.lastPointY = point.pageY;
18615
18616        newX = this.x + deltaX;
18617        newY = this.y + deltaY;
18618
18619        this._pos(newX, newY);
18620
18621// INSERT POINT: indicator._move
18622
18623        e.preventDefault();
18624        e.stopPropagation();
18625    },
18626
18627    _end: function (e) {
18628        if ( !this.initiated ) {
18629            return;
18630        }
18631
18632        this.initiated = false;
18633
18634        e.preventDefault();
18635        e.stopPropagation();
18636
18637        utils.removeEvent(window, 'touchmove', this);
18638        utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
18639        utils.removeEvent(window, 'mousemove', this);
18640
18641        if ( this.scroller.options.snap ) {
18642            var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
18643
18644            var time = this.options.snapSpeed || Math.max(
18645                    Math.max(
18646                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
18647                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
18648                    ), 300);
18649
18650            if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
18651                this.scroller.directionX = 0;
18652                this.scroller.directionY = 0;
18653                this.scroller.currentPage = snap;
18654                this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
18655            }
18656        }
18657
18658        if ( this.moved ) {
18659            this.scroller._execEvent('scrollEnd');
18660        }
18661    },
18662
18663    transitionTime: function (time) {
18664        time = time || 0;
18665        var durationProp = utils.style.transitionDuration;
18666        if(!durationProp) {
18667            return;
18668        }
18669
18670        this.indicatorStyle[durationProp] = time + 'ms';
18671
18672        if ( !time && utils.isBadAndroid ) {
18673            this.indicatorStyle[durationProp] = '0.0001ms';
18674            // remove 0.0001ms
18675            var self = this;
18676            rAF(function() {
18677                if(self.indicatorStyle[durationProp] === '0.0001ms') {
18678                    self.indicatorStyle[durationProp] = '0s';
18679                }
18680            });
18681        }
18682    },
18683
18684    transitionTimingFunction: function (easing) {
18685        this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
18686    },
18687
18688    refresh: function () {
18689        this.transitionTime();
18690
18691        if ( this.options.listenX && !this.options.listenY ) {
18692            this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
18693        } else if ( this.options.listenY && !this.options.listenX ) {
18694            this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
18695        } else {
18696            this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
18697        }
18698
18699        if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
18700            utils.addClass(this.wrapper, 'iScrollBothScrollbars');
18701            utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
18702
18703            if ( this.options.defaultScrollbars && this.options.customStyle ) {
18704                if ( this.options.listenX ) {
18705                    this.wrapper.style.right = '8px';
18706                } else {
18707                    this.wrapper.style.bottom = '8px';
18708                }
18709            }
18710        } else {
18711            utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
18712            utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
18713
18714            if ( this.options.defaultScrollbars && this.options.customStyle ) {
18715                if ( this.options.listenX ) {
18716                    this.wrapper.style.right = '2px';
18717                } else {
18718                    this.wrapper.style.bottom = '2px';
18719                }
18720            }
18721        }
18722
18723        var r = this.wrapper.offsetHeight;  // force refresh
18724
18725        if ( this.options.listenX ) {
18726            this.wrapperWidth = this.wrapper.clientWidth;
18727            if ( this.options.resize ) {
18728                this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
18729                this.indicatorStyle.width = this.indicatorWidth + 'px';
18730            } else {
18731                this.indicatorWidth = this.indicator.clientWidth;
18732            }
18733
18734            this.maxPosX = this.wrapperWidth - this.indicatorWidth;
18735
18736            if ( this.options.shrink == 'clip' ) {
18737                this.minBoundaryX = -this.indicatorWidth + 8;
18738                this.maxBoundaryX = this.wrapperWidth - 8;
18739            } else {
18740                this.minBoundaryX = 0;
18741                this.maxBoundaryX = this.maxPosX;
18742            }
18743
18744            this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
18745        }
18746
18747        if ( this.options.listenY ) {
18748            this.wrapperHeight = this.wrapper.clientHeight;
18749            if ( this.options.resize ) {
18750                this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
18751                this.indicatorStyle.height = this.indicatorHeight + 'px';
18752            } else {
18753                this.indicatorHeight = this.indicator.clientHeight;
18754            }
18755
18756            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
18757
18758            if ( this.options.shrink == 'clip' ) {
18759                this.minBoundaryY = -this.indicatorHeight + 8;
18760                this.maxBoundaryY = this.wrapperHeight - 8;
18761            } else {
18762                this.minBoundaryY = 0;
18763                this.maxBoundaryY = this.maxPosY;
18764            }
18765
18766            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
18767            this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
18768        }
18769
18770        this.updatePosition();
18771    },
18772
18773    updatePosition: function () {
18774        var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
18775            y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
18776
18777        if ( !this.options.ignoreBoundaries ) {
18778            if ( x < this.minBoundaryX ) {
18779                if ( this.options.shrink == 'scale' ) {
18780                    this.width = Math.max(this.indicatorWidth + x, 8);
18781                    this.indicatorStyle.width = this.width + 'px';
18782                }
18783                x = this.minBoundaryX;
18784            } else if ( x > this.maxBoundaryX ) {
18785                if ( this.options.shrink == 'scale' ) {
18786                    this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
18787                    this.indicatorStyle.width = this.width + 'px';
18788                    x = this.maxPosX + this.indicatorWidth - this.width;
18789                } else {
18790                    x = this.maxBoundaryX;
18791                }
18792            } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
18793                this.width = this.indicatorWidth;
18794                this.indicatorStyle.width = this.width + 'px';
18795            }
18796
18797            if ( y < this.minBoundaryY ) {
18798                if ( this.options.shrink == 'scale' ) {
18799                    this.height = Math.max(this.indicatorHeight + y * 3, 8);
18800                    this.indicatorStyle.height = this.height + 'px';
18801                }
18802                y = this.minBoundaryY;
18803            } else if ( y > this.maxBoundaryY ) {
18804                if ( this.options.shrink == 'scale' ) {
18805                    this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
18806                    this.indicatorStyle.height = this.height + 'px';
18807                    y = this.maxPosY + this.indicatorHeight - this.height;
18808                } else {
18809                    y = this.maxBoundaryY;
18810                }
18811            } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
18812                this.height = this.indicatorHeight;
18813                this.indicatorStyle.height = this.height + 'px';
18814            }
18815        }
18816
18817        this.x = x;
18818        this.y = y;
18819
18820        if ( this.scroller.options.useTransform ) {
18821            this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
18822        } else {
18823            this.indicatorStyle.left = x + 'px';
18824            this.indicatorStyle.top = y + 'px';
18825        }
18826    },
18827
18828    _pos: function (x, y) {
18829        if ( x < 0 ) {
18830            x = 0;
18831        } else if ( x > this.maxPosX ) {
18832            x = this.maxPosX;
18833        }
18834
18835        if ( y < 0 ) {
18836            y = 0;
18837        } else if ( y > this.maxPosY ) {
18838            y = this.maxPosY;
18839        }
18840
18841        x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
18842        y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
18843
18844        this.scroller.scrollTo(x, y);
18845    },
18846
18847    fade: function (val, hold) {
18848        if ( hold && !this.visible ) {
18849            return;
18850        }
18851
18852        clearTimeout(this.fadeTimeout);
18853        this.fadeTimeout = null;
18854
18855        var time = val ? 250 : 500,
18856            delay = val ? 0 : 300;
18857
18858        val = val ? '1' : '0';
18859
18860        this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
18861
18862        this.fadeTimeout = setTimeout((function (val) {
18863            this.wrapperStyle.opacity = val;
18864            this.visible = +val;
18865        }).bind(this, val), delay);
18866    }
18867};
18868
18869IScroll.utils = utils;
18870
18871if ( typeof module != 'undefined' && module.exports ) {
18872    module.exports = IScroll;
18873} else if ( typeof define == 'function' && define.amd ) {
18874        define( function () { return IScroll; } );
18875} else {
18876    window.IScroll = IScroll;
18877}
18878
18879})(window, document, Math);
18880/*!
18881 * fullPage 2.9.4
18882 * https://github.com/alvarotrigo/fullPage.js
18883 * @license MIT licensed
18884 *
18885 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
18886 */
18887(function(global, factory) {
18888    'use strict';
18889    if (typeof define === 'function' && define.amd) {
18890        define(['jquery'], function($) {
18891          return factory($, global, global.document, global.Math);
18892        });
18893    } else if (typeof exports === "object" && exports) {
18894        module.exports = factory(require('jquery'), global, global.document, global.Math);
18895    } else {
18896        factory(jQuery, global, global.document, global.Math);
18897    }
18898})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
18899    'use strict';
18900
18901    // keeping central set of classnames and selectors
18902    var WRAPPER =               'fullpage-wrapper';
18903    var WRAPPER_SEL =           '.' + WRAPPER;
18904
18905    // slimscroll
18906    var SCROLLABLE =            'fp-scrollable';
18907    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
18908
18909    // util
18910    var RESPONSIVE =            'fp-responsive';
18911    var NO_TRANSITION =         'fp-notransition';
18912    var DESTROYED =             'fp-destroyed';
18913    var ENABLED =               'fp-enabled';
18914    var VIEWING_PREFIX =        'fp-viewing';
18915    var ACTIVE =                'active';
18916    var ACTIVE_SEL =            '.' + ACTIVE;
18917    var COMPLETELY =            'fp-completely';
18918    var COMPLETELY_SEL =        '.' + COMPLETELY;
18919
18920    // section
18921    var SECTION_DEFAULT_SEL =   '.section';
18922    var SECTION =               'fp-section';
18923    var SECTION_SEL =           '.' + SECTION;
18924    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
18925    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
18926    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
18927    var TABLE_CELL =            'fp-tableCell';
18928    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
18929    var AUTO_HEIGHT =           'fp-auto-height';
18930    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
18931    var NORMAL_SCROLL =         'fp-normal-scroll';
18932    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
18933
18934    // section nav
18935    var SECTION_NAV =           'fp-nav';
18936    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
18937    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
18938    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
18939    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
18940
18941    // slide
18942    var SLIDE_DEFAULT_SEL =     '.slide';
18943    var SLIDE =                 'fp-slide';
18944    var SLIDE_SEL =             '.' + SLIDE;
18945    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
18946    var SLIDES_WRAPPER =        'fp-slides';
18947    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
18948    var SLIDES_CONTAINER =      'fp-slidesContainer';
18949    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
18950    var TABLE =                 'fp-table';
18951
18952    // slide nav
18953    var SLIDES_NAV =            'fp-slidesNav';
18954    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
18955    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
18956    var SLIDES_ARROW =          'fp-controlArrow';
18957    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
18958    var SLIDES_PREV =           'fp-prev';
18959    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
18960    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
18961    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
18962    var SLIDES_NEXT =           'fp-next';
18963    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
18964    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
18965    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
18966
18967    var $window = $(window);
18968    var $document = $(document);
18969
18970    // Default options for iScroll.js used when using scrollOverflow
18971    var iscrollOptions = {
18972        scrollbars: true,
18973        mouseWheel: true,
18974        hideScrollbars: false,
18975        fadeScrollbars: false,
18976        disableMouse: true,
18977        interactiveScrollbars: true,
18978        bounce: false,
18979    };
18980
18981    $.fn.fullpage = function(options) {
18982        //only once my friend!
18983        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
18984
18985        // common jQuery objects
18986        var $htmlBody = $('html, body');
18987        var $body = $('body');
18988
18989        var FP = $.fn.fullpage;
18990
18991        // Creating some defaults, extending them with any options that were provided
18992        options = $.extend({
18993            //navigation
18994            menu: false,
18995            anchors:[],
18996            lockAnchors: false,
18997            navigation: false,
18998            navigationPosition: 'right',
18999            navigationTooltips: [],
19000            showActiveTooltip: false,
19001            slidesNavigation: false,
19002            slidesNavPosition: 'bottom',
19003            scrollBar: false,
19004            hybrid: false,
19005
19006            //scrolling
19007            css3: true,
19008            scrollingSpeed: 700,
19009            autoScrolling: true,
19010            fitToSection: true,
19011            fitToSectionDelay: 1000,
19012            easing: 'easeInOutCubic',
19013            easingcss3: 'ease',
19014            loopBottom: false,
19015            loopTop: false,
19016            loopHorizontal: true,
19017            continuousVertical: false,
19018            continuousHorizontal: false,
19019            scrollHorizontally: false,
19020            interlockedSlides: false,
19021            dragAndMove: false,
19022            offsetSections: false,
19023            resetSliders: false,
19024            fadingEffect: false,
19025            normalScrollElements: null,
19026            scrollOverflow: false,
19027            scrollOverflowReset: false,
19028            scrollOverflowHandler: iscrollHandler,
19029            scrollOverflowOptions: null,
19030            touchSensitivity: 5,
19031            normalScrollElementTouchThreshold: 5,
19032            bigSectionsDestination: null,
19033
19034            //Accessibility
19035            keyboardScrolling: true,
19036            animateAnchor: true,
19037            recordHistory: true,
19038
19039            //design
19040            controlArrows: true,
19041            controlArrowColor: '#fff',
19042            verticalCentered: true,
19043            sectionsColor : [],
19044            paddingTop: 0,
19045            paddingBottom: 0,
19046            fixedElements: null,
19047            responsive: 0, //backwards compabitility with responsiveWiddth
19048            responsiveWidth: 0,
19049            responsiveHeight: 0,
19050            responsiveSlides: false,
19051            parallax: false,
19052            parallaxOptions: {
19053                type: 'reveal',
19054                percentage: 62,
19055                property: 'translate'
19056            },
19057
19058            //Custom selectors
19059            sectionSelector: SECTION_DEFAULT_SEL,
19060            slideSelector: SLIDE_DEFAULT_SEL,
19061
19062            //events
19063            afterLoad: null,
19064            onLeave: null,
19065            afterRender: null,
19066            afterResize: null,
19067            afterReBuild: null,
19068            afterSlideLoad: null,
19069            onSlideLeave: null,
19070            afterResponsive: null,
19071
19072            lazyLoading: true
19073        }, options);
19074
19075        //flag to avoid very fast sliding for landscape sliders
19076        var slideMoving = false;
19077
19078        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
19079        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
19080        var container = $(this);
19081        var windowsHeight = $window.height();
19082        var isResizing = false;
19083        var isWindowFocused = true;
19084        var lastScrolledDestiny;
19085        var lastScrolledSlide;
19086        var canScroll = true;
19087        var scrollings = [];
19088        var controlPressed;
19089        var startingSection;
19090        var isScrollAllowed = {};
19091        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
19092        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
19093        var MSPointer = getMSPointer();
19094        var events = {
19095            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
19096            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
19097        };
19098
19099        //timeouts
19100        var resizeId;
19101        var afterSectionLoadsId;
19102        var afterSlideLoadsId;
19103        var scrollId;
19104        var scrollId2;
19105        var keydownId;
19106        var originals = $.extend(true, {}, options); //deep copy
19107
19108        //Uncode addition
19109        var $masthead = $('#masthead');
19110        var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
19111        var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
19112        var bodyBorder = UNCODE.bodyBorder;
19113        var adminBarHeight = UNCODE.adminBarHeight;
19114
19115        displayWarnings();
19116
19117        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
19118        iscrollOptions.click = isTouch; // see #2035
19119
19120        //extending iScroll options with the user custom ones
19121        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
19122
19123        //easeInOutCubic animation included in the plugin
19124        $.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;}});
19125
19126        /**
19127        * Sets the autoScroll option.
19128        * It changes the scroll bar visibility and the history of the site as a result.
19129        */
19130        function setAutoScrolling(value, type){
19131            //removing the transformation
19132            if(!value){
19133                silentScroll(0);
19134            }
19135
19136            setVariableState('autoScrolling', value, type);
19137
19138            var element = $(SECTION_ACTIVE_SEL);
19139
19140            if(options.autoScrolling && !options.scrollBar){
19141                $htmlBody.css({
19142                    'overflow' : 'hidden !important',
19143                    'height' : '100%'
19144                });
19145
19146                //Uncode addition
19147                //setRecordHistory(originals.recordHistory, 'internal');
19148
19149                //for IE touch devices
19150                container.css({
19151                    '-ms-touch-action': 'none',
19152                    'touch-action': 'none'
19153                });
19154
19155                if(element.length){
19156                    //moving the container up
19157                    silentScroll(element.position().top);
19158                }
19159
19160            }else{
19161                $htmlBody.css({
19162                    'overflow' : 'visible !important',
19163                    'height' : 'initial'
19164                });
19165
19166                //Uncode addition
19167                //setRecordHistory(false, 'internal');
19168
19169                //for IE touch devices
19170                container.css({
19171                    '-ms-touch-action': '',
19172                    'touch-action': ''
19173                });
19174
19175                //scrolling the page to the section with no animation
19176                if (element.length) {
19177                    $htmlBody.scrollTop(element.position().top);
19178                }
19179            }
19180        }
19181
19182        /**
19183        * Defines wheter to record the history for each hash change in the URL.
19184        */
19185        function setRecordHistory(value, type){
19186            setVariableState('recordHistory', value, type);
19187        }
19188
19189        /**
19190        * Defines the scrolling speed
19191        */
19192        function setScrollingSpeed(value, type){
19193            setVariableState('scrollingSpeed', value, type);
19194        }
19195
19196        /**
19197        * Sets fitToSection
19198        */
19199        function setFitToSection(value, type){
19200            setVariableState('fitToSection', value, type);
19201        }
19202
19203        /**
19204        * Sets lockAnchors
19205        */
19206        function setLockAnchors(value){
19207            options.lockAnchors = value;
19208        }
19209
19210        /**
19211        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
19212        */
19213        function setMouseWheelScrolling(value){
19214            if(value){
19215                addMouseWheelHandler();
19216                addMiddleWheelHandler();
19217            }else{
19218                removeMouseWheelHandler();
19219                removeMiddleWheelHandler();
19220            }
19221        }
19222
19223        /**
19224        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
19225        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
19226        *
19227        * @param directions string containing the direction or directions separated by comma.
19228        */
19229        function setAllowScrolling(value, directions){
19230            if(typeof directions !== 'undefined'){
19231                directions = directions.replace(/ /g,'').split(',');
19232
19233                $.each(directions, function (index, direction){
19234                    setIsScrollAllowed(value, direction, 'm');
19235                });
19236            }
19237            else if(value){
19238                setMouseWheelScrolling(true);
19239                addTouchHandler();
19240            }else{
19241                setMouseWheelScrolling(false);
19242                removeTouchHandler();
19243            }
19244        }
19245
19246        /**
19247        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
19248        */
19249        function setKeyboardScrolling(value, directions){
19250            if(typeof directions !== 'undefined'){
19251                directions = directions.replace(/ /g,'').split(',');
19252
19253                $.each(directions, function (index, direction){
19254                    setIsScrollAllowed(value, direction, 'k');
19255                });
19256            }else{
19257                options.keyboardScrolling = value;
19258            }
19259        }
19260
19261        /**
19262        * Moves the page up one section.
19263        */
19264        function moveSectionUp(){
19265            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
19266
19267            //looping to the bottom if there's no more sections above
19268            if (!prev.length && (options.loopTop || options.continuousVertical)) {
19269                prev = $(SECTION_SEL).last();
19270            }
19271
19272            if (prev.length) {
19273                scrollPage(prev, null, true);
19274            }
19275        }
19276
19277        /**
19278        * Moves the page down one section.
19279        */
19280        function moveSectionDown(){
19281            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
19282
19283            //looping to the top if there's no more sections below
19284            if(!next.length &&
19285                (options.loopBottom || options.continuousVertical)){
19286                next = $(SECTION_SEL).first();
19287            }
19288
19289            if(next.length){
19290                scrollPage(next, null, false);
19291            }
19292        }
19293
19294        /**
19295        * Moves the page to the given section and slide with no animation.
19296        * Anchors or index positions can be used as params.
19297        */
19298        function silentMoveTo(sectionAnchor, slideAnchor){
19299            setScrollingSpeed (0, 'internal');
19300            moveTo(sectionAnchor, slideAnchor);
19301            setScrollingSpeed (originals.scrollingSpeed, 'internal');
19302        }
19303
19304        /**
19305        * Moves the page to the given section and slide.
19306        * Anchors or index positions can be used as params.
19307        */
19308        function moveTo(sectionAnchor, slideAnchor){
19309            var destiny = getSectionByAnchor(sectionAnchor);
19310
19311            if (typeof slideAnchor !== 'undefined'){
19312                scrollPageAndSlide(sectionAnchor, slideAnchor);
19313            }else if(destiny.length > 0){
19314                scrollPage(destiny);
19315            }
19316        }
19317
19318        /**
19319        * Slides right the slider of the active section.
19320        * Optional `section` param.
19321        */
19322        function moveSlideRight(section){
19323            moveSlide('right', section);
19324        }
19325
19326        /**
19327        * Slides left the slider of the active section.
19328        * Optional `section` param.
19329        */
19330        function moveSlideLeft(section){
19331            moveSlide('left', section);
19332        }
19333
19334        /**
19335         * When resizing is finished, we adjust the slides sizes and positions
19336         */
19337        function reBuild(resizing){
19338            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
19339
19340            isResizing = true;
19341
19342            windowsHeight = $window.height();  //updating global var
19343
19344            $(SECTION_SEL).each(function(){
19345                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
19346                var slides = $(this).find(SLIDE_SEL);
19347
19348                //adjusting the height of the table-cell for IE and Firefox
19349                if(options.verticalCentered){
19350                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
19351                }
19352
19353                $(this).css('height', windowsHeight + 'px');
19354
19355                //resizing the scrolling divs
19356                if(options.scrollOverflow){
19357                    if(slides.length){
19358                        slides.each(function(){
19359                            createScrollBar($(this));
19360                        });
19361                    }else{
19362                        createScrollBar($(this));
19363                    }
19364                }
19365
19366                //adjusting the position fo the FULL WIDTH slides...
19367                if (slides.length > 1) {
19368                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
19369                }
19370            });
19371
19372            var activeSection = $(SECTION_ACTIVE_SEL);
19373            var sectionIndex = activeSection.index(SECTION_SEL);
19374
19375            //isn't it the first section?
19376            if(sectionIndex){
19377                //adjusting the position for the current section
19378                silentMoveTo(sectionIndex + 1);
19379            }
19380
19381            isResizing = false;
19382            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
19383            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
19384        }
19385
19386        /**
19387        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
19388        * are smaller than the set limit values.
19389        */
19390        function setResponsive(active){
19391            var isResponsive = $body.hasClass(RESPONSIVE);
19392
19393            if(active){
19394                if(!isResponsive){
19395                    setAutoScrolling(false, 'internal');
19396                    setFitToSection(false, 'internal');
19397                    $(SECTION_NAV_SEL).hide();
19398                    $body.addClass(RESPONSIVE);
19399                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
19400                }
19401            }
19402            else if(isResponsive){
19403                setAutoScrolling(originals.autoScrolling, 'internal');
19404                setFitToSection(originals.autoScrolling, 'internal');
19405                $(SECTION_NAV_SEL).show();
19406                $body.removeClass(RESPONSIVE);
19407                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
19408            }
19409        }
19410
19411        if($(this).length){
19412            //public functions
19413            FP.setAutoScrolling = setAutoScrolling;
19414            FP.setRecordHistory = setRecordHistory;
19415            FP.setScrollingSpeed = setScrollingSpeed;
19416            FP.setFitToSection = setFitToSection;
19417            FP.setLockAnchors = setLockAnchors;
19418            FP.setMouseWheelScrolling = setMouseWheelScrolling;
19419            FP.setAllowScrolling = setAllowScrolling;
19420            FP.setKeyboardScrolling = setKeyboardScrolling;
19421            FP.moveSectionUp = moveSectionUp;
19422            FP.moveSectionDown = moveSectionDown;
19423            FP.silentMoveTo = silentMoveTo;
19424            FP.moveTo = moveTo;
19425            FP.moveSlideRight = moveSlideRight;
19426            FP.moveSlideLeft = moveSlideLeft;
19427            FP.fitToSection = fitToSection;
19428            FP.reBuild = reBuild;
19429            FP.setResponsive = setResponsive;
19430            FP.destroy = destroy;
19431
19432            init();
19433
19434            bindEvents();
19435        }
19436
19437        function init(){
19438            //if css3 is not supported, it will use jQuery animations
19439            if(options.css3){
19440                options.css3 = support3d();
19441            }
19442
19443            options.scrollBar = options.scrollBar || options.hybrid;
19444
19445            setOptionsFromDOM();
19446            prepareDom();
19447            setAllowScrolling(true);
19448            setAutoScrolling(options.autoScrolling, 'internal');
19449            responsive();
19450
19451            //setting the class for the body element
19452            setBodyClass();
19453
19454            //Uncode addition
19455            // if(document.readyState === 'complete'){
19456            //     scrollToAnchor();
19457            // }
19458            // $window.on('load', scrollToAnchor);
19459        }
19460
19461        function bindEvents(){
19462            $window
19463                //when scrolling...
19464                //.on('scroll', scrollHandler)
19465
19466                //detecting any change on the URL to scroll to the given anchor link
19467                //(a way to detect back history button as we play with the hashes on the URL)
19468                .on('hashchange', hashChangeHandler)
19469
19470                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
19471                .blur(blurHandler)
19472
19473                //when resizing the site, we adjust the heights of the sections, slimScroll...
19474                .resize(resizeHandler);
19475
19476            $document
19477                //Sliding with arrow keys, both, vertical and horizontal
19478                .keydown(keydownHandler)
19479
19480                //to prevent scrolling while zooming
19481                .keyup(keyUpHandler)
19482
19483                //Scrolls to the section when clicking the navigation bullet
19484                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
19485
19486                //Scrolls the slider to the given slide destination for the given section
19487                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
19488
19489                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
19490
19491            //Scrolling horizontally when clicking on the slider controls.
19492            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
19493
19494            /**
19495            * Applying normalScroll elements.
19496            * Ignoring the scrolls over the specified selectors.
19497            */
19498            if(options.normalScrollElements){
19499                $document.on('mouseenter', options.normalScrollElements, function () {
19500                    setMouseWheelScrolling(false);
19501                });
19502
19503                $document.on('mouseleave', options.normalScrollElements, function(){
19504                    setMouseWheelScrolling(true);
19505                });
19506            }
19507        }
19508
19509        /**
19510        * Setting options from DOM elements if they are not provided.
19511        */
19512        function setOptionsFromDOM(){
19513            var sections = container.find(options.sectionSelector);
19514
19515            //no anchors option? Checking for them in the DOM attributes
19516            if(!options.anchors.length){
19517                options.anchors = sections.filter('[data-anchor]').map(function(){
19518                    return $(this).data('anchor').toString();
19519                }).get();
19520            }
19521
19522            //no tooltips option? Checking for them in the DOM attributes
19523            if(!options.navigationTooltips.length){
19524                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
19525                    return $(this).data('tooltip').toString();
19526                }).get();
19527            }
19528        }
19529
19530        /**
19531        * Works over the DOM structure to set it up for the current fullpage options.
19532        */
19533        function prepareDom(){
19534            container.css({
19535                'height': '100%',
19536                'position': 'relative'
19537            });
19538
19539            //adding a class to recognize the container internally in the code
19540            container.addClass(WRAPPER);
19541            $('html').addClass(ENABLED);
19542
19543            windowsHeight = $window.height();
19544
19545            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
19546
19547            addInternalSelectors();
19548
19549             //styling the sections / slides / menu
19550            $(SECTION_SEL).each(function(index){
19551                var section = $(this);
19552                var slides = section.find(SLIDE_SEL);
19553                var numSlides = slides.length;
19554
19555                styleSection(section, index);
19556                styleMenu(section, index);
19557
19558                // if there's any slide
19559                if (numSlides > 0) {
19560                    styleSlides(section, slides, numSlides);
19561                }else{
19562                    if(options.verticalCentered){
19563                        addTableClass(section);
19564                    }
19565                }
19566            });
19567
19568            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
19569            if(options.fixedElements && options.css3){
19570                $(options.fixedElements).appendTo($body);
19571            }
19572
19573            //vertical centered of the navigation + active bullet
19574            if(options.navigation){
19575                addVerticalNavigation();
19576            }
19577
19578            enableYoutubeAPI();
19579
19580            if(options.scrollOverflow){
19581                if(document.readyState === 'complete'){
19582                    createScrollBarHandler();
19583                }
19584                //after DOM and images are loaded
19585                $window.on('load', createScrollBarHandler);
19586            }else{
19587                afterRenderActions();
19588            }
19589        }
19590
19591        /**
19592        * Styles the horizontal slides for a section.
19593        */
19594        function styleSlides(section, slides, numSlides){
19595            var sliderWidth = numSlides * 100;
19596            var slideWidth = 100 / numSlides;
19597
19598            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
19599            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
19600
19601            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
19602
19603            if(numSlides > 1){
19604                if(options.controlArrows){
19605                    createSlideArrows(section);
19606                }
19607
19608                if(options.slidesNavigation){
19609                    addSlidesNavigation(section, numSlides);
19610                }
19611            }
19612
19613            slides.each(function(index) {
19614                $(this).css('width', slideWidth + '%');
19615
19616                if(options.verticalCentered){
19617                    addTableClass($(this));
19618                }
19619            });
19620
19621            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
19622
19623            //if the slide won't be an starting point, the default will be the first one
19624            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
19624ide by default.
19625            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
19626                silentLandscapeScroll(startingSlide, 'internal');
19627            }else{
19628                slides.eq(0).addClass(ACTIVE);
19629            }
19630        }
19631
19632        /**
19633        * Styling vertical sections
19634        */
19635        function styleSection(section, index){
19636            //if no active section is defined, the 1st one will be the default one
19637            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
19638                section.addClass(ACTIVE);
19639            }
19640            startingSection = $(SECTION_ACTIVE_SEL);
19641
19642            section.css('height', windowsHeight + 'px');
19643
19644            if(options.paddingTop){
19645                section.css('padding-top', options.paddingTop);
19646            }
19647
19648            if(options.paddingBottom){
19649                section.css('padding-bottom', options.paddingBottom);
19650            }
19651
19652            if (typeof options.sectionsColor[index] !==  'undefined') {
19653                section.css('background-color', options.sectionsColor[index]);
19654            }
19655
19656            if (typeof options.anchors[index] !== 'undefined') {
19657                section.attr('data-anchor', options.anchors[index]);
19658            }
19659        }
19660
19661        /**
19662        * Sets the data-anchor attributes to the menu elements and activates the current one.
19663        */
19664        function styleMenu(section, index){
19665            if (typeof options.anchors[index] !== 'undefined') {
19666                //activating the menu / nav element on load
19667                if(section.hasClass(ACTIVE)){
19668                    activateMenuAndNav(options.anchors[index], index);
19669                }
19670            }
19671
19672            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
19673            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
19674                $(options.menu).appendTo($body);
19675            }
19676        }
19677
19678        /**
19679        * Adds internal classes to be able to provide customizable selectors
19680        * keeping the link with the style sheet.
19681        */
19682        function addInternalSelectors(){
19683            container.find(options.sectionSelector).addClass(SECTION);
19684            container.find(options.slideSelector).addClass(SLIDE);
19685        }
19686
19687        /**
19688        * Creates the control arrows for the given section
19689        */
19690        function createSlideArrows(section){
19691            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
19692
19693            if(options.controlArrowColor!='#fff'){
19694                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
19695                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
19696            }
19697
19698            if(!options.loopHorizontal){
19699                section.find(SLIDES_ARROW_PREV_SEL).hide();
19700            }
19701        }
19702
19703        /**
19704        * Creates a vertical navigation bar.
19705        */
19706        function addVerticalNavigation(){
19707            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
19708            var nav = $(SECTION_NAV_SEL);
19709
19710            nav.addClass(function() {
19711                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
19712            });
19713
19714            for (var i = 0; i < $(SECTION_SEL).length; i++) {
19715                var link = '';
19716                if (options.anchors.length) {
19717                    link = options.anchors[i];
19718                }
19719
19720                var li = '<li><a href="#' + link + '"><span></span></a>';
19721
19722                // Only add tooltip if needed (defined by user)
19723                var tooltip = options.navigationTooltips[i];
19724
19725                if (typeof tooltip !== 'undefined' && tooltip !== '') {
19726                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
19727                }
19728
19729                li += '</li>';
19730
19731                nav.find('ul').append(li);
19732            }
19733
19734            //centering it vertically
19735            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
19736
19737            //activating the current active section
19738            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
19739        }
19740
19741        /**
19742        * Creates the slim scroll scrollbar for the sections and slides inside them.
19743        */
19744        function createScrollBarHandler(){
19745            $(SECTION_SEL).each(function(){
19746                var slides = $(this).find(SLIDE_SEL);
19747
19748                if(slides.length){
19749                    slides.each(function(){
19750                        createScrollBar($(this));
19751                    });
19752                }else{
19753                    createScrollBar($(this));
19754                }
19755
19756            });
19757            afterRenderActions();
19758        }
19759
19760        /*
19761        * Enables the Youtube videos API so we can control their flow if necessary.
19762        */
19763        function enableYoutubeAPI(){
19764            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
19765                addURLParam($(this), 'enablejsapi=1');
19766            });
19767        }
19768
19769        /**
19770        * Adds a new parameter and its value to the `src` of a given element
19771        */
19772        function addURLParam(element, newParam){
19773            var originalSrc = element.attr('src');
19774            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
19775        }
19776
19777        /*
19778        * Returns the prefix sign to use for a new parameter in an existen URL.
19779        *
19780        * @return {String}  ? | &
19781        */
19782        function getUrlParamSign(url){
19783            return ( !/\?/.test( url ) ) ? '?' : '&';
19784        }
19785
19786        /**
19787        * Actions and callbacks to fire afterRender
19788        */
19789        function afterRenderActions(){
19790            var section = $(SECTION_ACTIVE_SEL);
19791
19792            section.addClass(COMPLETELY);
19793
19794            if(options.scrollOverflowHandler.afterRender){
19795                options.scrollOverflowHandler.afterRender(section);
19796            }
19797            lazyLoad(section);
19798            playMedia(section);
19799            options.scrollOverflowHandler.afterLoad();
19800            
19801            if(isDestinyTheStartingSection()){
19802                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
19803            }
19804
19805            $.isFunction( options.afterRender ) && options.afterRender.call(container);
19806        }
19807
19808        /**
19809        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
19810        */
19811        function isDestinyTheStartingSection(){
19812            var anchors =  window.location.hash.replace('#', '').split('/');
19813            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
19814    
19815            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
19816        }
19817
19818
19819        var isScrolling = false;
19820        var lastScroll = 0;
19821
19822        //when scrolling...
19823        function scrollHandler(){
19824            var currentSection;
19825
19826            if(!options.autoScrolling || options.scrollBar){
19827                var currentScroll = $window.scrollTop();
19828                var scrollDirection = getScrollDirection(currentScroll);
19829                var visibleSectionIndex = 0;
19830                var screen_mid = currentScroll + ($window.height() / 2.0);
19831                var isAtBottom = $body.height() - $window.height() === currentScroll;
19832                var sections =  document.querySelectorAll(SECTION_SEL);
19833
19834                //when using `auto-height` for a small last section it won't be centered in the viewport
19835                if(isAtBottom){
19836                    visibleSectionIndex = sections.length - 1;
19837                }
19838                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
19839                else if(!currentScroll){
19840                    visibleSectionIndex = 0;
19841                }
19842
19843                //taking the section which is showing more content in the viewport
19844                else{
19845                    for (var i = 0; i < sections.length; ++i) {
19846                        var section = sections[i];
19847
19848                        // Pick the the last section which passes the middle line of the screen.
19849                        if (section.offsetTop <= screen_mid)
19850                        {
19851                            visibleSectionIndex = i;
19852                        }
19853                    }
19854                }
19855
19856                if(isCompletelyInViewPort(scrollDirection)){
19857                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
19858                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
19859                    }
19860                }
19861
19862                //geting the last one, the current one on the screen
19863                currentSection = $(sections).eq(visibleSectionIndex);
19864
19865                //setting the visible section as active when manually scrolling
19866                //executing only once the first time we reach the section
19867                if(!currentSection.hasClass(ACTIVE)){
19868                    isScrolling = true;
19869                    var leavingSection = $(SECTION_ACTIVE_SEL);
19870                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
19871                    var yMovement = getYmovement(currentSection);
19872                    var anchorLink  = currentSection.data('anchor');
19873                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
19874                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
19875                    var slideIndex;
19876                    var slideAnchorLink;
19877
19878                    if(activeSlide.length){
19879                        slideAnchorLink = activeSlide.data('anchor');
19880                        slideIndex = activeSlide.index();
19881                    }
19882
19883                    if(canScroll){
19884                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
19885
19886                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
19887                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
19888
19889                        stopMedia(leavingSection);
19890                        lazyLoad(currentSection);
19891                        playMedia(currentSection);
19892
19893                        activateMenuAndNav(anchorLink, sectionIndex - 1);
19894
19895                        if(options.anchors.length){
19896                            //needed to enter in hashChange event when using the menu with anchor links
19897                            lastScrolledDestiny = anchorLink;
19898                        }
19899                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
19900                    }
19901
19902                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
19903                    clearTimeout(scrollId);
19904                    scrollId = setTimeout(function(){
19905                        isScrolling = false;
19906                    }, 100);
19907                }
19908
19909                if(options.fitToSection){
19910                    //for the auto adjust of the viewport to fit a whole section
19911                    clearTimeout(scrollId2);
19912
19913                    scrollId2 = setTimeout(function(){
19914                        //checking it again in case it changed during the delay
19915                        if(options.fitToSection){
19916                            fitToSection();
19917                        }
19918                    }, options.fitToSectionDelay);
19919                }
19920            }
19921        }
19922
19923        /**
19924        * Fits the site to the nearest active section
19925        */
19926        function fitToSection(){
19927            //checking fitToSection again in case it was set to false before the timeout delay
19928            if(canScroll){
19929                //allows to scroll to an active section and
19930                //if the section is already active, we prevent firing callbacks
19931                isResizing = true;
19932
19933                scrollPage($(SECTION_ACTIVE_SEL));
19934                isResizing = false;
19935            }
19936        }
19937
19938        /**
19939        * Determines whether the active section has seen in its whole or not.
19940        */
19941        function isCompletelyInViewPort(movement){
19942            var top = $(SECTION_ACTIVE_SEL).position().top;
19943            var bottom = top + $window.height();
19944
19945            if(movement == 'up'){
19946                return bottom >= ($window.scrollTop() + $window.height());
19947            }
19948            return top <= $window.scrollTop();
19949        }
19950
19951        /**
19952        * Gets the directon of the the scrolling fired by the scroll event.
19953        */
19954        function getScrollDirection(currentScroll){
19955            var direction = currentScroll > lastScroll ? 'down' : 'up';
19956
19957            lastScroll = currentScroll;
19958
19959            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
19960            previousDestTop = currentScroll;
19961
19962            return direction;
19963        }
19964
19965        /**
19966        * Determines the way of scrolling up or down:
19967        * by 'automatically' scrolling a section or by using the default and normal scrolling.
19968        */
19969        function scrolling(type, scrollable){
19970            if (!isScrollAllowed.m[type]){
19971                return;
19972            }
19973            var check = (type === 'down') ? 'bottom' : 'top';
19974            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
19975
19976            if(scrollable.length > 0 ){
19977                //is the scrollbar at the start/end of the scroll?
19978                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
19979                    scrollSection();
19980                }else{
19981                    return true;
19982                }
19983            }else{
19984                // moved up/down
19985                scrollSection();
19986            }
19987        }
19988
19989        /*
19990        * Preventing bouncing in iOS #2285
19991        */
19992        function preventBouncing(event){
19993            var e = event.originalEvent;
19994            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e)){
19995                //preventing the easing on iOS devices
19996                event.preventDefault();
19997            }
19998        }
19999
20000        var touchStartY = 0;
20001        var touchStartX = 0;
20002        var touchEndY = 0;
20003        var touchEndX = 0;
20004
20005        /* Detecting touch events
20006
20007        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
20008        * This way, the touchstart and the touch moves shows an small difference between them which is the
20009        * used one to determine the direction.
20010        */
20011        function touchMoveHandler(event){
20012            var e = event.originalEvent;
20013            var activeSection = $(e.target).closest(SECTION_SEL);
20014
20015            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
20016            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
20017
20018                if(options.autoScrolling){
20019                    //preventing the easing on iOS devices
20020                    event.preventDefault();
20021                }
20022
20023                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
20024                var touchEvents = getEventsPage(e);
20025
20026                touchEndY = touchEvents.y;
20027                touchEndX = touchEvents.x;
20028
20029                //if movement in the X axys is greater than in the Y and the currect section has slides...
20030                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
20031
20032                    //is the movement greater than the minimum resistance to scroll?
20033                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
20034                        if (touchStartX > touchEndX) {
20035                            if(isScrollAllowed.m.right){
20036                                moveSlideRight(activeSection); //next
20037                            }
20038                        } else {
20039                            if(isScrollAllowed.m.left){
20040                                moveSlideLeft(activeSection); //prev
20041                            }
20042                        }
20043                    }
20044                }
20045
20046                //vertical scrolling (only when autoScrolling is enabled)
20047                else if(options.autoScrolling && canScroll){
20048
20049                    //is the movement greater than the minimum resistance to scroll?
20050                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
20051                        if (touchStartY > touchEndY) {
20052                            scrolling('down', scrollable);
20053                        } else if (touchEndY > touchStartY) {
20054                            scrolling('up', scrollable);
20055                        }
20056                    }
20057                }
20058            }
20059        }
20060
20061        /**
20062         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
20063         * Currently works well for iOS - Android might need some testing
20064         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
20065         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
20066         * @return {boolean} true if there is a match to options.normalScrollElements
20067         */
20068        function checkParentForNormalScrollElement (el, hop) {
20069            hop = hop || 0;
20070            var parent = $(el).parent();
20071
20072            if (hop < options.normalScrollElementTouchThreshold &&
20073                parent.is(options.normalScrollElements) ) {
20074                return true;
20075            } else if (hop == options.normalScrollElementTouchThreshold) {
20076                return false;
20077            } else {
20078                return checkParentForNormalScrollElement(parent, ++hop);
20079            }
20080        }
20081
20082        /**
20083        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
20084        * this way we make sure that is really a touch event what IE is detecting.
20085        */
20086        function isReallyTouch(e){
20087            //if is not IE   ||  IE is detecting `touch` or `pen`
20088            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
20089        }
20090
20091        /**
20092        * Handler for the touch start event.
20093        */
20094        function touchStartHandler(event){
20095            var e = event.originalEvent;
20096
20097            //stopping the auto scroll to adjust to a section
20098            if(options.fitToSection){
20099                $htmlBody.stop();
20100            }
20101
20102            if(isReallyTouch(e)){
20103                var touchEvents = getEventsPage(e);
20104                touchStartY = touchEvents.y;
20105                touchStartX = touchEvents.x;
20106            }
20107        }
20108
20109        /**
20110        * Gets the average of the last `number` elements of the given array.
20111        */
20112        function getAverage(elements, number){
20113            var sum = 0;
20114
20115            //taking `number` elements from the end to make the average, if there are not enought, 1
20116            var lastElements = elements.slice(Math.max(elements.length - number, 1));
20117
20118            for(var i = 0; i < lastElements.length; i++){
20119                sum = sum + lastElements[i];
20120            }
20121
20122            return Math.ceil(sum/number);
20123        }
20124
20125        /**
20126         * Detecting mousewheel scrolling
20127         *
20128         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
20129         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
20130         */
20131        var prevTime = new Date().getTime();
20132
20133        function MouseWheelHandler(e) {
20134            var curTime = new Date().getTime();
20135            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
20136
20137            //autoscrolling and not zooming?
20138            if(options.autoScrolling && !controlPressed && !isNormalScroll){
20139                // cross-browser wheel delta
20140                e = e || window.event;
20141                var value = e.wheelDelta || -e.deltaY || -e.detail;
20142                var delta = Math.max(-1, Math.min(1, value));
20143
20144                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
20145                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
20146
20147                //Limiting the array to 150 (lets not waste memory!)
20148                if(scrollings.length > 149){
20149                    scrollings.shift();
20150                }
20151
20152                //keeping record of the previous scrollings
20153                scrollings.push(Math.abs(value));
20154
20155                //preventing to scroll the site on mouse wheel when scrollbar is present
20156                if(options.scrollBar){
20157                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
20158                }
20159
20160                var activeSection = $(SECTION_ACTIVE_SEL);
20161                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
20162
20163                //time difference between the last scroll and the current one
20164                var timeDiff = curTime-prevTime;
20165                prevTime = curTime;
20166
20167                //haven't they scrolled in a while?
20168                //(enough to be consider a different scrolling action to scroll another section)
20169                if(timeDiff > 200){
20170                    //emptying the array, we dont care about old scrollings for our averages
20171                    scrollings = [];
20172                }
20173
20174                if(canScroll){
20175                    var averageEnd = getAverage(scrollings, 10);
20176                    var averageMiddle = getAverage(scrollings, 70);
20177                    var isAccelerating = averageEnd >= averageMiddle;
20178
20179                    //to avoid double swipes...
20180                    if(isAccelerating && isScrollingVertically){
20181                        //scrolling down?
20182                        if (delta < 0) {
20183                            scrolling('down', scrollable);
20184
20185                        //scrolling up?
20186                        }else {
20187                            scrolling('up', scrollable);
20188                        }
20189                    }
20190                }
20191
20192                return false;
20193            }
20194
20195            if(options.fitToSection){
20196                //stopping the auto scroll to adjust to a section
20197                $htmlBody.stop();
20198            }
20199        }
20200
20201        /**
20202        * Slides a slider to the given direction.
20203        * Optional `section` param.
20204        */
20205        function moveSlide(direction, section){
20206            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
20207            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
20208            var numSlides = slides.find(SLIDE_SEL).length;
20209
20210            // more than one slide needed and nothing should be sliding
20211            if (!slides.length || slideMoving || numSlides < 2) {
20212                return;
20213            }
20214
20215            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
20216            var destiny = null;
20217
20218            if(direction === 'left'){
20219                destiny = currentSlide.prev(SLIDE_SEL);
20220            }else{
20221                destiny = currentSlide.next(SLIDE_SEL);
20222            }
20223
20224            //isn't there a next slide in the secuence?
20225            if(!destiny.length){
20226                //respect loopHorizontal settin
20227                if (!options.loopHorizontal) return;
20228
20229                if(direction === 'left'){
20230                    destiny = currentSlide.siblings(':last');
20231                }else{
20232                    destiny = currentSlide.siblings(':first');
20233                }
20234            }
20235
20236            slideMoving = true;
20237
20238            landscapeScroll(slides, destiny, direction);
20239        }
20240
20241        /**
20242        * Maintains the active slides in the viewport
20243        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
20244        */
20245        function keepSlidesPosition(){
20246            $(SLIDE_ACTIVE_SEL).each(function(){
20247                silentLandscapeScroll($(this), 'internal');
20248            });
20249        }
20250
20251        var previousDestTop = 0;
20252        /**
20253        * Returns the destination Y position based on the scrolling direction and
20254        * the height of the section.
20255        */
20256        function getDestinationPosition(element){
20257            var elemPosition = element.position();
20258
20259            //top of the desination will be at the top of the viewport
20260            var position = elemPosition.top;
20261            var isScrollingDown =  elemPosition.top > previousDestTop;
20262            var sectionBottom = position - windowsHeight + element.outerHeight();
20263            var bigSectionsDestination = options.bigSectionsDestination;
20264
20265            //Uncode addition
20266            var containerH = container.outerHeight();
20267            var containerPosition = container.offset();
20268
20269            //########### Commented by Uncode - START ###########
20270            //is the destination element bigger than the viewport?
20271            // if(element.outerHeight() > windowsHeight){
20272            //     //scrolling up?
20273            //     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
20274            //         position = sectionBottom;
20275            //     }
20276            // }
20277
20278            // //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
20279            // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
20280            //     //The bottom of the destination will be at the bottom of the viewport
20281            //     position = sectionBottom;
20282            // }
20283            //########### Commented by Uncode - END ###########
20284
20285            //Uncode addition
20286            if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
20287                position += 18;
20288            if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
20289                position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
20290            }
20291            
20292            /*
20293            Keeping record of the last scrolled position to determine the scrolling direction.
20294            No conventional methods can be used as the scroll bar might not be present
20295            AND the section might not be active if it is auto-height and didnt reach the middle
20296            of the viewport.
20297            */
20298            previousDestTop = position;
20299            return position;
20300        }
20301
20302        /**
20303        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
20304        */
20305        function scrollPage(element, callback, isMovementUp){
20306            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
20307
20308            var dtop = getDestinationPosition(element);
20309            var slideAnchorLink;
20310            var slideIndex;
20311
20312            //local variables
20313            var v = {
20314                element: element,
20315                callback: callback,
20316                isMovementUp: isMovementUp,
20317                dtop: dtop,
20318                yMovement: getYmovement(element),
20319                anchorLink: element.data('anchor'),
20320                sectionIndex: element.index(SECTION_SEL),
20321                activeSlide: element.find(SLIDE_ACTIVE_SEL),
20322                activeSection: $(SECTION_ACTIVE_SEL),
20323                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
20324
20325                //caching the value of isResizing at the momment the function is called
20326                //because it will be checked later inside a setTimeout and the value might change
20327                localIsResizing: isResizing
20328            };
20329
20330            //quiting when destination scroll is the same as the current one
20331            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
20332
20333            if(v.activeSlide.length){
20334                slideAnchorLink = v.activeSlide.data('anchor');
20335                slideIndex = v.activeSlide.index();
20336            }
20337
20338            // If continuousVertical && we need to wrap around
20339            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
20340                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
20341                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
20342
20343                v = createInfiniteSections(v);
20344            }
20345
20346            //callback (onLeave) if the site is not just resizing and readjusting the slides
20347            if($.isFunction(options.onLeave) && !v.localIsResizing){
20348                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
20349                    return;
20350                }
20351            }
20352
20353            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
20354            if(!v.localIsResizing){
20355                stopMedia(v.activeSection);
20356            }
20357
20358            options.scrollOverflowHandler.beforeLeave();
20359            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
20360            lazyLoad(element);
20361            options.scrollOverflowHandler.onLeave();
20362
20363
20364            //preventing from activating the MouseWheelHandler event
20365            //more than once if the page is scrolling
20366            canScroll = false;
20367
20368            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
20369
20370            performMovement(v);
20371
20372            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
20373            lastScrolledDestiny = v.anchorLink;
20374
20375            //avoid firing it twice (as it does also on scroll)
20376            activateMenuAndNav(v.anchorLink, v.sectionIndex);
20377        }
20378
20379        /**
20380        * Performs the vertical movement (by CSS3 or by jQuery)
20381        */
20382        function performMovement(v){
20383            // using CSS3 translate functionality
20384            if (options.css3 && options.autoScrolling && !options.scrollBar) {
20385
20386                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
20387                // that's why we round it to 0.
20388                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
20389                transformContainer(translate3d, true);
20390
20391                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
20392                //scrollingSpeed to change in case of using silentMoveTo();
20393                if(options.scrollingSpeed){
20394                    clearTimeout(afterSectionLoadsId);
20395                    afterSectionLoadsId = setTimeout(function () {
20396                        afterSectionLoads(v);
20397                    }, options.scrollingSpeed);
20398                }else{
20399                    afterSectionLoads(v);
20400                }
20401            }
20402
20403            // using jQuery animate
20404            else{
20405                var scrollSettings = getScrollSettings(v);
20406
20407                $(scrollSettings.element).animate(
20408                    scrollSettings.options,
20409                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
20410                    if(options.scrollBar){
20411
20412                        /* Hack!
20413                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
20414                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
20415
20416                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
20417                        */
20418                        setTimeout(function(){
20419                            afterSectionLoads(v);
20420                        },30);
20421                    }else{
20422                        afterSectionLoads(v);
20423                    }
20424                });
20425            }
20426        }
20427
20428        /**
20429        * Gets the scrolling settings depending on the plugin autoScrolling option
20430        */
20431        function getScrollSettings(v){
20432            var scroll = {};
20433
20434            if(options.autoScrolling && !options.scrollBar){
20435                scroll.options = { 'top': -v.dtop};
20436                scroll.element = WRAPPER_SEL;
20437            }else{
20438                scroll.options = { 'scrollTop': v.dtop};
20439                scroll.element = 'html, body';
20440            }
20441
20442            return scroll;
20443        }
20444
20445        /**
20446        * Adds sections before or after the current one to create the infinite effect.
20447        */
20448        function createInfiniteSections(v){
20449            // Scrolling down
20450            if (!v.isMovementUp) {
20451                // Move all previous sections to after the active section
20452                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
20453            }
20454            else { // Scrolling up
20455                // Move all next sections to before the active section
20456                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
20457            }
20458
20459            // Maintain the displayed position (now that we changed the element order)
20460            silentScroll($(SECTION_ACTIVE_SEL).position().top);
20461
20462            // Maintain the active slides visible in the viewport
20463            keepSlidesPosition();
20464
20465            // save for later the elements that still need to be reordered
20466            v.wrapAroundElements = v.activeSection;
20467
20468            // Recalculate animation variables
20469            v.dtop = v.element.position().top;
20470            v.yMovement = getYmovement(v.element);
20471
20472            return v;
20473        }
20474
20475        /**
20476        * Fix section order after continuousVertical changes have been animated
20477        */
20478        function continuousVerticalFixSectionOrder (v) {
20479            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
20480            // finish moving the elements around so the direct navigation will function more simply
20481            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
20482                return;
20483            }
20484
20485            if (v.isMovementUp) {
20486                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
20487            }
20488            else {
20489                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
20490            }
20491
20492            silentScroll($(SECTION_ACTIVE_SEL).position().top);
20493
20494            // Maintain the active slides visible in the viewport
20495            keepSlidesPosition();
20496        }
20497
20498
20499        /**
20500        * Actions to do once the section is loaded.
20501        */
20502        function afterSectionLoads (v){
20503            continuousVerticalFixSectionOrder(v);
20504
20505            //callback (afterLoad) if the site is not just resizing and readjusting the slides
20506            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
20507            options.scrollOverflowHandler.afterLoad();
20508
20509            if(!v.localIsResizing){
20510                playMedia(v.element);
20511            }
20512
20513            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
20514
20515            canScroll = true;
20516
20517            $.isFunction(v.callback) && v.callback.call(this);
20518        }
20519
20520        /**
20521        * Sets the value for the given attribute from the `data-` attribute with the same suffix
20522        * ie: data-srcset ==> srcset  |  data-src ==> src
20523        */
20524        function setSrc(element, attribute){
20525            element
20526                .attr(attribute, element.data(attribute))
20527                .removeAttr('data-' + attribute);
20528        }
20529
20530        /**
20531        * Lazy loads image, video and audio elements.
20532        */
20533        function lazyLoad(destiny){
20534            if (!options.lazyLoading){
20535                return;
20536            }
20537
20538            var panel = getSlideOrSection(destiny);
20539            var element;
20540            
20541            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
20542                element = $(this);
20543
20544                $.each(['src', 'srcset'], function(index, type){
20545                    var attribute = element.attr('data-' + type);
20546                    if(typeof attribute !== 'undefined' && attribute){
20547                        setSrc(element, type);
20548                    }
20549                });
20550
20551                if(element.is('source')){
20552                    element.closest('video').get(0).load();
20553                }
20554            });
20555        }
20556
20557        /**
20558        * Plays video and audio elements.
20559        */
20560        function playMedia(destiny){
20561            var panel = getSlideOrSection(destiny);
20562
20563            //playing HTML5 media elements
20564            panel.find('video, audio').each(function(){
20565                var element = $(this).get(0);
20566
20567                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
20568                    element.play();
20569                }
20570            });
20571
20572            //youtube videos
20573            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
20574                var element = $(this).get(0);
20575
20576                if ( element.hasAttribute('data-autoplay') ){
20577                    playYoutube(element);
20578                }
20579
20580                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
20581                element.onload = function() {
20582                    if ( element.hasAttribute('data-autoplay') ){
20583                        playYoutube(element);
20584                    }
20585                };
20586            });
20587        }
20588
20589        /**
20590        * Plays a youtube video
20591        */
20592        function playYoutube(element){
20593            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
20594        }
20595
20596        /**
20597        * Stops video and audio elements.
20598        */
20599        function stopMedia(destiny){
20600            var panel = getSlideOrSection(destiny);
20601
20602            //stopping HTML5 media elements
20603            panel.find('video, audio').each(function(){
20604                var element = $(this).get(0);
20605
20606                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
20607                    element.pause();
20608                }
20609            });
20610
20611            //youtube videos
20612            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
20613                var element = $(this).get(0);
20614
20615                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
20616                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
20617                }
20618            });
20619        }
20620
20621        /**
20622        * Gets the active slide (or section) for the given section
20623        */
20624        function getSlideOrSection(destiny){
20625            var slide = destiny.find(SLIDE_ACTIVE_SEL);
20626            if( slide.length ) {
20627                destiny = $(slide);
20628            }
20629
20630            return destiny;
20631        }
20632
20633        /**
20634        * Scrolls to the anchor in the URL when loading the site
20635        */
20636        function scrollToAnchor(){
20637            //getting the anchor link in the URL and deleting the `#`
20638            var value =  window.location.hash.replace('#', '').split('/');
20639            var sectionAnchor = decodeURIComponent(value[0]);
20640            var slideAnchor = decodeURIComponent(value[1]);
20641
20642            if(sectionAnchor){  //if theres any #
20643                if(options.animateAnchor){
20644                    scrollPageAndSlide(sectionAnchor, slideAnchor);
20645                }else{
20646                    silentMoveTo(sectionAnchor, slideAnchor);
20647                }
20648            }
20649        }
20650
20651        /**
20652        * Detecting any change on the URL to scroll to the given anchor link
20653        * (a way to detect back history button as we play with the hashes on the URL)
20654        */
20655        function hashChangeHandler(){
20656            if(!isScrolling && !options.lockAnchors){
20657                var value =  window.location.hash.replace('#', '').split('/');
20658                var sectionAnchor = decodeURIComponent(value[0]);
20659                var slideAnchor = decodeURIComponent(value[1]);
20660
20661                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
20662                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
20663                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
20664
20665
20666                if(sectionAnchor.length){
20667                    /*in order to call scrollpage() only once for each destination at a time
20668                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
20669                    event is fired on every scroll too.*/
20670                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
20671                        scrollPageAndSlide(sectionAnchor, slideAnchor);
20672                    }
20673                }
20674            }
20675        }
20676
20677        //Sliding with arrow keys, both, vertical and horizontal
20678        function keydownHandler(e) {
20679
20680            clearTimeout(keydownId);
20681
20682            var activeElement = $(':focus');
20683
20684            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
20685                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
20686                options.keyboardScrolling && options.autoScrolling){
20687                var keyCode = e.which;
20688
20689                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
20690                var keyControls = [40, 38, 32, 33, 34];
20691                if($.inArray(keyCode, keyControls) > -1){
20692                    e.preventDefault();
20693                }
20694
20695                controlPressed = e.ctrlKey;
20696
20697                keydownId = setTimeout(function(){
20698                    onkeydown(e);
20699                },150);
20700            }
20701        }
20702
20703        function tooltipTextHandler(){
20704            $(this).prev().trigger('click');
20705        }
20706
20707        //to prevent scrolling while zooming
20708        function keyUpHandler(e){
20709            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
20710                controlPressed = e.ctrlKey;
20711            }
20712        }
20713
20714        //binding the mousemove when the mouse's middle button is released
20715        function mouseDownHandler(e){
20716            //middle button
20717            if (e.which == 2){
20718                oldPageY = e.pageY;
20719                container.on('mousemove', mouseMoveHandler);
20720            }
20721        }
20722
20723        //unbinding the mousemove when the mouse's middle button is released
20724        function mouseUpHandler(e){
20725            //middle button
20726            if (e.which == 2){
20727                container.off('mousemove');
20728            }
20729        }
20730
20731        //Scrolling horizontally when clicking on the slider controls.
20732        function slideArrowHandler(){
20733            var section = $(this).closest(SECTION_SEL);
20734
20735            if ($(this).hasClass(SLIDES_PREV)) {
20736                if(isScrollAllowed.m.left){
20737                    moveSlideLeft(section);
20738                }
20739            } else {
20740                if(isScrollAllowed.m.right){
20741                    moveSlideRight(section);
20742                }
20743            }
20744        }
20745
20746        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
20747        function blurHandler(){
20748            isWindowFocused = false;
20749            controlPressed = false;
20750        }
20751
20752        //Scrolls to the section when clicking the navigation bullet
20753        function sectionBulletHandler(e){
20754            e.preventDefault();
20755            var index = $(this).parent().index();
20756            scrollPage($(SECTION_SEL).eq(index));
20757        }
20758
20759        //Scrolls the slider to the given slide destination for the given section
20760        function slideBulletHandler(e){
20761            e.preventDefault();
20762            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
20763            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
20764
20765            landscapeScroll(slides, destiny);
20766        }
20767
20768        /**
20769        * Keydown event
20770        */
20771        function onkeydown(e){
20772            var shiftPressed = e.shiftKey;
20773
20774            //do nothing if we can not scroll or we are not using horizotnal key arrows.
20775            if(!canScroll && [37,39].indexOf(e.which) < 0){
20776                return;
20777            }
20778
20779            switch (e.which) {
20780                //up
20781                case 38:
20782                case 33:
20783                    if(isScrollAllowed.k.up){
20784                        moveSectionUp();
20785                    }
20786                    break;
20787
20788                //down
20789                case 32: //spacebar
20790                    if(shiftPressed && isScrollAllowed.k.up){
20791                        moveSectionUp();
20792                        break;
20793                    }
20794                /* falls through */
20795                case 40:
20796                case 34:
20797                    if(isScrollAllowed.k.down){
20798                        moveSectionDown();
20799                    }
20800                    break;
20801
20802                //Home
20803                case 36:
20804                    if(isScrollAllowed.k.up){
20805                        moveTo(1);
20806                    }
20807                    break;
20808
20809                //End
20810                case 35:
20811                     if(isScrollAllowed.k.down){
20812                        moveTo( $(SECTION_SEL).length );
20813                    }
20814                    break;
20815
20816                //left
20817                case 37:
20818                    if(isScrollAllowed.k.left){
20819                        moveSlideLeft();
20820                    }
20821                    break;
20822
20823                //right
20824                case 39:
20825                    if(isScrollAllowed.k.right){
20826                        moveSlideRight();
20827                    }
20828                    break;
20829
20830                default:
20831                    return; // exit this handler for other keys
20832            }
20833        }
20834
20835        /**
20836        * Detecting the direction of the mouse movement.
20837        * Used only for the middle button of the mouse.
20838        */
20839        var oldPageY = 0;
20840        function mouseMoveHandler(e){
20841            if(canScroll){
20842                // moving up
20843                if (e.pageY < oldPageY && isScrollAllowed.m.up){
20844                    moveSectionUp();
20845                }
20846
20847                // moving down
20848                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
20849                    moveSectionDown();
20850                }
20851            }
20852            oldPageY = e.pageY;
20853        }
20854
20855        /**
20856        * Scrolls horizontal sliders.
20857        */
20858        function landscapeScroll(slides, destiny, direction){
20859            var section = slides.closest(SECTION_SEL);
20860            var v = {
20861                slides: slides,
20862                destiny: destiny,
20863                direction: direction,
20864                destinyPos: destiny.position(),
20865                slideIndex: destiny.index(),
20866                section: section,
20867                sectionIndex: section.index(SECTION_SEL),
20868                anchorLink: section.data('anchor'),
20869                slidesNav: section.find(SLIDES_NAV_SEL),
20870                slideAnchor:  getAnchor(destiny),
20871                prevSlide: section.find(SLIDE_ACTIVE_SEL),
20872                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
20873
20874                //caching the value of isResizing at the momment the function is called
20875                //because it will be checked later inside a setTimeout and the value might change
20876                localIsResizing: isResizing
20877            };
20878            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
20879
20880            //important!! Only do it when not resizing
20881            if(!v.localIsResizing){
20882                //preventing from scrolling to the next/prev section when using scrollHorizontally
20883                canScroll = false;
20884            }
20885
20886            if(options.onSlideLeave){
20887
20888                //if the site is not just resizing and readjusting the slides
20889                if(!v.localIsResizing && v.xMovement!=='none'){
20890                    if($.isFunction( options.onSlideLeave )){
20891                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
20892                            slideMoving = false;
20893                            return;
20894                        }
20895                    }
20896                }
20897            }
20898
20899            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
20900
20901            if(!v.localIsResizing){
20902                stopMedia(v.prevSlide);
20903                lazyLoad(destiny);
20904            }
20905
20906            if(!options.loopHorizontal && options.controlArrows){
20907                //hidding it for the fist slide, showing for the rest
20908                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
20909
20910                //hidding it for the last slide, showing for the rest
20911                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
20912            }
20913
20914            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
20915            if(section.hasClass(ACTIVE) && !v.localIsResizing){
20916                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
20917            }
20918
20919            performHorizontalMove(slides, v, true);
20920        }
20921
20922
20923        function afterSlideLoads(v){
20924            activeSlidesNavigation(v.slidesNav, v.slideIndex);
20925
20926            //if the site is not just resizing and readjusting the slides
20927            if(!v.localIsResizing){
20928                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
20929
20930                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
20931                //and to prevent double scroll right after a windows resize
20932                canScroll = true;
20933
20934                playMedia(v.destiny);
20935            }
20936
20937            //letting them slide again
20938            slideMoving = false;
20939        }
20940
20941        /**
20942        * Performs the horizontal movement. (CSS3 or jQuery)
20943        *
20944        * @param fireCallback {Bool} - determines whether or not to fire the callback
20945        */
20946        function performHorizontalMove(slides, v, fireCallback){
20947            var destinyPos = v.destinyPos;
20948
20949            if(options.css3){
20950                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
20951
20952                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
20953
20954                afterSlideLoadsId = setTimeout(function(){
20955                    fireCallback && afterSlideLoads(v);
20956                }, options.scrollingSpeed, options.easing);
20957            }else{
20958                slides.animate({
20959                    scrollLeft : Math.round(destinyPos.left)
20960                }, options.scrollingSpeed, options.easing, function() {
20961
20962                    fireCallback && afterSlideLoads(v);
20963                });
20964            }
20965        }
20966
20967        /**
20968        * Sets the state for the horizontal bullet navigations.
20969        */
20970        function activeSlidesNavigation(slidesNav, slideIndex){
20971            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
20972            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
20973        }
20974
20975        var previousHeight = windowsHeight;
20976
20977        //when resizing the site, we adjust the heights of the sections, slimScroll...
20978        function resizeHandler(){
20979            //checking if it needs to get responsive
20980            responsive();
20981
20982            // rebuild immediately on touch devices
20983            if (isTouchDevice) {
20984                var activeElement = $(document.activeElement);
20985
20986                //if the keyboard is NOT visible
20987                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
20988                    var currentHeight = $window.height();
20989
20990                    //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)
20991                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
20992                        reBuild(true);
20993                        previousHeight = currentHeight;
20994                    }
20995                }
20996            }else{
20997                //in order to call the functions only when the resize is finished
20998                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
20999                clearTimeout(resizeId);
21000
21001                resizeId = setTimeout(function(){
21002                    reBuild(true);
21003                }, 350);
21004            }
21005        }
21006
21007        /**
21008        * Checks if the site needs to get responsive and disables autoScrolling if so.
21009        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
21010        */
21011        function responsive(){
21012            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
21013            var heightLimit = options.responsiveHeight;
21014
21015            //only calculating what we need. Remember its called on the resize event.
21016            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
21017            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
21018
21019            if(widthLimit && heightLimit){
21020                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
21021            }
21022            else if(widthLimit){
21023                setResponsive(isBreakingPointWidth);
21024            }
21025            else if(heightLimit){
21026                setResponsive(isBreakingPointHeight);
21027            }
21028        }
21029
21030        /**
21031        * Adds transition animations for the given element
21032        */
21033        function addAnimation(container, element){
21034            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
21035
21036            container.removeClass(NO_TRANSITION);
21037            return container.css({
21038                '-webkit-transition': transition,
21039                'transition': transition
21040            });
21041        }
21042
21043        /**
21044        * Remove transition animations for the given element
21045        */
21046        function removeAnimation(element){
21047            return element.addClass(NO_TRANSITION);
21048        }
21049
21050        /**
21051        * Activating the vertical navigation bullets according to the given slide name.
21052        */
21053        function activateNavDots(name, sectionIndex){
21054            if(options.navigation){
21055                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
21056                if(name){
21057                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
21058                }else{
21059                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
21060                }
21061            }
21062        }
21063
21064        /**
21065        * Activating the website main menu elements according to the given slide name.
21066        */
21067        function activateMenuElement(name){
21068            if(options.menu){
21069                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
21070                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
21071            }
21072        }
21073
21074        /**
21075        * Sets to active the current menu and vertical nav items.
21076        */
21077        function activateMenuAndNav(anchor, index){
21078            activateMenuElement(anchor);
21079            activateNavDots(anchor, index);
21080        }
21081
21082        /**
21083        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
21084        * from the current section.
21085        */
21086        function getYmovement(destiny){
21087            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
21088            var toIndex = destiny.index(SECTION_SEL);
21089            if( fromIndex == toIndex){
21090                return 'none';
21091            }
21092            if(fromIndex > toIndex){
21093                return 'up';
21094            }
21095            return 'down';
21096        }
21097
21098        /**
21099        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
21100        * from the current slide.
21101        */
21102        function getXmovement(fromIndex, toIndex){
21103            if( fromIndex == toIndex){
21104                return 'none';
21105            }
21106            if(fromIndex > toIndex){
21107                return 'left';
21108            }
21109            return 'right';
21110        }
21111
21112        /**
21113        * Checks if the element needs scrollbar and if the user wants to apply it.
21114        * If so it creates it.
21115        *
21116        * @param {Object} element   jQuery object of the section or slide
21117        */
21118        function createScrollBar(element){
21119            //User doesn't want scrollbar here? Sayonara baby!
21120            if(element.hasClass('fp-noscroll')) return;
21121
21122            //needed to make `scrollHeight` work under Opera 12
21123            element.css('overflow', 'hidden');
21124
21125            var scrollOverflowHandler = options.scrollOverflowHandler;
21126            var wrap = scrollOverflowHandler.wrapContent();
21127            //in case element is a slide
21128            var section = element.closest(SECTION_SEL);
21129            var scrollable = scrollOverflowHandler.scrollable(element);
21130            var contentHeight;
21131
21132            //if there was scroll, the contentHeight will be the one in the scrollable section
21133            if(scrollable.length){
21134                contentHeight = scrollOverflowHandler.scrollHeight(element);
21135            }else{
21136                contentHeight = element.get(0).scrollHeight;
21137                if(options.verticalCentered){
21138                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
21139                }
21140            }
21141
21142            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
21143            //Uncode addition
21144            scrollHeight -= UNCODE.bodyBorder*2 + UNCODE.adminBarHeight;
21145
21146            //needs scroll?
21147            if ( contentHeight > scrollHeight) {
21148                //did we already have an scrollbar ? Updating it
21149                if(scrollable.length){
21150                    scrollOverflowHandler.update(element, scrollHeight);
21151                }
21152                //creating the scrolling
21153                else{
21154                    if(options.verticalCentered){
21155                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
21156                    }else{
21157                        element.wrapInner(wrap);
21158                    }
21159                    scrollOverflowHandler.create(element, scrollHeight);
21160                }
21161            }
21162            //removing the scrolling when it is not necessary anymore
21163            else{
21164                scrollOverflowHandler.remove(element);
21165            }
21166
21167            //undo
21168            element.css('overflow', '');
21169        }
21170
21171        function addTableClass(element){
21172            //In case we are styling for the 2nd time as in with reponsiveSlides
21173            if(!element.hasClass(TABLE)){
21174                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
21175            }
21176        }
21177
21178        function getTableHeight(element){
21179            var sectionHeight = windowsHeight;
21180
21181            if(options.paddingTop || options.paddingBottom){
21182                var section = element;
21183                if(!section.hasClass(SECTION)){
21184                    section = element.closest(SECTION_SEL);
21185                }
21186
21187                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
21188                sectionHeight = (windowsHeight - paddings);
21189            }
21190
21191            return sectionHeight;
21192        }
21193
21194        /**
21195        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
21196        */
21197        function transformContainer(translate3d, animated){
21198            if(animated){
21199                addAnimation(container);
21200            }else{
21201                removeAnimation(container);
21202            }
21203
21204            container.css(getTransforms(translate3d));
21205
21206            //syncronously removing the class after the animation has been applied.
21207            setTimeout(function(){
21208                container.removeClass(NO_TRANSITION);
21209            },10);
21210        }
21211
21212        /**
21213        * Gets a section by its anchor / index
21214        */
21215        function getSectionByAnchor(sectionAnchor){
21216            if(!sectionAnchor) return [];
21217
21218            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
21219            if(!section.length){
21220                section = $(SECTION_SEL).eq( sectionAnchor -1);
21221            }
21222
21223            return section;
21224        }
21225
21226        /**
21227        * Gets a slide inside a given section by its anchor / index
21228        */
21229        function getSlideByAnchor(slideAnchor, section){
21230            var slides = section.find(SLIDES_WRAPPER_SEL);
21231            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
21232
21233            if(!slide.length){
21234                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
21235            }
21236
21237            return slide;
21238        }
21239
21240        /**
21241        * Scrolls to the given section and slide anchors
21242        */
21243        function scrollPageAndSlide(destiny, slide){
21244            var section = getSectionByAnchor(destiny);
21245
21246            //do nothing if there's no section with the given anchor name
21247            if(!section.length) return;
21248
21249            //default slide
21250            if (typeof slide === 'undefined') {
21251                slide = 0;
21252            }
21253
21254            //we need to scroll to the section and then to the slide
21255            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
21256                scrollPage(section, function(){
21257                    scrollSlider(section, slide);
21258                });
21259            }
21260            //if we were already in the section
21261            else{
21262                scrollSlider(section, slide);
21263            }
21264        }
21265
21266        /**
21267        * Scrolls the slider to the given slide destination for the given section
21268        */
21269        function scrollSlider(section, slideAnchor){
21270            if(typeof slideAnchor !== 'undefined'){
21271                var slides = section.find(SLIDES_WRAPPER_SEL);
21272                var destiny =  getSlideByAnchor(slideAnchor, section);
21273
21274                if(destiny.length){
21275                    landscapeScroll(slides, destiny);
21276                }
21277            }
21278        }
21279
21280        /**
21281        * Creates a landscape navigation bar with dots for horizontal sliders.
21282        */
21283        function addSlidesNavigation(section, numSlides){
21284            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
21285            var nav = section.find(SLIDES_NAV_SEL);
21286
21287            //top or bottom
21288            nav.addClass(options.slidesNavPosition);
21289
21290            for(var i=0; i< numSlides; i++){
21291                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
21292            }
21293
21294            //centering it
21295            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
21296
21297            nav.find('li').first().find('a').addClass(ACTIVE);
21298        }
21299
21300
21301        /**
21302        * Sets the state of the website depending on the active section/slide.
21303        * It changes the URL hash when needed and updates the body class.
21304        */
21305        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
21306            var sectionHash = '';
21307
21308            if(options.anchors.length && !options.lockAnchors){
21309
21310                //isn't it the first slide?
21311                if(slideIndex){
21312                    if(typeof anchorLink !== 'undefined'){
21313                        sectionHash = anchorLink;
21314                    }
21315
21316                    //slide without anchor link? We take the index instead.
21317                    if(typeof slideAnchor === 'undefined'){
21318                        slideAnchor = slideIndex;
21319                    }
21320
21321                    lastScrolledSlide = slideAnchor;
21322                    setUrlHash(sectionHash + '/' + slideAnchor);
21323
21324                //first slide won't have slide anchor, just the section one
21325                }else if(typeof slideIndex !== 'undefined'){
21326                    lastScrolledSlide = slideAnchor;
21327                    setUrlHash(anchorLink);
21328                }
21329
21330                //section without slides
21331                else{
21332                    setUrlHash(anchorLink);
21333                }
21334            }
21335
21336            setBodyClass();
21337        }
21338
21339        /**
21340        * Sets the URL hash.
21341        */
21342        function setUrlHash(url){
21343            //Uncode addition
21344            if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
21345                return false;
21346
21347            if(options.recordHistory){
21348                location.hash = url;
21349            }else{
21350                //Uncode addition
21351                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
21352                // if(isTouchDevice || isTouch){
21353                //     window.history.replaceState(undefined, undefined, '#' + url);
21354                // }else{
21355                //     var baseUrl = window.location.href.split('#')[0];
21356                //     window.location.replace( baseUrl + '#' + url );
21357                // }
21358                return false;
21359            }
21360        }
21361
21362        /**
21363        * Gets the anchor for the given slide / section. Its index will be used if there's none.
21364        */
21365        function getAnchor(element){
21366            var anchor = element.data('anchor');
21367            var index = element.index();
21368
21369            //Slide without anchor link? We take the index instead.
21370            if(typeof anchor === 'undefined'){
21371                anchor = index;
21372            }
21373
21374            return anchor;
21375        }
21376
21377        /**
21378        * Sets a class for the body of the page depending on the active section / slide
21379        */
21380        function setBodyClass(){
21381            var section = $(SECTION_ACTIVE_SEL);
21382            var slide = section.find(SLIDE_ACTIVE_SEL);
21383
21384            var sectionAnchor = getAnchor(section);
21385            var slideAnchor = getAnchor(slide);
21386
21387            var text = String(sectionAnchor);
21388
21389            if(slide.length){
21390                text = text + '-' + slideAnchor;
21391            }
21392
21393            //changing slash for dash to make it a valid CSS style
21394            text = text.replace('/', '-').replace('#','');
21395
21396            //removing previous anchor classes
21397            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
21398            $body[0].className = $body[0].className.replace(classRe, '');
21399
21400            //adding the current anchor
21401            $body.addClass(VIEWING_PREFIX + '-' + text);
21402        }
21403
21404        /**
21405        * Checks for translate3d support
21406        * @return boolean
21407        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
21408        */
21409        function support3d() {
21410            var el = document.createElement('p'),
21411                has3d,
21412                transforms = {
21413                    'webkitTransform':'-webkit-transform',
21414                    'OTransform':'-o-transform',
21415                    'msTransform':'-ms-transform',
21416                    'MozTransform':'-moz-transform',
21417                    'transform':'transform'
21418                };
21419
21420            // Add it to the body to get the computed style.
21421            document.body.insertBefore(el, null);
21422
21423            for (var t in transforms) {
21424                if (el.style[t] !== undefined) {
21425                    el.style[t] = 'translate3d(1px,1px,1px)';
21426                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
21427                }
21428            }
21429
21430            document.body.removeChild(el);
21431
21432            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
21433        }
21434
21435        /**
21436        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
21437        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
21438        */
21439        function removeMouseWheelHandler(){
21440            if (document.addEventListener) {
21441                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
21442                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
21443                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
21444            } else {
21445                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
21446            }
21447        }
21448
21449        /**
21450        * Adds the auto scrolling action for the mouse wheel and trackpad.
21451        * After this function is called, the mousewheel and trackpad movements will scroll through sections
21452        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
21453        */
21454        function addMouseWheelHandler(){
21455            var prefix = '';
21456            var _addEventListener;
21457
21458            if (window.addEventListener){
21459                _addEventListener = "addEventListener";
21460            }else{
21461                _addEventListener = "attachEvent";
21462                prefix = 'on';
21463            }
21464
21465             // detect available wheel event
21466            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
21467                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
21468                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
21469
21470
21471            if(support == 'DOMMouseScroll'){
21472                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false);
21473            }
21474
21475            //handle MozMousePixelScroll in older Firefox
21476            else{
21477                document[ _addEventListener ](prefix + support, MouseWheelHandler, false);
21478            }
21479        }
21480
21481        /**
21482        * Binding the mousemove when the mouse's middle button is pressed
21483        */
21484        function addMiddleWheelHandler(){
21485            container
21486                .on('mousedown', mouseDownHandler)
21487                .on('mouseup', mouseUpHandler);
21488        }
21489
21490        /**
21491        * Unbinding the mousemove when the mouse's middle button is released
21492        */
21493        function removeMiddleWheelHandler(){
21494            container
21495                .off('mousedown', mouseDownHandler)
21496                .off('mouseup', mouseUpHandler);
21497        }
21498
21499        /**
21500        * Adds the possibility to auto scroll through sections on touch devices.
21501        */
21502        function addTouchHandler(){
21503            if(isTouchDevice || isTouch){
21504                if(options.autoScrolling){
21505                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
21506                }
21507
21508                $(WRAPPER_SEL)
21509                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
21510                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
21511            }
21512        }
21513
21514        /**
21515        * Removes the auto scrolling for touch devices.
21516        */
21517        function removeTouchHandler(){
21518            if(isTouchDevice || isTouch){
21519                $(WRAPPER_SEL)
21520                    .off(events.touchstart)
21521                    .off(events.touchmove);
21522            }
21523        }
21524
21525        /*
21526        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
21527        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
21528        */
21529        function getMSPointer(){
21530            var pointer;
21531
21532            //IE >= 11 & rest of browsers
21533            if(window.PointerEvent){
21534                pointer = { down: 'pointerdown', move: 'pointermove'};
21535            }
21536
21537            //IE < 11
21538            else{
21539                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
21540            }
21541
21542            return pointer;
21543        }
21544
21545        /**
21546        * Gets the pageX and pageY properties depending on the browser.
21547        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
21548        */
21549        function getEventsPage(e){
21550            var events = [];
21551
21552            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
21553            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
21554
21555            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
21556            if(isTouch && isReallyTouch(e) && options.scrollBar){
21557                events.y = e.touches[0].pageY;
21558                events.x = e.touches[0].pageX;
21559            }
21560
21561            return events;
21562        }
21563
21564        /**
21565        * Slides silently (with no animation) the active slider to the given slide.
21566        * @param noCallback {bool} true or defined -> no callbacks
21567        */
21568        function silentLandscapeScroll(activeSlide, noCallbacks){
21569            setScrollingSpeed (0, 'internal');
21570
21571            if(typeof noCallbacks !== 'undefined'){
21572                //preventing firing callbacks afterSlideLoad etc.
21573                isResizing = true;
21574            }
21575
21576            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
21577
21578            if(typeof noCallbacks !== 'undefined'){
21579                isResizing = false;
21580            }
21581
21582            setScrollingSpeed(originals.scrollingSpeed, 'internal');
21583        }
21584
21585        /**
21586        * Scrolls silently (with no animation) the page to the given Y position.
21587        */
21588        function silentScroll(top){
21589            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
21590            // that's why we round it to 0.
21591            var roundedTop = Math.round(top);
21592
21593            if (options.css3 && options.autoScrolling && !options.scrollBar){
21594                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
21595                transformContainer(translate3d, false);
21596            }
21597            else if(options.autoScrolling && !options.scrollBar){
21598                container.css('top', -roundedTop);
21599            }
21600            else{
21601                $htmlBody.scrollTop(roundedTop);
21602            }
21603        }
21604
21605        /**
21606        * Returns the cross-browser transform string.
21607        */
21608        function getTransforms(translate3d){
21609            return {
21610                '-webkit-transform': translate3d,
21611                '-moz-transform': translate3d,
21612                '-ms-transform':translate3d,
21613                'transform': translate3d
21614            };
21615        }
21616
21617        /**
21618        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
21619        * @type  m (mouse) or k (keyboard)
21620        */
21621        function setIsScrollAllowed(value, direction, type){
21622            switch (direction){
21623                case 'up': isScrollAllowed[type].up = value; break;
21624                case 'down': isScrollAllowed[type].down = value; break;
21625                case 'left': isScrollAllowed[type].left = value; break;
21626                case 'right': isScrollAllowed[type].right = value; break;
21627                case 'all':
21628                    if(type == 'm'){
21629                        setAllowScrolling(value);
21630                    }else{
21631                        setKeyboardScrolling(value);
21632                    }
21633            }
21634        }
21635
21636        /*
21637        * Destroys fullpage.js plugin events and optinally its html markup and styles
21638        */
21639        function destroy(all){
21640            setAutoScrolling(false, 'internal');
21641            setAllowScrolling(false);
21642            setKeyboardScrolling(false);
21643            container.addClass(DESTROYED);
21644
21645            clearTimeout(afterSlideLoadsId);
21646            clearTimeout(afterSectionLoadsId);
21647            clearTimeout(resizeId);
21648            clearTimeout(scrollId);
21649            clearTimeout(scrollId2);
21650
21651            $window
21652                .off('scroll', scrollHandler)
21653                .off('hashchange', hashChangeHandler)
21654                .off('resize', resizeHandler);
21655
21656            $document
21657                .off('click touchstart', SECTION_NAV_SEL + ' a')
21658                .off('mouseenter', SECTION_NAV_SEL + ' li')
21659                .off('mouseleave', SECTION_NAV_SEL + ' li')
21660                .off('click touchstart', SLIDES_NAV_LINK_SEL)
21661                .off('mouseover', options.normalScrollElements)
21662                .off('mouseout', options.normalScrollElements);
21663
21664            $(SECTION_SEL)
21665                .off('click touchstart', SLIDES_ARROW_SEL);
21666
21667            clearTimeout(afterSlideLoadsId);
21668            clearTimeout(afterSectionLoadsId);
21669
21670            //lets make a mess!
21671            if(all){
21672                destroyStructure();
21673            }
21674        }
21675
21676        /*
21677        * Removes inline styles added by fullpage.js
21678        */
21679        function destroyStructure(){
21680            //reseting the `top` or `translate` properties to 0
21681            silentScroll(0);
21682
21683            //loading all the lazy load content
21684            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
21685                setSrc($(this), 'src');
21686            });
21687
21688            container.find('img[data-srcset]').each(function(){
21689                setSrc($(this), 'srcset');
21690            });
21691
21692            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
21693
21694            //removing inline styles
21695            $(SECTION_SEL).css( {
21696                'height': '',
21697                'background-color' : '',
21698                'padding': ''
21699            });
21700
21701            $(SLIDE_SEL).css( {
21702                'width': ''
21703            });
21704
21705            container.css({
21706                'height': '',
21707                'position': '',
21708                '-ms-touch-action': '',
21709                'touch-action': ''
21710            });
21711
21712            $htmlBody.css({
21713                'overflow': '',
21714                'height': ''
21715            });
21716
21717            // remove .fp-enabled class
21718            $('html').removeClass(ENABLED);
21719
21720            // remove .fp-responsive class
21721            $body.removeClass(RESPONSIVE);
21722
21723            // remove all of the .fp-viewing- classes
21724            $.each($body.get(0).className.split(/\s+/), function (index, className) {
21725                if (className.indexOf(VIEWING_PREFIX) === 0) {
21726                    $body.removeClass(className);
21727                }
21728            });
21729
21730            //removing added classes
21731            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
21732                options.scrollOverflowHandler.remove($(this));
21733                $(this).removeClass(TABLE + ' ' + ACTIVE);
21734            });
21735
21736            removeAnimation(container);
21737
21738            //Unwrapping content
21739            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
21740                //unwrap not being use in case there's no child element inside and its just text
21741                $(this).replaceWith(this.childNodes);
21742            });
21743
21744            //removing the applied transition from the fullpage wrapper
21745            container.css({
21746                '-webkit-transition': 'none',
21747                'transition': 'none'
21748            });
21749
21750            //scrolling the page to the top with no animation
21751            $htmlBody.scrollTop(0);
21752
21753            //removing selectors
21754            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
21755            $.each(usedSelectors, function(index, value){
21756                $('.' + value).removeClass(value);
21757            });
21758        }
21759
21760        /*
21761        * Sets the state for a variable with multiple states (original, and temporal)
21762        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
21763        * This function is used to keep track of both states, the original and the temporal one.
21764        * If type is not 'internal', then we assume the user is globally changing the variable.
21765        */
21766        function setVariableState(variable, value, type){
21767            options[variable] = value;
21768            if(type !== 'internal'){
21769                originals[variable] = value;
21770            }
21771        }
21772
21773        /**
21774        * Displays warnings
21775        */
21776        function displayWarnings(){
21777            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
21778            //UNCODE.addition
21779            // if($('html').hasClass(ENABLED)){
21780            //     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
21781            //     return;
21782            // }
21783
21784            // Disable mutually exclusive settings
21785            //UNCODE.addition
21786            // if (options.continuousVertical &&
21787            //     (options.loopTop || options.loopBottom)) {
21788            //     options.continuousVertical = false;
21789            //     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
21790            // }
21791
21792            // if(options.scrollBar && options.scrollOverflow){
21793            //     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
21794            // }
21795
21796            // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
21797            //     options.continuousVertical = false;
21798            //     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
21799            // }
21800
21801            //using extensions? Wrong file!
21802            $.each(extensions, function(index, extension){
21803                //is the option set to true?
21804                if(options[extension]){
21805                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
21806                }
21807            });
21808
21809            //anchors can not have the same value as any element ID or NAME
21810            $.each(options.anchors, function(index, name){
21811
21812                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
21813                var nameAttr = $document.find('[name]').filter(function() {
21814                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
21815                });
21816
21817                var idAttr = $document.find('[id]').filter(function() {
21818                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
21819                });
21820
21821                if(idAttr.length || nameAttr.length ){
21822                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
21823                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
21824                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
21825                }
21826            });
21827        }
21828
21829        /**
21830        * Shows a message in the console of the given type.
21831        */
21832        function showError(type, text){
21833            console && console[type] && console[type]('fullPage: ' + text);
21834        }
21835
21836    }; //end of $.fn.fullpage
21837
21838    if(typeof IScroll !== 'undefined'){
21839        /*
21840        * Turns iScroll `mousewheel` option off dynamically
21841        * https://github.com/cubiq/iscroll/issues/1036
21842        */
21843        IScroll.prototype.wheelOn = function () {
21844            this.wrapper.addEventListener('wheel', this);
21845            this.wrapper.addEventListener('mousewheel', this);
21846            this.wrapper.addEventListener('DOMMouseScroll', this);
21847        };
21848
21849        /*
21850        * Turns iScroll `mousewheel` option on dynamically
21851        * https://github.com/cubiq/iscroll/issues/1036
21852        */
21853        IScroll.prototype.wheelOff = function () {
21854            this.wrapper.removeEventListener('wheel', this);
21855            this.wrapper.removeEventListener('mousewheel', this);
21856            this.wrapper.removeEventListener('DOMMouseScroll', this);
21857        };
21858    }
21859
21860    /**
21861     * An object to handle overflow scrolling.
21862     * This uses jquery.slimScroll to accomplish overflow scrolling.
21863     * It is possible to pass in an alternate scrollOverflowHandler
21864     * to the fullpage.js option that implements the same functions
21865     * as this handler.
21866     *
21867     * @type {Object}
21868     */
21869    var iscrollHandler = {
21870        refreshId: null,
21871        iScrollInstances: [],
21872
21873        // Enables or disables the mouse wheel for the active section or all slides in it
21874        toggleWheel: function(value){
21875            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
21876            scrollable.each(function(){
21877                var iScrollInstance = $(this).data('iscrollInstance');
21878                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
21879                    if(value){
21880                        iScrollInstance.wheelOn();
21881                    }
21882                    else{
21883                        iScrollInstance.wheelOff();
21884                    }
21885                }
21886            });
21887        },
21888
21889        /**
21890        * Turns off iScroll for the destination section.
21891        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
21892        * scroll the destination section/slide before the sections animations ends.
21893        */
21894        onLeave: function(){
21895            iscrollHandler.toggleWheel(false);
21896        },
21897
21898        // Turns off iScroll for the leaving section
21899        beforeLeave: function(){
21900            iscrollHandler.onLeave()
21901        },
21902
21903        // Turns on iScroll on section load
21904        afterLoad: function(){
21905            iscrollHandler.toggleWheel(true);
21906        },
21907
21908        /**
21909         * Called when overflow scrolling is needed for a section.
21910         *
21911         * @param  {Object} element      jQuery object containing current section
21912         * @param  {Number} scrollHeight Current window height in pixels
21913         */
21914        create: function(element, scrollHeight) {
21915            var scrollable = element.find(SCROLLABLE_SEL);
21916
21917            scrollable.height(scrollHeight);
21918            scrollable.each(function() {
21919                var $this = $(this);
21920                var iScrollInstance = $this.data('iscrollInstance');
21921                if (iScrollInstance) {
21922                    $.each(iscrollHandler.iScrollInstances, function(){
21923                        $(this).destroy();
21924                    });
21925                }
21926
21927                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
21928                iscrollHandler.iScrollInstances.push(iScrollInstance);
21929
21930                //off by default until the section gets active
21931                iScrollInstance.wheelOff();
21932
21933                $this.data('iscrollInstance', iScrollInstance);
21934            });
21935        },
21936
21937        /**
21938         * Return a boolean depending on whether the scrollable element is a
21939         * the end or at the start of the scrolling depending on the given type.
21940         *
21941         * @param  {String}  type       Either 'top' or 'bottom'
21942         * @param  {Object}  scrollable jQuery object for the scrollable element
21943         * @return {Boolean}
21944         */
21945        isScrolled: function(type, scrollable) {
21946            var scroller = scrollable.data('iscrollInstance');
21947
21948            //no scroller?
21949            if (!scroller) {
21950                return true;
21951            }
21952
21953            if (type === 'top') {
21954                return scroller.y >= 0 && !scrollable.scrollTop();
21955            } else if (type === 'bottom') {
21956                return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
21957            }
21958        },
21959
21960        /**
21961         * Returns the scrollable element for the given section.
21962         * If there are landscape slides, will only return a scrollable element
21963         * if it is in the active slide.
21964         *
21965         * @param  {Object}  activeSection jQuery object containing current section
21966         * @return {Boolean}
21967         */
21968        scrollable: function(activeSection){
21969            // if there are landscape slides, we check if the scrolling bar is in the current one or not
21970            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
21971                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
21972            }
21973            return activeSection.find(SCROLLABLE_SEL);
21974        },
21975
21976        /**
21977         * Returns the scroll height of the wrapped content.
21978         * If this is larger than the window height minus section padding,
21979         * overflow scrolling is needed.
21980         *
21981         * @param  {Object} element jQuery object containing current section
21982         * @return {Number}
21983         */
21984        scrollHeight: function(element) {
21985            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
21986        },
21987
21988        /**
21989         * Called when overflow scrolling is no longer needed for a section.
21990         *
21991         * @param  {Object} element      jQuery object containing current section
21992         */
21993        remove: function(element) {
21994            var scrollable = element.find(SCROLLABLE_SEL);
21995            if (scrollable.length) {
21996                var iScrollInstance = scrollable.data('iscrollInstance');
21997                iScrollInstance.destroy();
21998
21999                scrollable.data('iscrollInstance', null);
22000            }
22001            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
22002        },
22003
22004        /**
22005         * Called when overflow scrolling has already been setup but the
22006         * window height has potentially changed.
22007         *
22008         * @param  {Object}
vendor: 16,384 bytes, lines 22008-22555
22008 element      jQuery object containing current section
22009         * @param  {Number} scrollHeight Current window height in pixels
22010         */
22011        update: function(element, scrollHeight) {
22012            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
22013            //short period of time.
22014            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
22015            clearTimeout(iscrollHandler.refreshId);
22016            iscrollHandler.refreshId = setTimeout(function(){
22017                $.each(iscrollHandler.iScrollInstances, function(){
22018                    $(this).get(0).refresh();
22019                });
22020            }, 150);
22021
22022            //updating the wrappers height
22023            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
22024        },
22025
22026        /**
22027         * Called to get any additional elements needed to wrap the section
22028         * content in order to facilitate overflow scrolling.
22029         *
22030         * @return {String|Object} Can be a string containing HTML,
22031         *                         a DOM element, or jQuery object.
22032         */
22033        wrapContent: function() {
22034            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
22035        }
22036    };
22037});
22038
22039
22040
22041/* ========================================================================
22042 * Bootstrap: collapse.js v3.1.1
22043 * http://getbootstrap.com/javascript/#collapse
22044 * ========================================================================
22045 * Copyright 2011-2014 Twitter, Inc.
22046 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22047 * ======================================================================== */
22048
22049
22050+function ($) {
22051  'use strict';
22052
22053  // COLLAPSE PUBLIC CLASS DEFINITION
22054  // ================================
22055
22056  var Collapse = function (element, options) {
22057    this.$element      = $(element)
22058    this.options       = $.extend({}, Collapse.DEFAULTS, options)
22059    this.transitioning = null
22060
22061    if (this.options.parent) this.$parent = $(this.options.parent)
22062    if (this.options.toggle) this.toggle()
22063  }
22064
22065  Collapse.DEFAULTS = {
22066    toggle: true
22067  }
22068
22069  Collapse.prototype.dimension = function () {
22070    var hasWidth = this.$element.hasClass('width')
22071    return hasWidth ? 'width' : 'height'
22072  }
22073
22074  Collapse.prototype.show = function () {
22075    if (this.transitioning || this.$element.hasClass('in')) return
22076
22077    var startEvent = $.Event('show.bs.collapse')
22078    this.$element.trigger(startEvent)
22079    if (startEvent.isDefaultPrevented()) return
22080
22081    var actives = this.$parent && this.$parent.find('> .panel > .in')
22082
22083    if (actives && actives.length) {
22084      var hasData = actives.data('bs.collapse')
22085      if (hasData && hasData.transitioning) return
22086      actives.collapse('hide')
22087      hasData || actives.data('bs.collapse', null)
22088    }
22089
22090    var dimension = this.dimension()
22091
22092    this.$element
22093      .removeClass('collapse')
22094      .addClass('collapsing')[dimension](0)
22095
22096    this.transitioning = 1
22097
22098    var complete = function (e) {
22099      if (e && e.target != this.$element[0]) return
22100      this.$element
22101        .removeClass('collapsing')
22102        .addClass('collapse in')[dimension]('auto')
22103      this.transitioning = 0
22104      this.$element.trigger('shown.bs.collapse')
22105    }
22106
22107    if (!$.support.transition) return complete.call(this)
22108
22109    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
22110
22111    this.$element
22112      .one($.support.transition.end, $.proxy(complete, this))
22113      .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
22114  }
22115
22116  Collapse.prototype.hide = function () {
22117    if (this.transitioning || !this.$element.hasClass('in')) return
22118
22119    var startEvent = $.Event('hide.bs.collapse')
22120    this.$element.trigger(startEvent)
22121    if (startEvent.isDefaultPrevented()) return
22122
22123    var dimension = this.dimension()
22124
22125    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
22126
22127    this.$element
22128      .addClass('collapsing')
22129      .removeClass('collapse')
22130      .removeClass('in')
22131
22132    this.transitioning = 1
22133
22134    var complete = function (e) {
22135      if (e && e.target != this.$element[0]) return
22136      this.transitioning = 0
22137      this.$element
22138        .trigger('hidden.bs.collapse')
22139        .removeClass('collapsing')
22140        .addClass('collapse')
22141    }
22142
22143    if (!$.support.transition) return complete.call(this)
22144
22145    this.$element
22146      [dimension](0)
22147      .one($.support.transition.end, $.proxy(complete, this))
22148      .emulateTransitionEnd(350)
22149  }
22150
22151  Collapse.prototype.toggle = function () {
22152    this[this.$element.hasClass('in') ? 'hide' : 'show']()
22153  }
22154
22155
22156  // COLLAPSE PLUGIN DEFINITION
22157  // ==========================
22158
22159  var old = $.fn.collapse
22160
22161  $.fn.collapse = function (option) {
22162    return this.each(function () {
22163      var $this   = $(this)
22164      var data    = $this.data('bs.collapse')
22165      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
22166
22167      if (!data && options.toggle && option == 'show') option = !option
22168      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
22169      if (typeof option == 'string') data[option]()
22170    })
22171  }
22172
22173  $.fn.collapse.Constructor = Collapse
22174
22175
22176  // COLLAPSE NO CONFLICT
22177  // ====================
22178
22179  $.fn.collapse.noConflict = function () {
22180    $.fn.collapse = old
22181    return this
22182  }
22183
22184
22185  // COLLAPSE DATA-API
22186  // =================
22187
22188  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
22189    var $this   = $(this), href
22190    var target  = $this.attr('data-target')
22191        || e.preventDefault()
22192        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
22193    //Edited by Uncode to replace ID in panel [START]
22194    var _target = href.replace(/^#/, "");
22195    if ( $('[data-id="' + _target + '"]').length ) {
22196      var $target = $('[data-id="' + _target + '"]')
22197    } else {
22198      var $target = $(target)
22199    }
22200    //Edited by Uncode to replace ID in panel [END]
22201    var data    = $target.data('bs.collapse')
22202    var option  = data ? 'toggle' : $this.data()
22203    var parent  = $this.attr('data-parent')
22204    var $parent = parent && $(parent)
22205
22206    if (!data || !data.transitioning) {
22207      if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
22208      $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
22209    }
22210
22211    $target.collapse(option)
22212  })
22213
22214}(jQuery);
22215
22216
22217/* ========================================================================
22218 * Bootstrap: tab.js v3.1.1
22219 * http://getbootstrap.com/javascript/#tabs
22220 * ========================================================================
22221 * Copyright 2011-2014 Twitter, Inc.
22222 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22223 * ======================================================================== */
22224
22225
22226+function ($) {
22227  'use strict';
22228
22229  // TAB CLASS DEFINITION
22230  // ====================
22231
22232  var Tab = function (element) {
22233    this.element = $(element)
22234  }
22235
22236  Tab.prototype.show = function () {
22237    var $this    = this.element
22238    var $ul      = $this.closest('ul:not(.dropdown-menu)')
22239    var selector = $this.data('target')
22240
22241    if (!selector) {
22242      selector = $this.attr('href')
22243      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
22244    }
22245
22246    if ($this.parent('li').hasClass('active')) return
22247
22248    var previous = $ul.find('.active:last a')[0]
22249    var e        = $.Event('show.bs.tab', {
22250      relatedTarget: previous
22251    })
22252
22253    $this.trigger(e)
22254
22255    if (e.isDefaultPrevented()) return
22256
22257    //Edited by Uncode to replace ID in panel [START]
22258    var _target = selector.replace(/^#/, "");
22259    if ( $('[data-id="' + _target + '"]').length )
22260      var $target = $('[data-id="' + _target + '"]')
22261    else
22262      var $target = $(selector)
22263    //Edited by Uncode to replace ID in panel [END]
22264
22265    this.activate($this.parent('li'), $ul)
22266    this.activate($target, $target.parent(), function () {
22267      $this.trigger({
22268        type: 'shown.bs.tab',
22269        relatedTarget: previous
22270      })
22271    })
22272  }
22273
22274  Tab.prototype.activate = function (element, container, callback) {
22275    var $active    = container.find('> .active')
22276    var transition = callback
22277      && $.support.transition
22278      && $active.hasClass('fade')
22279
22280    function next() {
22281      $active
22282        .removeClass('active')
22283        .find('> .dropdown-menu > .active')
22284        .removeClass('active')
22285
22286      element.addClass('active')
22287
22288      if (transition) {
22289        element[0].offsetWidth // reflow for transition
22290        element.addClass('in')
22291      } else {
22292        element.removeClass('fade')
22293      }
22294
22295      if (element.parent('.dropdown-menu')) {
22296        element.closest('li.dropdown').addClass('active')
22297      }
22298
22299      callback && callback()
22300    }
22301
22302    transition ?
22303      $active
22304        .one($.support.transition.end, next)
22305        .emulateTransitionEnd(150) :
22306      next()
22307
22308    $active.removeClass('in')
22309  }
22310
22311
22312  // TAB PLUGIN DEFINITION
22313  // =====================
22314
22315  var old = $.fn.tab
22316
22317  $.fn.tab = function ( option ) {
22318    return this.each(function () {
22319      var $this = $(this)
22320      var data  = $this.data('bs.tab')
22321
22322      if (!data) $this.data('bs.tab', (data = new Tab(this)))
22323      if (typeof option == 'string') data[option]()
22324    })
22325  }
22326
22327  $.fn.tab.Constructor = Tab
22328
22329
22330  // TAB NO CONFLICT
22331  // ===============
22332
22333  $.fn.tab.noConflict = function () {
22334    $.fn.tab = old
22335    return this
22336  }
22337
22338
22339  // TAB DATA-API
22340  // ============
22341
22342  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
22343    e.preventDefault()
22344    $(this).tab('show')
22345  })
22346
22347}(jQuery);
22348
22349
22350/* ========================================================================
22351 * Bootstrap: tooltip.js v3.1.1
22352 * http://getbootstrap.com/javascript/#tooltip
22353 * Inspired by the original jQuery.tipsy by Jason Frame
22354 * ========================================================================
22355 * Copyright 2011-2014 Twitter, Inc.
22356 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22357 * ======================================================================== */
22358
22359
22360+function ($) {
22361  'use strict';
22362
22363  // TOOLTIP PUBLIC CLASS DEFINITION
22364  // ===============================
22365
22366  var Tooltip = function (element, options) {
22367    this.type       =
22368    this.options    =
22369    this.enabled    =
22370    this.timeout    =
22371    this.hoverState =
22372    this.$element   = null
22373
22374    this.init('tooltip', element, options)
22375  }
22376
22377  Tooltip.DEFAULTS = {
22378    animation: true,
22379    placement: 'top',
22380    selector: false,
22381    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
22382    trigger: 'hover focus',
22383    title: '',
22384    delay: 0,
22385    html: false,
22386    container: false,
22387    viewport: {
22388      selector: 'body',
22389      padding: 0
22390    }
22391  }
22392
22393  Tooltip.prototype.init = function (type, element, options) {
22394    this.enabled   = true
22395    this.type      = type
22396    this.$element  = $(element)
22397    this.options   = this.getOptions(options)
22398    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
22399
22400    var triggers = this.options.trigger.split(' ')
22401
22402    for (var i = triggers.length; i--;) {
22403      var trigger = triggers[i]
22404
22405      if (trigger == 'click') {
22406        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
22407      } else if (trigger != 'manual') {
22408        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
22409        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
22410
22411        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
22412        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
22413      }
22414    }
22415
22416    this.options.selector ?
22417      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
22418      this.fixTitle()
22419  }
22420
22421  Tooltip.prototype.getDefaults = function () {
22422    return Tooltip.DEFAULTS
22423  }
22424
22425  Tooltip.prototype.getOptions = function (options) {
22426    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
22427
22428    if (options.delay && typeof options.delay == 'number') {
22429      options.delay = {
22430        show: options.delay,
22431        hide: options.delay
22432      }
22433    }
22434
22435    return options
22436  }
22437
22438  Tooltip.prototype.getDelegateOptions = function () {
22439    var options  = {}
22440    var defaults = this.getDefaults()
22441
22442    this._options && $.each(this._options, function (key, value) {
22443      if (defaults[key] != value) options[key] = value
22444    })
22445
22446    return options
22447  }
22448
22449  Tooltip.prototype.enter = function (obj) {
22450    var self = obj instanceof this.constructor ?
22451      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
22452
22453    clearTimeout(self.timeout)
22454
22455    self.hoverState = 'in'
22456
22457    if (!self.options.delay || !self.options.delay.show) return self.show()
22458
22459    self.timeout = setTimeout(function () {
22460      if (self.hoverState == 'in') self.show()
22461    }, self.options.delay.show)
22462  }
22463
22464  Tooltip.prototype.leave = function (obj) {
22465    var self = obj instanceof this.constructor ?
22466      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
22467
22468    clearTimeout(self.timeout)
22469
22470    self.hoverState = 'out'
22471
22472    if (!self.options.delay || !self.options.delay.hide) return self.hide()
22473
22474    self.timeout = setTimeout(function () {
22475      if (self.hoverState == 'out') self.hide()
22476    }, self.options.delay.hide)
22477  }
22478
22479  Tooltip.prototype.show = function () {
22480    var e = $.Event('show.bs.' + this.type)
22481
22482    if (this.hasContent() && this.enabled) {
22483      this.$element.trigger(e)
22484
22485      if (e.isDefaultPrevented()) return
22486      var that = this;
22487
22488      var $tip = this.tip()
22489
22490      this.setContent()
22491
22492      if (this.options.animation) $tip.addClass('fade')
22493
22494      var placement = typeof this.options.placement == 'function' ?
22495        this.options.placement.call(this, $tip[0], this.$element[0]) :
22496        this.options.placement
22497
22498      var autoToken = /\s?auto?\s?/i
22499      var autoPlace = autoToken.test(placement)
22500      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
22501
22502      $tip
22503        .detach()
22504        .css({ top: 0, left: 0, display: 'block' })
22505        .addClass(placement)
22506
22507      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
22508
22509      var pos          = this.getPosition()
22510      var actualWidth  = $tip[0].offsetWidth
22511      var actualHeight = $tip[0].offsetHeight
22512
22513      if (autoPlace) {
22514        var orgPlacement = placement
22515        var $parent      = this.$element.parent()
22516        var parentDim    = this.getPosition($parent)
22517
22518        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
22519                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
22520                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
22521                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
22522                    placement
22523
22524        $tip
22525          .removeClass(orgPlacement)
22526          .addClass(placement)
22527      }
22528
22529      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
22530
22531      this.applyPlacement(calculatedOffset, placement)
22532      this.hoverState = null
22533
22534      var complete = function() {
22535        that.$element.trigger('shown.bs.' + that.type)
22536      }
22537
22538      $.support.transition && this.$tip.hasClass('fade') ?
22539        $tip
22540          .one($.support.transition.end, complete)
22541          .emulateTransitionEnd(150) :
22542        complete()
22543    }
22544  }
22545
22546  Tooltip.prototype.applyPlacement = function (offset, placement) {
22547    var $tip   = this.tip()
22548    var width  = $tip[0].offsetWidth
22549    var height = $tip[0].offsetHeight
22550
22551    // manually read margins because getBoundingClientRect includes difference
22552    var marginTop = parseInt($tip.css('margin-top'), 10)
22553    var marginLeft = parseInt($tip.css('margin-left'), 10)
22554
22555    // we must check for NaN for i
22555e 8/9
22556    if (isNaN(marginTop))  marginTop  = 0
22557    if (isNaN(marginLeft)) marginLeft = 0
22558
22559    offset.top  = offset.top  + marginTop
22560    offset.left = offset.left + marginLeft
22561
22562    // $.fn.offset doesn't round pixel values
22563    // so we use setOffset directly with our own function B-0
22564    $.offset.setOffset($tip[0], $.extend({
22565      using: function (props) {
22566        $tip.css({
22567          top: Math.round(props.top),
22568          left: Math.round(props.left)
22569        })
22570      }
22571    }, offset), 0)
22572
22573    $tip.addClass('in')
22574
22575    // check to see if placing tip in new offset caused the tip to resize itself
22576    var actualWidth  = $tip[0].offsetWidth
22577    var actualHeight = $tip[0].offsetHeight
22578
22579    if (placement == 'top' && actualHeight != height) {
22580      offset.top = offset.top + height - actualHeight
22581    }
22582
22583    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
22584
22585    if (delta.left) offset.left += delta.left
22586    else offset.top += delta.top
22587
22588    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
22589    var arrowPosition       = delta.left ? 'left'        : 'top'
22590    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
22591
22592    $tip.offset(offset)
22593    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
22594  }
22595
22596  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
22597    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
22598  }
22599
22600  Tooltip.prototype.setContent = function () {
22601    var $tip  = this.tip()
22602    var title = this.getTitle()
22603
22604    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
22605    $tip.removeClass('fade in top bottom left right')
22606  }
22607
22608  Tooltip.prototype.hide = function () {
22609    var that = this
22610    var $tip = this.tip()
22611    var e    = $.Event('hide.bs.' + this.type)
22612
22613    function complete() {
22614      if (that.hoverState != 'in') $tip.detach()
22615      that.$element.trigger('hidden.bs.' + that.type)
22616    }
22617
22618    this.$element.trigger(e)
22619
22620    if (e.isDefaultPrevented()) return
22621
22622    $tip.removeClass('in')
22623
22624    $.support.transition && this.$tip.hasClass('fade') ?
22625      $tip
22626        .one($.support.transition.end, complete)
22627        .emulateTransitionEnd(150) :
22628      complete()
22629
22630    this.hoverState = null
22631
22632    return this
22633  }
22634
22635  Tooltip.prototype.fixTitle = function () {
22636    var $e = this.$element
22637    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
22638      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
22639    }
22640  }
22641
22642  Tooltip.prototype.hasContent = function () {
22643    return this.getTitle()
22644  }
22645
22646  Tooltip.prototype.getPosition = function ($element) {
22647    $element   = $element || this.$element
22648    var el     = $element[0]
22649    var isBody = el.tagName == 'BODY'
22650    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
22651      scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
22652      width:  isBody ? $(window).width()  : $element.outerWidth(),
22653      height: isBody ? $(window).height() : $element.outerHeight()
22654    }, isBody ? {top: 0, left: 0} : $element.offset())
22655  }
22656
22657  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
22658    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
22659           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
22660           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
22661        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
22662
22663  }
22664
22665  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
22666    var delta = { top: 0, left: 0 }
22667    if (!this.$viewport) return delta
22668
22669    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
22670    var viewportDimensions = this.getPosition(this.$viewport)
22671
22672    if (/right|left/.test(placement)) {
22673      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
22674      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
22675      if (topEdgeOffset < viewportDimensions.top) { // top overflow
22676        delta.top = viewportDimensions.top - topEdgeOffset
22677      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
22678        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
22678EdgeOffset
22679      }
22680    } else {
22681      var leftEdgeOffset  = pos.left - viewportPadding
22682      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
22683      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
22684        delta.left = viewportDimensions.left - leftEdgeOffset
22685      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
22686        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
22687      }
22688    }
22689
22690    return delta
22691  }
22692
22693  Tooltip.prototype.getTitle = function () {
22694    var title
22695    var $e = this.$element
22696    var o  = this.options
22697
22698    title = $e.attr('data-original-title')
22699      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
22700
22701    return title
22702  }
22703
22704  Tooltip.prototype.tip = function () {
22705    return this.$tip = this.$tip || $(this.options.template)
22706  }
22707
22708  Tooltip.prototype.arrow = function () {
22709    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
22710  }
22711
22712  Tooltip.prototype.validate = function () {
22713    if (!this.$element[0].parentNode) {
22714      this.hide()
22715      this.$element = null
22716      this.options  = null
22717    }
22718  }
22719
22720  Tooltip.prototype.enable = function () {
22721    this.enabled = true
22722  }
22723
22724  Tooltip.prototype.disable = function () {
22725    this.enabled = false
22726  }
22727
22728  Tooltip.prototype.toggleEnabled = function () {
22729    this.enabled = !this.enabled
22730  }
22731
22732  Tooltip.prototype.toggle = function (e) {
22733    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
22734    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
22735  }
22736
22737  Tooltip.prototype.destroy = function () {
22738    clearTimeout(this.timeout)
22739    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
22740  }
22741
22742
22743  // TOOLTIP PLUGIN DEFINITION
22744  // =========================
22745
22746  var old = $.fn.tooltip
22747
22748  $.fn.tooltip = function (option) {
22749    return this.each(function () {
22750      var $this   = $(this)
22751      var data    = $this.data('bs.tooltip')
22752      var options = typeof option == 'object' && option
22753
22754      if (!data && option == 'destroy') return
22755      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
22756      if (typeof option == 'string') data[option]()
22757    })
22758  }
22759
22760  $.fn.tooltip.Constructor = Tooltip
22761
22762
22763  // TOOLTIP NO CONFLICT
22764  // ===================
22765
22766  $.fn.tooltip.noConflict = function () {
22767    $.fn.tooltip = old
22768    return this
22769  }
22770
22771}(jQuery);
22772
22773
22774/* ========================================================================
22775 * Bootstrap: transition.js v3.1.1
22776 * http://getbootstrap.com/javascript/#transitions
22777 * ========================================================================
22778 * Copyright 2011-2014 Twitter, Inc.
22779 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22780 * ======================================================================== */
22781
22782
22783+function ($) {
22784  'use strict';
22785
22786  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
22787  // ============================================================
22788
22789  function transitionEnd() {
22790    var el = document.createElement('bootstrap')
22791
22792    var transEndEventNames = {
22793      WebkitTransition : 'webkitTransitionEnd',
22794      MozTransition    : 'transitionend',
22795      OTransition      : 'oTransitionEnd otransitionend',
22796      transition       : 'transitionend'
22797    }
22798
22799    for (var name in transEndEventNames) {
22800      if (el.style[name] !== undefined) {
22801        return { end: transEndEventNames[name] }
22802      }
22803    }
22804
22805    return false // explicit for ie8 (  ._.)
22806  }
22807
22808  // http://blog.alexmaccaw.com/css-transitions
22809  $.fn.emulateTransitionEnd = function (duration) {
22810    var called = false, $el = this
22811    $(this).one($.support.transition.end, function () { called = true })
22812    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
22813    setTimeout(callback, duration)
22814    return this
22815  }
22816
22817  $(function () {
22818    $.support.transition = transitionEnd()
22819  })
22820
22821}(jQuery);
22822
22823

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.