PageSourceSearch

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

js sdacneclinic.com collected 2026-10-05 06:41:42 UTC 782,599 bytes, 22,845 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-double').length ) {
6139						leftPos = '0px';
6140					} else {
6141						if ( $('body.hmenu-center-split').length > 0 && !$sub.closest('.navbar-cta').length && ! $('body.hormenu-position-right').length ) {
6142							leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px';
6143						} else {
6144							if ( $sub.closest('.navbar-cta').length && !$('body.hmenu').length && !$('body.hmenu-center').length ) {
6145								leftPos = - ( parseFloat($sub.closest('.navbar-cta').offset().left) - parseFloat($sub.closest('.row-menu-inner').find('.logo-container').offset().left) ) + 'px';
6146							} else if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0 && !$('body.hmenu-center-split').length) {
6147								leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px';
6148							} else {
6149								leftPos = '0px';
6150							}
6151						}
6152					}
6153				} else {
6154					leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px';
6155					x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1;
6156				}
6157
6158				$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) });
6159				// IE iframe shim
6160				this.menuIframeShim($sub);
6161				if ($sub.dataSM('ie-shim')) {
6162					$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) });
6163				}
6164			},
6165			menuScroll: function($sub, up, wheel) {
6166				var y = parseFloat($sub.css('margin-top')),
6167					scroll = $sub.dataSM('scroll'),
6168					end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH),
6169					step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
6170				$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
6171				y = parseFloat($sub.css('margin-top'));
6172				// show opposite arrow if appropriate
6173				if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
6174					$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
6175				}
6176				// accelerate when not using mousewheel to scroll
6177				if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
6178					$sub.dataSM('scroll').step += 0.5;
6179				}
6180				// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
6181				if (Math.abs(y - end) < 1) {
6182					$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
6183					$sub.dataSM('scroll').step = 1;
6184				} else if (!wheel) {
6185					var self = this;
6186					this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
6187				}
6188			},
6189			menuScrollMousewheel: function($sub, e) {
6190				var $closestSub = $(e.target).closest('ul');
6191				while ($closestSub.dataSM('in-mega')) {
6192					$closestSub = $closestSub.parent().closest('ul');
6193				}
6194				if ($closestSub[0] == $sub[0]) {
6195					var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
6196					if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
6197						this.menuScroll($sub, up, true);
6198					}
6199				}
6200				e.preventDefault();
6201			},
6202			menuScrollOut: function($sub, e) {
6203				var reClass = /^scroll-(up|down)/,
6204					$closestSub = $(e.relatedTarget).closest('ul');
6205				while ($closestSub.dataSM('in-mega')) {
6206					$closestSub = $closestSub.parent().closest('ul');
6207				}
6208				if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
6209					$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
6210				}
6211			},
6212			menuScrollOver: function($sub, e) {
6213				var reClass = /^scroll-(up|down)/,
6214					$closestSub = $(e.target).closest('ul');
6215				while ($closestSub.dataSM('in-mega')) {
6216					$closestSub = $closestSub.parent().closest('ul');
6217				}
6218				if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
6219					$sub.dataSM('scroll-arrows').css('visibility', 'visible');
6220				}
6221			},
6222			menuScrollStop: function($sub) {
6223				if (this.scrollTimeout) {
6224					clearTimeout(this.scrollTimeout);
6225					this.scrollTimeout = 0;
6226					$sub.dataSM('scroll').step = 1;
6227				}
6228			},
6229			menuShow: function($sub) {
6230				if (!$sub.dataSM('beforefirstshowfired')) {
6231					$sub.dataSM('beforefirstshowfired', true);
6232					if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
6233						return;
6234					}
6235				}
6236				if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
6237					return;
6238				}
6239				this.menuFixLayout($sub);
6240				$sub.stop(true, true);
6241				if (!$sub.is(':visible')) {
6242					// set z-index - for IE < 9 set it to the parent LI
6243					var zIndex = this.getStartZIndex() + (++this.zIndexInc);
6244					if (IElt9) {
6245						$sub.parent().css('z-index', zIndex);
6246					} else {
6247						$sub.css('z-index', zIndex);
6248					}
6249					// highlight parent item
6250					if (this.opts.keepHighlighted || this.isCollapsible()) {
6251						if ($sub.dataSM('parent-a').attr('data-type') != 'title')
6252							$sub.dataSM('parent-a').addClass('highlighted');
6253					}
6254					// min/max-width fix - no way to rely purely on CSS as all UL's are nested
6255					if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
6256						if (!IElt8) {
6257							$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
6258							if (this.opts.subMenusMinWidth) {
6259							 	$sub.css('min-width', this.opts.subMenusMinWidth);
6260							}
6261							if (this.opts.subMenusMaxWidth) {
6262							 	var noMaxWidth = this.getWidth($sub);
6263							 	$sub.css('max-width', this.opts.subMenusMaxWidth);
6264								if (noMaxWidth > this.getWidth($sub)) {
6265									$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
6266								}
6267							}
6268						// IE6,7
6269 						} else {
6270							$sub.children().css('styleFloat', 'none');
6271							if (IE6) {
6272								$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
6273									.children().children('a').css('white-space', 'nowrap');
6274							} else { // IE7
6275								$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
6276								if (this.opts.subMenusMinWidth) {
6277							    $sub.css('min-width', this.opts.subMenusMinWidth);
6278								}
6279							}
6280							if (this.opts.subMenusMaxWidth) {
6281								var noMaxWidth = $sub.width();
6282								if (IE6) {
6283							 		var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
6284									if (noMaxWidth > maxWidth) {
6285										$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
6286									} else {
6287										$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
6288									}
6289								} else { // IE7
6290									$sub.css('max-width', this.opts.subMenusMaxWidth);
6291									if (noMaxWidth > $sub.width()) {
6292										$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
6293									} else {
6294										$sub.width(noMaxWidth);
6295									}
6296								}
6297							} else {
6298							 	$sub.width($sub.width());
6299							}
6300							$sub.children().css('styleFloat', 'left');
6301						}
6302					}
6303					this.menuPosition($sub);
6304					// insert IE iframe shim
6305					if ($sub.dataSM('ie-shim')) {
6306						$sub.dataSM('ie-shim').insertBefore($sub);
6307					}
6308					var complete = function() {
6309						// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
6310						$sub.css('overflow', '');
6311					};
6312					// if sub is collapsible (mobile view)
6313					if (this.isCollapsible()) {
6314						if (this.opts.collapsibleShowFunction) {
6315							this.opts.collapsibleShowFunction.call(this, $sub, complete);
6316						} else {
6317							$sub.show(this.opts.collapsibleShowDuration, complete);
6318						}
6319					} else {
6320						if (this.opts.showFunction) {
6321							this.opts.showFunction.call(this, $sub, complete);
6322						} else {
6323							$sub.show(this.opts.showDuration, complete);
6324						}
6325					}
6326					// save new sub menu for this level
6327					this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
6328					this.$root.triggerHandler('show.smapi', $sub[0]);
6329				}
6330			},
6331			popupHide: function(noHideTimeout) {
6332				if (this.hideTimeout) {
6333					clearTimeout(this.hideTimeout);
6334					this.hideTimeout = 0;
6335				}
6336				var self = this;
6337				this.hideTimeout = setTimeout(function() {
6338					self.menuHideAll();
6339				}, noHideTimeout ? 1 : this.opts.hideTimeout);
6340			},
6341			popupShow: function(left, top) {
6342				if (!this.opts.isPopup) {
6343					alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
6344					return;
6345				}
6346				if (this.hideTimeout) {
6347					clearTimeout(this.hideTimeout);
6348					this.hideTimeout = 0;
6349				}
6350				this.menuFixLayout(this.$root);
6351				this.$root.stop(true, true);
6352				if (!this.$root.is(':visible')) {
6353					this.$root.css({ left: left, top: top });
6354					// IE iframe shim
6355					this.menuIframeShim(this.$root);
6356					if (this.$root.dataSM('ie-shim')) {
6357						this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
6357: left, top: top }).insertBefore(this.$root);
6358					}
6359					// show menu
6360					if (this.opts.showFunction) {
6361						this.opts.showFunction.call(this, this.$root);
6362					} else {
6363						this.$root.show(this.opts.showDuration);
6364					}
6365					this.visibleSubMenus[0] = this.$root;
6366				}
6367			},
6368			refresh: function() {
6369				this.menuHideAll();
6370				this.$root.find('ul').each(function() {
6371						var $this = $(this);
6372						if ($this.dataSM('scroll-arrows')) {
6373							$this.dataSM('scroll-arrows').remove();
6374						}
6375					})
6376					.removeDataSM('in-mega')
6377					.removeDataSM('shown-before')
6378					.removeDataSM('ie-shim')
6379					.removeDataSM('scroll-arrows')
6380					.removeDataSM('parent-a')
6381					.removeDataSM('level')
6382					.removeDataSM('beforefirstshowfired');
6383				this.$root.find('a.has-submenu').removeClass('has-submenu')
6384					.parent().removeDataSM('sub');
6385				if (this.opts.subIndicators) {
6386					this.$root.find('span.sub-arrow').remove();
6387				}
6388				if (this.opts.markCurrentItem) {
6389					this.$root.find('a.current').removeClass('current');
6390				}
6391				this.subMenus = [];
6392				this.init(true);
6393			},
6394			rootOut: function(e) {
6395				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
6396					return;
6397				}
6398				if (this.hideTimeout) {
6399					clearTimeout(this.hideTimeout);
6400					this.hideTimeout = 0;
6401				}
6402				if (!this.opts.showOnClick || !this.opts.hideOnClick) {
6403					var self = this;
6404					this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
6405				}
6406			},
6407			rootOver: function(e) {
6408				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
6409					return;
6410				}
6411				if (this.hideTimeout) {
6412					clearTimeout(this.hideTimeout);
6413					this.hideTimeout = 0;
6414				}
6415			},
6416			winResize: function(e) {
6417				if (!this.handleEvents()) {
6418					// we still need to resize the disable overlay if it's visible
6419					if (this.$disableOverlay) {
6420						var pos = this.$root.offset();
6421	 					this.$disableOverlay.css({
6422							top: pos.top,
6423							left: pos.left,
6424							width: this.$root.outerWidth(),
6425							height: this.$root.outerHeight()
6426						});
6427					}
6428					return;
6429				}
6430				// hide sub menus on resize - on mobile do it only on orientation change
6431				if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
6432					if (this.activatedItems.length) {
6433						this.activatedItems[this.activatedItems.length - 1][0].blur();
6434					}
6435					this.menuHideAll();
6436				}
6437			}
6438		}
6439	});
6440
6441	$.fn.dataSM = function(key, val) {
6442		if (val) {
6443			return this.data(key + '_smartmenus', val);
6444		}
6445		return this.data(key + '_smartmenus');
6446	}
6447
6448	$.fn.removeDataSM = function(key) {
6449		return this.removeData(key + '_smartmenus');
6450	}
6451
6452	$.fn.smartmenus = function(options) {
6453		if (typeof options == 'string') {
6454			var args = arguments,
6455				method = options;
6456			Array.prototype.shift.call(args);
6457			return this.each(function() {
6458				var smartmenus = $(this).data('smartmenus');
6459				if (smartmenus && smartmenus[method]) {
6460					smartmenus[method].apply(smartmenus, args);
6461				}
6462			});
6463		}
6464		var opts = $.extend({}, $.fn.smartmenus.defaults, options);
6465		return this.each(function() {
6466			new $.SmartMenus(this, opts);
6467		});
6468	}
6469
6470	// default settings
6471	$.fn.smartmenus.defaults = {
6472		isPopup:		false,		// is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
6473		mainMenuSubOffsetX:	0,		// pixels offset from default position
6474		mainMenuSubOffsetY:	0,		// pixels offset from default position
6475		subMenusSubOffsetX:	0,		// pixels offset from default position
6476		subMenusSubOffsetY:	0,		// pixels offset from default position
6477		subMenusMinWidth:	'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
6478		subMenusMaxWidth:	'20em',		// max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
6479		subIndicators: 		true,		// create sub menu indicators - creates a SPAN and inserts it in the A
6480		subIndicatorsPos: 	'prepend',	// position of the SPAN relative to the menu item content ('prepend', 'append')
6481		subIndicatorsText:	'+',		// [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
6482		scrollStep: 		30,		// pixels step when scrolling long sub menus that do not fit in the viewport height
6483		scrollInterval:		30,		// interval between each scrolling step
6484		scrollAccelerate:	true,		// accelerate scrolling or use a fixed step
6485		showTimeout:		250,		// timeout before showing the sub menus
6486		hideTimeout:		500,		// timeout before hiding the sub menus
6487		showDuration:		0,		// duration for show animation - set to 0 for no animation - matters only if showFunction:null
6488		showFunction:		null,		// custom function to use when showing a sub menu (the default is the jQuery 'show')
6489							// don't forget to call complete() at the end of whatever you do
6490							// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
6491		hideDuration:		0,		// duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
6492		hideFunction:		function($ul, complete) { $ul.fadeOut(200, complete); },	// custom function to use when hiding a sub menu (the default is the jQuery 'hide')
6493							// don't forget to call complete() at the end of whatever you do
6494							// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
6495		collapsibleShowDuration:0,		// duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
6496		collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); },	// custom function to use when showing a collapsible sub menu
6497							// (i.e. when mobile styles are used to make the sub menus collapsible)
6498		collapsibleHideDuration:0,		// duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
6499		collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); },	// custom function to use when hiding a collapsible sub menu
6500							// (i.e. when mobile styles are used to make the sub menus collapsible)
6501		showOnClick:		false,		// show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
6502		hideOnClick:		true,		// hide the sub menus on click/tap anywhere on the page
6503		keepInViewport:		true,		// reposition the sub menus if needed to make sure they always appear inside the viewport
6504		keepHighlighted:	true,		// keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
6505		markCurrentItem:	false,		// automatically add the 'current' class to the A element of the item linking to the current URL
6506		markCurrentTree:	true,		// add the 'current' class also to the A elements of all ancestor items of the current item
6507		rightToLeftSubMenus:	false,		// right to left display of the sub menus (check the CSS for the sub indicators' position)
6508		bottomToTopSubMenus:	false,		// bottom to top display of the sub menus
6509		overlapControlsInIE:	true		// make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
6510	};
6511
6512})(jQuery);
6513
6514/*
6515 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
6516 *
6517 * Uses the built in easing capabilities added In jQuery 1.1
6518 * to offer multiple easing options
6519 *
6520 * TERMS OF USE - jQuery Easing
6521 * 
6522 * Open source under the BSD License.
6523 * 
6524 * Copyright © 2008 George McGinley Smith
6525 * All rights reserved.
6526 * 
6527 * Redistribution and use in source and binary forms, with or without modification, 
6528 * are permitted provided that the following conditions are met:
6529 * 
6530 * Redistributions of source code must retain the above copyright notice, this list of 
6531 * conditions and the following disclaimer.
6532 * Redistributions in binary form must reproduce the above copyright notice, this list 
6533 * of conditions and the following disclaimer in the documentation and/or other materials 
6534 * provided with the distribution.
6535 * 
6536 * Neither the name of the author nor the names of contributors may be used to endorse 
6537 * or promote products derived from this software without specific prior written permission.
6538 * 
6539 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
6540 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
6541 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
6542 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
vendor: 5,091 bytes, lines 6543-6688
6543 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
6544 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
6545 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6546 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
6547 * OF THE POSSIBILITY OF SUCH DAMAGE. 
6548 *
6549*/
6550
6551// t: current time, b: begInnIng value, c: change In value, d: duration
6552jQuery.easing['jswing'] = jQuery.easing['swing'];
6553
6554jQuery.extend( jQuery.easing,
6555{
6556	def: 'easeOutQuad',
6557	swing: function (x, t, b, c, d) {
6558		//alert(jQuery.easing.default);
6559		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
6560	},
6561	easeInQuad: function (x, t, b, c, d) {
6562		return c*(t/=d)*t + b;
6563	},
6564	easeOutQuad: function (x, t, b, c, d) {
6565		return -c *(t/=d)*(t-2) + b;
6566	},
6567	easeInOutQuad: function (x, t, b, c, d) {
6568		if ((t/=d/2) < 1) return c/2*t*t + b;
6569		return -c/2 * ((--t)*(t-2) - 1) + b;
6570	},
6571	easeInCubic: function (x, t, b, c, d) {
6572		return c*(t/=d)*t*t + b;
6573	},
6574	easeOutCubic: function (x, t, b, c, d) {
6575		return c*((t=t/d-1)*t*t + 1) + b;
6576	},
6577	easeInOutCubic: function (x, t, b, c, d) {
6578		if ((t/=d/2) < 1) return c/2*t*t*t + b;
6579		return c/2*((t-=2)*t*t + 2) + b;
6580	},
6581	easeInQuart: function (x, t, b, c, d) {
6582		return c*(t/=d)*t*t*t + b;
6583	},
6584	easeOutQuart: function (x, t, b, c, d) {
6585		return -c * ((t=t/d-1)*t*t*t - 1) + b;
6586	},
6587	easeInOutQuart: function (x, t, b, c, d) {
6588		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
6589		return -c/2 * ((t-=2)*t*t*t - 2) + b;
6590	},
6591	easeInQuint: function (x, t, b, c, d) {
6592		return c*(t/=d)*t*t*t*t + b;
6593	},
6594	easeOutQuint: function (x, t, b, c, d) {
6595		return c*((t=t/d-1)*t*t*t*t + 1) + b;
6596	},
6597	easeInOutQuint: function (x, t, b, c, d) {
6598		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
6599		return c/2*((t-=2)*t*t*t*t + 2) + b;
6600	},
6601	easeInSine: function (x, t, b, c, d) {
6602		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
6603	},
6604	easeOutSine: function (x, t, b, c, d) {
6605		return c * Math.sin(t/d * (Math.PI/2)) + b;
6606	},
6607	easeInOutSine: function (x, t, b, c, d) {
6608		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
6609	},
6610	easeInExpo: function (x, t, b, c, d) {
6611		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
6612	},
6613	easeOutExpo: function (x, t, b, c, d) {
6614		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
6615	},
6616	easeInOutExpo: function (x, t, b, c, d) {
6617		if (t==0) return b;
6618		if (t==d) return b+c;
6619		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
6620		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
6621	},
6622	easeInCirc: function (x, t, b, c, d) {
6623		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
6624	},
6625	easeOutCirc: function (x, t, b, c, d) {
6626		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
6627	},
6628	easeInOutCirc: function (x, t, b, c, d) {
6629		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
6630		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
6631	},
6632	easeInElastic: function (x, t, b, c, d) {
6633		var s=1.70158;var p=0;var a=c;
6634		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
6635		if (a < Math.abs(c)) { a=c; var s=p/4; }
6636		else var s = p/(2*Math.PI) * Math.asin (c/a);
6637		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
6638	},
6639	easeOutElastic: function (x, t, b, c, d) {
6640		var s=1.70158;var p=0;var a=c;
6641		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
6642		if (a < Math.abs(c)) { a=c; var s=p/4; }
6643		else var s = p/(2*Math.PI) * Math.asin (c/a);
6644		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
6645	},
6646	easeInOutElastic: function (x, t, b, c, d) {
6647		var s=1.70158;var p=0;var a=c;
6648		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
6649		if (a < Math.abs(c)) { a=c; var s=p/4; }
6650		else var s = p/(2*Math.PI) * Math.asin (c/a);
6651		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
6652		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
6653	},
6654	easeInBack: function (x, t, b, c, d, s) {
6655		if (s == undefined) s = 1.70158;
6656		return c*(t/=d)*t*((s+1)*t - s) + b;
6657	},
6658	easeOutBack: function (x, t, b, c, d, s) {
6659		if (s == undefined) s = 1.70158;
6660		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
6661	},
6662	easeInOutBack: function (x, t, b, c, d, s) {
6663		if (s == undefined) s = 1.70158; 
6664		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
6665		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
6666	},
6667	easeInBounce: function (x, t, b, c, d) {
6668		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
6669	},
6670	easeOutBounce: function (x, t, b, c, d) {
6671		if ((t/=d) < (1/2.75)) {
6672			return c*(7.5625*t*t) + b;
6673		} else if (t < (2/2.75)) {
6674			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
6675		} else if (t < (2.5/2.75)) {
6676			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
6677		} else {
6678			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
6679		}
6680	},
6681	easeInOutBounce: function (x, t, b, c, d) {
6682		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
6683		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
6684	}
6685});
6686
6687/*
6688 *
6689 * TERMS OF USE - EASING EQUATIONS
6690 * 
6691 * Open source under the BSD License. 
6692 * 
6693 * Copyright © 2001 Robert Penner
6694 * All rights reserved.
6695 * 
6696 * Redistribution and use in source and binary forms, with or without modification, 
6697 * are permitted provided that the following conditions are met:
6698 * 
6699 * Redistributions of source code must retain the above copyright notice, this list of 
6700 * conditions and the following disclaimer.
6701 * Redistributions in binary form must reproduce the above copyright notice, this list 
6702 * of conditions and the following disclaimer in the documentation and/or other materials 
6703 * provided with the distribution.
6704 * 
6705 * Neither the name of the author nor the names of contributors may be used to endorse 
6706 * or promote products derived from this software without specific prior written permission.
6707 * 
6708 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
6709 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
6710 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
6711 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
6712 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
6713 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
6714 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6715 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
6716 * OF THE POSSIBILITY OF SUCH DAMAGE. 
6717 *
6718 */
6719
6720(function($, window, undefined) {
6721    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
6722    // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
6723 
6724    // requestAnimationFrame polyfill by Erik Möller
6725    // fixes from Paul Irish and Tino Zijdel
6726 
6727    var lastTime = 0,
6728        running,
6729        animate = function (elem) {
6730            if (running) {
6731                window.requestAnimationFrame(animate, elem);
6732                jQuery.fx.tick();
6733            }
6734        },
6735        vendors = ['ms', 'moz', 'webkit', 'o'];
6736 
6737    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
6738        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
6739        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
6740            || window[vendors[x]+'CancelRequestAnimationFrame'];
6741    }
6742 
6743    if (!window.requestAnimationFrame)
6744        window.requestAnimationFrame = function(fn, element) {
6745            var currTime = new Date().getTime(),
6746                delta = currTime - lastTime,
6747                timeToCall = Math.max(0, 16 - delta);
6748 
6749            var id = window.setTimeout(function() {
6750                    fn(currTime + timeToCall);
6751                },
6752                timeToCall
6753            );
6754 
6755            lastTime = currTime + timeToCall;
6756 
6757            return id;
6758        };
6759 
6760    if (!window.cancelAnimationFrame) {
6761        window.cancelAnimationFrame = function(id) {
6762            clearTimeout(id);
6763        };
6764    }
6765 
6766    jQuery.fx.timer = function (timer) {
6767        if (timer() && jQuery.timers.push(timer) && !running) {
6768            running = true;
6769            animate(timer.elem);
6770        }
6771    };
6772 
6773    jQuery.fx.stop = function() {
6774        running = false;
6775    };
6776 
6777}(jQuery, this));
6778
6779/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
6780 * Licensed under the MIT License (LICENSE.txt).
6781 *
6782 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
6783 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
6784 * Thanks to: Seamus Leahy for adding deltaX and deltaY
6785 *
6786 * Version: 3.0.6
6787 *
6788 * Requires: 1.2.2+
6789 */
6790(function($) {
6791    var types = ['DOMMouseScroll', 'mousewheel'];
6792    if ($.event.fixHooks) {
6793        for (var i = types.length; i;) {
6794            $.event.fixHooks[types[--i]] = $.event.mouseHooks;
6795        }
6796    }
6797    $.event.special.mousewheel = {
6798        setup: function() {
6799            if (this.addEventListener) {
6800                for (var i = types.length; i;) {
6801                    this.addEventListener(types[--i], handler, false);
6802                }
6803            } else {
6804                this.onmousewheel = handler;
6805            }
6806        },
6807        teardown: function() {
6808            if (this.removeEventListener) {
6809                for (var i = types.length; i;) {
6810                    this.removeEventListener(types[--i], handler, false);
6811                }
6812            } else {
6813                this.onmousewheel = null;
6814            }
6815        }
6816    };
6817    $.fn.extend({
6818        mousewheel: function(fn) {
6819            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
6820        },
6821        unmousewheel: function(fn) {
6822            return this.unbind("mousewheel", fn);
6823        }
6824    });
6825
6826    function handler(event) {
6827        var orgEvent = event || window.event,
6828            args = [].slice.call(arguments, 1),
6829            delta = 0,
6830            returnValue = true,
6831            deltaX = 0,
6832            deltaY = 0;
6833        event = $.event.fix(orgEvent);
6834        event.type = "mousewheel";
6835        // Old school scrollwheel delta
6836        if (orgEvent.wheelDelta) {
6837            delta = orgEvent.wheelDelta / 120;
6838        }
6839        if (orgEvent.detail) {
6840            delta = -orgEvent.detail / 3;
6841        }
6842        // New school multidimensional scroll (touchpads) deltas
6843        deltaY = delta;
6844        // Gecko
6845        if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
6846            deltaY = 0;
6847            deltaX = -1 * delta;
6848        }
6849        // Webkit
6850        if (orgEvent.wheelDeltaY !== undefined) {
6851            deltaY = orgEvent.wheelDeltaY / 120;
6852        }
6853        if (orgEvent.wheelDeltaX !== undefined) {
6854            deltaX = -1 * orgEvent.wheelDeltaX / 120;
6855        }
6856        // Add event and delta to the front of the arguments
6857        args.unshift(event, delta, deltaX, deltaY);
6858        return ($.event.dispatch || $.event.handle).apply(this, args);
6859    }
6860})(jQuery);
6861
6862/**
6863 * jQuery iLightBox - Revolutionary Lightbox Plugin
6864 * http://www.ilightbox.net/
6865 *
6866 * @version: 2.2.4 - October 14, 2017
6867 *
6868 * @author: iProDev (Hemn Chawroka)
6869 *          http://www.iprodev.com/
6870 *
6871 */
6872(function($, window, undefined) {
6873
6874	var extensions = {
6875			flash: ['swf'],
6876			image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'],
6877			iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'],
6878			video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v']
6879		},
6880
6881		// Global DOM elements
6882		$win = $(window),
6883		$doc = $(document),
6884
6885		// Support indicators
6886		browser,
6887		transform,
6888		gpuAcceleration,
6889		fullScreenApi = '',
6890		userAgent = navigator.userAgent || navigator.vendor || window.opera,
6891		supportTouch = !!('ontouchstart' in window) && (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)),
6892		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)),
6893
6894		// Events
6895		clickEvent = supportTouch ? "itap.iLightBox" : "click.iLightBox",
6896		touchStartEvent = supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox",
6897		touchStopEvent = supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox",
6898		touchMoveEvent = supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox",
6899
6900		// Math shorthands
6901		abs = Math.abs,
6902		sqrt = Math.sqrt,
6903		round = Math.round,
6904		max = Math.max,
6905		min = Math.min,
6906		floor = Math.floor,
6907		random = Math.random,
6908
6909		pluginspages = {
6910			quicktime: 'http://www.apple.com/quicktime/download',
6911			flash: 'https://www.adobe.com/go/getflash'
6912		},
6913
6914		iLightBox = function(el, options, items, instant) {
6915			var iL = this;
6916
6917			iL.options = options,
6918				iL.selector = el.selector || el,
6919				iL.context = el.context,
6920				iL.instant = instant;
6921
6922			if (items.length < 1) iL.attachItems();
6923			else iL.items = items;
6924
6925			iL.vars = {
6926				total: iL.items.length,
6927				start: 0,
6928				current: null,
6929				next: null,
6930				prev: null,
6931				BODY: $('body'),
6932				loadRequests: 0,
6933				overlay: $('<div class="ilightbox-overlay"></div>'),
6934				loader: $('<div class="ilightbox-loader"><div></div></div>'),
6935				toolbar: $('<div class="ilightbox-toolbar"></div>'),
6936				innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'),
6937				title: $('<div class="ilightbox-title"></div>'),
6938				closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'),
6939				fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'),
6940				innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'),
6941				innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'),
6942				innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'),
6943				holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6944				nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6945				prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6946				nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'),
6947				prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
6948				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>'),
6949				thumbs: false,
6950				nextLock: false,
6951				prevLock: false,
6952				hashLock: false,
6953				isMobile: false,
6954				mobileMaxWidth: 980,
6955				isInFullScreen: false,
6956				isSwipe: false,
6957				mouseID: 0,
6958				cycleID: 0,
6959				isPaused: 0,
6960				captionHeight: 39,
6961			};
6962
6963			// Hideable elements with mousemove event
6964			iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton);
6965
6966			iL.normalizeItems();
6967
6968			//Check necessary plugins
6969			iL.availPlugins();
6970
6971			//Set startFrom
6972			iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom;
6973
6974			//If randomStart
6975			iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom;
6976			iL.vars.start = iL.options.startFrom;
6977
6978			if (instant) iL.instantCall();
6979			else iL.patchItemsEvents();
6980
6981			if (iL.options.linkId) {
6982				iL.hashChangeHandler();
6983				$win.iLightBoxHashChange(function() {
6984					iL.hashChangeHandler();
6985				});
6986			}
6987
6988			if (supportTouch) {
6989				var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig,
6990					replace = "itap";
6991				iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace),
6992					iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace),
6993					iL.options.social.show = iL.options.social.show.replace(RegExp, replace),
6994					iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace);
6995			}
6996
6997			if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) {
6998				$.extend(iL.options.styles, {
6999					nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
7000					prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
7001					nextOpacity: 0,
7002					prevOpacity: 0
7003				});
7004			}
7005		};
7006
7007	//iLightBox helpers
7008	iLightBox.prototype = {
7009		showLoader: function() {
7010			var iL = this;
7011			iL.vars.loadRequests += 1;
7012			if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({
7013				//top: '-30px'
7014				opacity: '1'
7015			}, iL.options.show.speed, 'easeOutCirc');
7016			else iL.vars.loader.addClass('ilightbox-show').stop().animate({
7017				//left: '-30px'
7018				opacity: '1'
7019			}, iL.options.show.speed, 'easeOutCirc');
7020		},
7021
7022		hideLoader: function() {
7023			var iL = this;
7024			iL.vars.loadRequests -= 1;
7025			iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests;
7026			if (iL.options.path.toLowerCase() == "horizontal") {
7027				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
7028					//top: '-192px'
7029					opacity: '0'
7030				}, iL.options.show.speed, 'easeInCirc');
7031			} else {
7032				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
7033					//left: '-192px'
7034					opacity: '0'
7035				}, iL.options.show.speed, 'easeInCirc');
7036			}
7037		},
7038
7039		createUI: function() {
7040			var iL = this;
7041
7042			iL.ui = {
7043				currentElement: iL.vars.holder,
7044				nextElement: iL.vars.nextPhoto,
7045				prevElement: iL.vars.prevPhoto,
7046				currentItem: iL.vars.current,
7047				nextItem: iL.vars.next,
7048				prevItem: iL.vars.prev,
7049				hide: function() {
7050					iL.closeAction();
7051				},
7052				refresh: function() {
7053					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
7054				},
7055				fullscreen: function() {
7056					iL.fullScreenAction();
7057				}
7058			};
7059		},
7060
7061		attachItems: function() {
7062			var iL = this,
7063				itemsObject = new Array(),
7064				items = new Array();
7065
7066			$(iL.selector, iL.context).each(function() {
7067				var t = $(this),
7068					URL = t.attr(iL.options.attr) || null,
7069					options = t.data("options") && eval("({" + t.data("options") + "})") || {},
7070					caption = t.data('caption'),
7071					title = t.data('title'),
7072					type = t.data('type') || getTypeByExtension(URL),
7073					clone = t.data('lbox-clone') || false;
7074
7075				if (t.data('lbox-clone') != undefined) return;
7076
7077				//Uncode addition ##START##
7078				if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) {
7079					var ALBUM_URLS = JSON.parse(t.attr('data-album')),
7080						URL_i,
7081						URLS_LENGHT = ALBUM_URLS.length;
7082					for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) {
7083						if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) {
7084							var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\'';
7085							item_opts = item_opts && eval("({" + item_opts + "})") || {},
7086							items.push({
7087								URL: ALBUM_URLS[URL_i].url,
7088								caption: ALBUM_URLS[URL_i].caption,
7089								title: ALBUM_URLS[URL_i].title,
7090								type: getTypeByExtension(ALBUM_URLS[URL_i].url),
7091								options: item_opts,
7092								clone: clone
7093							});
7094							var newT = t;
7095							newT.attr('href',ALBUM_URLS[URL_i].url);
7096							if (!iL.instant) itemsObject.push(newT);
7097						}
7098					}
7099				} else {
7100				//Uncode addition ##END##
7101					items.push({
7102						URL: URL,
7103						caption: caption,
7104						title: title,
7105						type: type,
7106						options: options,
7107						clone: clone
7108					});
7109				}
7110
7111
7112				if (iL.vars != undefined) iL.vars.total = items.length;
7113
7114				if (!iL.instant) itemsObject.push(t);
7115			});
7116
7117			iL.items = items,
7118				iL.itemsObject = itemsObject;
7119
7120		},
7121
7122		normalizeItems: function() {
7123			var iL = this,
7124				newItems = new Array();
7125
7126			$.each(iL.items, function(key, val) {
7127
7128				if (typeof val == "string") val = {
7129					url: val
7130				};
7131
7132				var URL = val.url || val.URL || null,
7133					options = val.options || {},
7134					caption = val.caption || null,
7135					title = val.title || null,
7136					type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL),
7137					ext = (typeof URL != 'object') ? getExtension(URL) : '';
7138
7139				options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
7140				options.videoType = options.videoType || null,
7141				options.skin = options.skin || iL.options.skin,
7142				options.width = options.width || null,
7143				options.height = options.height || null,
7144				options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true,
7145				options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true,
7146				options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons);
7147
7148				if (type == "video") {
7149					options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {};
7150
7151					options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null;
7152					options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls";
7153					options.html5video.preload = options.html5video.preload || "metadata";
7154					options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false;
7155					//UNCODE addition		
7156					options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false;
7157				}
7158
7159				if (!options.width || !options.height) {
7160					if (type == "video") options.width = 1280, options.height = 720;
7161					else if (type == "iframe") options.width = '100%', options.height = '90%';
7162					else if (type == "flash") options.width = 1280, options.height = 720;
7163				}
7164
7165				delete val.url;
7166				val.index = key;
7167				val.URL = URL;
7168				val.caption = caption;
7169				val.title = title;
7170				val.type = type;
7171				val.options = options;
7172				val.ext = ext;
7173
7174				newItems.push(val);
7175			});
7176
7177			iL.items = newItems;
7178		},
7179
7180		instantCall: function() {
7181			var iL = this,
7182				key = iL.vars.start;
7183
7184			iL.vars.current = key;
7185			iL.vars.next = (iL.items[key + 1]) ? key + 1 : null;
7186			iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null;
7187
7188			iL.addContents();
7189			iL.patchEvents();
7190		},
7191
7192		addContents: function() {
7193			var iL = this,
7194				vars = iL.vars,
7195				opts = iL.options,
7196				viewport = getViewport(),
7197				path = opts.path.toLowerCase(),
7198				recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) {
7199					return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition);
7200				}),
7201				needRecognition = recognizingItems.length > 0;
7202
7203			if (opts.mobileOptimizer && !opts.innerToolbar)
7204				vars.isMobile = viewport.width <= vars.mobileMaxWidth;
7205
7206			vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity);
7207
7208			if (opts.linkId)
7209				vars.overlay[0].setAttribute('linkid', opts.linkId);
7210
7211			//Add Toolbar Buttons
7212			if (opts.controls.toolbar) {
7213				vars.toolbar.addClass(opts.skin).append(vars.closeButton);
7214				if (opts.controls.fullscreen)
7215					vars.toolbar.append(vars.fullScreenButton);
7216				if (opts.controls.slideshow)
7217					vars.toolbar.append(vars.innerPlayButton);
7218				if (vars.total > 1)
7219					vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton);
7220			}
7221
7222			//Append elements to body
7223			vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto);
7224
7225			if (!opts.innerToolbar)
7226				vars.BODY.append(vars.toolbar);
7227			if (opts.controls.arrows)
7228				vars.BODY.append(vars.nextButton).append(vars.prevButton);
7229
7230			if (opts.controls.thumbnail && vars.total > 1) {
7231				vars.BODY.append(vars.thumbnails);
7232				vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path);
7233				$('div.ilightbox-thumbnails-grid', vars.thumbnails).empty();
7234				vars.thumbs = true;
7235			}
7236
7237			//Configure loader and arrows
7238			var loaderCss = (opts.path.toLowerCase() == "horizontal") ? {
7239				left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2))
7240			} : {
7241				top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2))
7242			};
7243			vars.loader.addClass(opts.skin).css(loaderCss);
7244			vars.nextButton.add(vars.prevButton).addClass(opts.skin);
7245			if (path == "horizontal")
7246				vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal');
7247
7248			// Configure arrow buttons
7249			vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
7250
7251			if (!opts.infinite) {
7252				vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
7253
7254				if (vars.current == 0)
7255					vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
7256				if (vars.current >= vars.total - 1)
7257					vars.nextButton.add(vars.innerNextButton).addClass('disabled');
7258			}
7259
7260			if (opts.show.effect) {
7261				vars.overlay.stop().fadeIn(opts.show.speed);
7262				vars.toolbar.stop().fadeIn(opts.show.speed);
7263			} else {
7264				vars.overlay.show();
7265				vars.toolbar.show();
7266			}
7267
7268			var length = recognizingItems.length;
7269			if (needRecognition) {
7270				iL.showLoader();
7271
7272				$.each(recognizingItems, function(key, val) {
7273					var resultFnc = function(result) {
7274							var key = -1,
7275								filter = iL.items.filter(function(e, i, arr) {
7276									if (e.URL == result.url)
7277										key = i;
7278
7279									return e.URL == result.url;
7280								}),
7281								self = iL.items[key];
7282
7283							if (result)
7284								$.extend(true, self, {
7285									URL: result.source,
7286									type: result.type,
7287									recognized: true,
7288									options: {
7289										html5video: result.html5video,
7290										width: (result.type == "image") ? 0 : (result.width || self.width),
7291										height: (result.type == "image") ? 0 : (result.height || self.height),
7292										thumbnail: self.options.thumbnail || result.thumbnail
7293									}
7294								});
7295
7296							length--;
7297
7298							if (length == 0) {
7299								iL.hideLoader();
7300
7301								vars.dontGenerateThumbs = false;
7302								iL.generateThumbnails();
7303
7304								if (opts.show.effect)
7305									setTimeout(function() {
7306										iL.generateBoxes();
7307									}, opts.show.speed);
7308								else
7309									iL.generateBoxes();
7310							}
7311						};
7312
7313					iL.ogpRecognition(this, resultFnc);
7314				});
7315			}
7316			else {
7317				if (opts.show.effect)
7318					setTimeout(function() {
7319						iL.generateBoxes();
7320					}, opts.show.speed);
7321				else
7322					iL.generateBoxes();
7323			}
7324
7325			iL.createUI();
7326
7327			window.iLightBox = {
7328				close: function() {
7329					iL.closeAction();
7330				},
7331				fullscreen: function() {
7332					iL.fullScreenAction();
7333				},
7334				moveNext: function() {
7335					iL.moveTo('next');
7336				},
7337				movePrev: function() {
7338					iL.moveTo('prev');
7339				},
7340				goTo: function(index) {
7341					iL.goTo(index);
7342				},
7343				refresh: function() {
7344					iL.refresh();
7345				},
7346				reposition: function() {
7347					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
7348				},
7349				setOption: function(options) {
7350					iL.setOption(options);
7351				},
7352				destroy: function() {
7353					iL.closeAction();
7354					iL.dispatchItemsEvents();
7355				}
7356			};
7357
7358			if (opts.linkId) {
7359				vars.hashLock = true;
7360				window.location.hash = opts.linkId + '/' + vars.current;
7361				setTimeout(function() {
7362					vars.hashLock = false;
7363				}, 55);
7364			}
7365
7366			if (!opts.slideshow.startPaused) {
7367				iL.resume();
7368				vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause');
7369			}
7370
7371			//Trigger the onOpen callback
7372			if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL);
7373		},
7374
7375		loadContent: function(obj, opt, speed) {
7376			var iL = this,
7377				holder, item;
7378
7379			iL.createUI();
7380
7381			obj.speed = speed || iL.options.effects.loadedFadeSpeed;
7382
7383			if (opt == 'current') {
7384				if (!obj.options.mousewheel) iL.vars.lockWheel = true;
7385				else iL.vars.lockWheel = false;
7386
7387				if (!obj.options.swipe) iL.vars.lockSwipe = true;
7388				else iL.vars.lockSwipe = false;
7389			}
7390
7391			switch (opt) {
7392				case 'current':
7393					holder = iL.vars.holder, item = iL.vars.current;
7394					break;
7395				case 'next':
7396					holder = iL.vars.nextPhoto, item = iL.vars.next;
7397					break;
7398				case 'prev':
7399					holder = iL.vars.prevPhoto, item = iL.vars.prev;
7400					break;
7401			}
7402
7403			holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin);
7404			$('div.ilightbox-inner-toolbar', holder).remove();
7405
7406			if (obj.title || iL.options.innerToolbar) {
7407				var innerToolbar = iL.vars.innerToolbar.clone();
7408				if (obj.title && iL.options.show.title) {
7409					var title = iL.vars.title.clone();
7410					title.empty().html(obj.title);
7411					innerToolbar.append(title);
7412				}
7413				if (iL.options.innerToolbar) {
7414					innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar);
7415				}
7416				holder.prepend(innerToolbar);
7417			}
7418
7419			//console.warn('loadContent', arguments);
7420
7421			iL.loadSwitcher(obj, holder, item, opt);
7422		},
7423
7424		loadSwitcher: function(obj, holder, item, opt) {
7425			var iL = this,
7426				opts = iL.options,
7427				api = {
7428					element: holder,
7429					position: item
7430				};
7431
7432			switch (obj.type) {
7433				case 'image':
7434					//Trigger the onBeforeLoad callback
7435					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7436					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7437
7438					iL.loadImage(obj.URL, function(img) {
7439						//Trigger the onAfterLoad callback
7440						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7441						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7442
7443						var width = (img) ? img.width : 400,
7444							height = (img) ? img.height : 200;
7445
7446						holder.data({
7447							naturalWidth: width,
7448							naturalHeight: height
7449						});
7450						$('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>');
7451
7452						//Trigger the onRender callback
7453						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7454						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7455
7456						iL.configureHolder(obj, opt, holder);
7457					});
7458
7459					break;
7460
7461				case 'video':
7462					holder.data({
7463						naturalWidth: obj.options.width,
7464						naturalHeight: obj.options.height
7465					});
7466
7467					if (opt === 'current') {
7468						iL.addContent(holder, obj);
7469
7470						//Trigger the onRender callback
7471						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7472						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7473					} else {
7474						$('div.ilightbox-container', holder).empty();
7475					}
7476
7477					iL.configureHolder(obj, opt, holder);
7478
7479					break;
7480
7481				case 'iframe':
7482					//iL.showLoader();
7483					holder.data({
7484						naturalWidth: obj.options.width,
7485						naturalHeight: obj.options.height
7486					});
7487
7488					iL.configureHolder(obj, opt, holder);
7489
7490					if (opt === 'current') {
7491						var el = iL.addContent(holder, obj);
7492
7493						//Trigger the onRender callback
7494						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7495						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7496
7497						//Trigger the onBeforeLoad callback
7498						if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7499						if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7500
7501						el.bind('load', function() {
7502							//Trigger the onAfterLoad callback
7503							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7504							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7505
7506							//iL.hideLoader();
7507							el.unbind('load');
7508						});
7509					} else {
7510						$('div.ilightbox-container', holder).empty();
7511					}
7512
7513					break;
7514
7515				case 'inline':
7516					var el = $(obj.URL),
7517						content = iL.addContent(holder, obj),
7518						images = findImageInElement(holder);
7519
7520					holder.data({
7521						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
7522						naturalHeight: (iL.items[item].options.height || el.outerHeight())
7523					});
7524					content.children().eq(0).show();
7525
7526					//Trigger the onRender callback
7527					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7528					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7529
7530					//Trigger the onBeforeLoad callback
7531					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7532					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7533
7534					iL.loadImage(images, function() {
7535						//Trigger the onAfterLoad callback
7536						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7537						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7538
7539						iL.configureHolder(obj, opt, holder);
7540					});
7541
7542					break;
7543
7544				case 'flash':
7545					var el = iL.addContent(holder, obj);
7546
7547					holder.data({
7548						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
7549						naturalHeight: (iL.items[item].options.height || el.outerHeight())
7550					});
7551
7552					//Trigger the onRender callback
7553					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7554					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7555
7556					iL.configureHolder(obj, opt, holder);
7557
7558					break;
7559
7560				case 'ajax':
7561					var ajax = obj.options.ajax || {};
7562					//Trigger the onBeforeLoad callback
7563					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7564					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7565
7566					iL.showLoader();
7567					$.ajax({
7568						url: obj.URL || opts.ajaxSetup.url,
7569						data: ajax.data || null,
7570						dataType: ajax.dataType || "html",
7571						type: ajax.type || opts.ajaxSetup.type,
7572						cache: ajax.cache || opts.ajaxSetup.cache,
7573						crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain,
7574						global: ajax.global || opts.ajaxSetup.global,
7575						ifModified: ajax.ifModified || opts.ajaxSetup.ifModified,
7576						username: ajax.username || opts.ajaxSetup.username,
7577						password: ajax.password || opts.ajaxSetup.password,
7578						beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend,
7579						complete: ajax.complete || opts.ajaxSetup.complete,
7580						success: function(data, textStatus, jqXHR) {
7581							iL.hideLoader();
7582
7583							var el = $(data),
7584								container = $('div.ilightbox-container', holder),
7585								elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')),
7586								elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')),
7587								css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? {
7588									'overflow': 'hidden'
7589								} : {};
7590
7591							container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el));
7592							holder.show().data({
7593								naturalWidth: (elWidth || container.outerWidth()),
7594								naturalHeight: (elHeight || container.outerHeight())
7595							}).hide();
7596
7597							//Trigger the onRender callback
7598							if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7599							if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7600
7601							var images = findImageInElement(holder);
7602							iL.loadImage(images, function() {
7603								//Trigger the onAfterLoad callback
7604								if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7605								if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7606
7607								iL.configureHolder(obj, opt, holder);
7608							});
7609
7610							opts.ajaxSetup.success(data, textStatus, jqXHR);
7611							if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR);
7612						},
7613						error: function(jqXHR, textStatus, errorThrown) {
7614							//Trigger the onAfterLoad callback
7615							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7616							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7617
7618							iL.hideLoader();
7619							$('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>');
7620							iL.configureHolder(obj, opt, holder);
7621
7622							opts.ajaxSetup.error(jqXHR, textStatus, errorThrown);
7623							if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown);
7624						}
7625					});
7626
7627					break;
7628
7629				case 'html':
7630					var object = obj.URL,
7631						el
7632					container = $('div.ilightbox-container', holder);
7633
7634					if (object[0].nodeName) el = object.clone();
7635					else {
7636						var dom = $(object);
7637						if (dom.selector) el = $('<div>' + dom + '</div>');
7638						else el = dom;
7639					}
7640
7641					var elWidth = iL.items[item].options.width || parseInt(el.attr('width')),
7642						elHeight = iL.items[item].options.height || parseInt(el.attr('height'));
7643
7644					iL.addContent(holder, obj);
7645
7646					el.appendTo(document.documentElement).hide();
7647
7648					//Trigger the onRender callback
7649					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7650					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7651
7652					var images = findImageInElement(holder);
7653
7654					//Trigger the onBeforeLoad callback
7655					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7656					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7657
7658					iL.loadImage(images, function() {
7659						//Trigger the onAfterLoad callback
7660						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7661						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7662
7663						holder.show().data({
7664							naturalWidth: (elWidth || container.outerWidth()),
7665							naturalHeight: (elHeight || container.outerHeight())
7666						}).hide();
7667						el.remove();
7668
7669						iL.configureHolder(obj, opt, holder);
7670					});
7671
7672					break;
7673			}
7674		},
7675
7676		configureHolder: function(obj, opt, holder) {
7677			var iL = this,
7678				vars = iL.vars,
7679				opts = iL.options;
7680
7681			if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev');
7682
7683			if (opt == "current")
7684				var item = vars.current;
7685			else if (opt == "next")
7686				var opacity = opts.styles.nextOpacity,
7687					item = vars.next;
7688			else
7689				var opacity = opts.styles.prevOpacity,
7690					item = vars.prev;
7691
7692			var api = {
7693				element: holder,
7694				position: item
7695			};
7696
7697			iL.items[item].options.width = iL.items[item].options.width || 0,
7698			iL.items[item].options.height = iL.items[item].options.height || 0;
7699
7700			if (opt == "current") {
7701				if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() {
7702					holder.css(transform, '');
7703					if (obj.caption) {
7704						iL.setCaption(obj, holder);
7705						var caption = $('div.ilightbox-caption', holder),
7706							percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100);
7707						if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
7707Speed);
7708					}
7709
7710					var social = obj.options.social;
7711					if (social) {
7712						iL.setSocial(social, obj.URL, holder);
7713						if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed);
7714					}
7715
7716					//Generate thumbnails
7717					iL.generateThumbnails();
7718
7719					//Trigger the onShow callback
7720					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7721					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7722				});
7723				else {
7724					holder.show();
7725
7726					//Generate thumbnails
7727					iL.generateThumbnails();
7728
7729					//Trigger the onShow callback
7730					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7731					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7732				}
7733			} else {
7734				if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() {
7735					if (opt == "next") vars.nextLock = false;
7736					else vars.prevLock = false;
7737
7738					//Generate thumbnails
7739					iL.generateThumbnails();
7740
7741					//Trigger the onShow callback
7742					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7743					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7744				});
7745				else {
7746					holder.css({
7747						opacity: opacity
7748					}).show();
7749					if (opt == "next") vars.nextLock = false;
7750					else vars.prevLock = false;
7751
7752					//Generate thumbnails
7753					iL.generateThumbnails();
7754
7755					//Trigger the onShow callback
7756					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7757					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7758				}
7759			}
7760
7761			setTimeout(function() {
7762				iL.repositionPhoto();
7763			}, 0);
7764		},
7765
7766		generateBoxes: function() {
7767			var iL = this,
7768				vars = iL.vars,
7769				opts = iL.options;
7770
7771			if (opts.infinite && vars.total >= 3) {
7772				if (vars.current == vars.total - 1) vars.next = 0;
7773				if (vars.current == 0) vars.prev = vars.total - 1;
7774			} else opts.infinite = false;
7775
7776			//UNCODE addition		
7777			if ( typeof iL.items[vars.current] == 'undefined' )
7778				vars.current = 0;
7779
7780			iL.loadContent(iL.items[vars.current], 'current', opts.show.speed);
7781
7782			if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed);
7783			if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed);
7784		},
7785
7786		generateThumbnails: function() {
7787			var iL = this,
7788				vars = iL.vars,
7789				opts = iL.options,
7790				timeOut = null;
7791
7792			if (vars.thumbs && !iL.vars.dontGenerateThumbs) {
7793				var thumbnails = vars.thumbnails,
7794					container = $('div.ilightbox-thumbnails-container', thumbnails),
7795					grid = $('div.ilightbox-thumbnails-grid', container),
7796					i = 0;
7797
7798				grid.removeAttr('style').empty();
7799
7800				$.each(iL.items, function(key, val) {
7801					var isActive = (vars.current == key) ? 'ilightbox-active' : '',
7802						opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity,
7803						thumb = val.options.thumbnail,
7804						thumbnail = $('<div class="ilightbox-thumbnail"></div>'),
7805						icon = $('<div class="ilightbox-thumbnail-icon"></div>');
7806
7807					thumbnail.css({
7808						opacity: 0
7809					}).addClass(isActive);
7810
7811					if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') {
7812						icon.addClass('ilightbox-thumbnail-video');
7813						thumbnail.append(icon);
7814					} else if (val.options.icon) {
7815						icon.addClass('ilightbox-thumbnail-' + val.options.icon);
7816						thumbnail.append(icon);
7817					}
7818
7819					if (thumb) iL.loadImage(thumb, function(img) {
7820						i++;
7821						if (img) thumbnail.data({
7822							naturalWidth: img.width,
7823							naturalHeight: img.height
7824						}).append('<img src="' + thumb + '" border="0" />');
7825						else thumbnail.data({
7826							naturalWidth: opts.thumbnails.maxWidth,
7827							naturalHeight: opts.thumbnails.maxHeight
7828						});
7829
7830						clearTimeout(timeOut);
7831						timeOut = setTimeout(function() {
7832							iL.positionThumbnails(thumbnails, container, grid);
7833						}, 20);
7834						setTimeout(function() {
7835							thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity);
7836						}, i * 20);
7837					});
7838
7839					grid.append(thumbnail);
7840				});
7841				iL.vars.dontGenerateThumbs = true;
7842			}
7843		},
7844
7845		positionThumbnails: function(thumbnails, container, grid) {
7846			var iL = this,
7847				vars = iL.vars,
7848				opts = iL.options,
7849				viewport = getViewport(),
7850				path = opts.path.toLowerCase();
7851
7852			if (!thumbnails) thumbnails = vars.thumbnails;
7853			if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails);
7854			if (!grid) grid = $('div.ilightbox-thumbnails-grid', container);
7855
7856			var thumbs = $('.ilightbox-thumbnail', grid),
7857				widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX,
7858				heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY,
7859				gridWidth = (path == 'horizontal') ? 0 : widthAvail,
7860				gridHeight = (path == 'horizontal') ? heightAvail : 0,
7861				active = $('.ilightbox-active', grid),
7862				gridCss = {},
7863				css = {};
7864
7865			if (arguments.length < 3) {
7866				thumbs.css({
7867					opacity: opts.thumbnails.normalOpacity
7868				});
7869				active.css({
7870					opacity: opts.thumbnails.activeOpacity
7871				});
7872			}
7873
7874			thumbs.each(function(i) {
7875				var t = $(this),
7876					data = t.data(),
7877					width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth;
7878				height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0;
7879				dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true);
7880
7881				t.css({
7882					width: dims.width,
7883					height: dims.height
7884				});
7885				if (path == 'horizontal') t.css({
7886					'float': 'left'
7887				});
7888
7889				(path == 'horizontal') ? (
7890					gridWidth += t.outerWidth()
7891				) : (
7892					gridHeight += t.outerHeight()
7893				);
7894			});
7895
7896			gridCss = {
7897				width: gridWidth,
7898				height: gridHeight
7899			};
7900
7901			grid.css(gridCss);
7902
7903			gridCss = {};
7904
7905			var gridOffset = grid.offset(),
7906				activeOffset = (active.length) ? active.offset() : {
7907					top: parseInt(heightAvail / 2),
7908					left: parseInt(widthAvail / 2)
7909				};
7910
7911			gridOffset.top = (gridOffset.top - $doc.scrollTop()),
7912				gridOffset.left = (gridOffset.left - $doc.scrollLeft()),
7913				activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()),
7914				activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft());
7915
7916			(path == 'horizontal') ? (
7917				gridCss.top = 0,
7918				gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2))
7919			) : (
7920				gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))),
7921				gridCss.left = 0
7922			);
7923
7924			if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc');
7925			else grid.css(gridCss);
7926		},
7927
7928		loadImage: function(image, callback) {
7929			if (!$.isArray(image)) image = [image];
7930
7931			var iL = this,
7932				length = image.length;
7933
7934			if (length > 0) {
7935				iL.showLoader();
7936				$.each(image, function(index, value) {
7937					var img = new Image();
7938					img.onload = function() {
7939						length -= 1;
7940						if (length == 0) {
7941							iL.hideLoader();
7942							callback(img);
7943						}
7944					};
7945					img.onerror = img.onabort = function() {
7946						length -= 1;
7947						if (length == 0) {
7948							iL.hideLoader();
7949							callback(false);
7950						}
7951					};
7952					img.src = image[index];
7953				});
7954			} else callback(false);
7955		},
7956
7957		patchItemsEvents: function() {
7958			var iL = this,
7959				vars = iL.vars,
7960				clickEvent = supportTouch ? "itap.iL" : "click.iL",
7961				vEvent = supportTouch ? "click.iL" : "itap.iL";
7962
7963			if (iL.context && iL.selector) {
7964				var $items = $(iL.selector, iL.context);
7965
7966				$(iL.context).on(clickEvent, iL.selector, function() {
7967					var $this = $(this),
7968						//UNCODE addition
7969						key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this);
7970					if (UNCODE.isMobile) {
7971						var isCarousel = $this.closest('.owl-carousel');
7972						if (isCarousel.length) {
7973							if (isCarousel.hasClass('owl-translating')) return false;
7974						}
7975					}
7976
7977					vars.current = key;
7978					vars.next = iL.items[key + 1] ? key + 1 : null;
7979					vars.prev = iL.items[key - 1] ? key - 1 : null;
7980
7981					//UNCODE addition
7982					if ( vars.BODY.hasClass('fp-slide-scrolling') )
7983						return false;
7984
7985					iL.addContents();
7986					iL.patchEvents();
7987
7988					return false;
7989				}).on(vEvent, iL.selector, function() {
7990					return false;
7991				});
7992			} else
7993				$.each(iL.itemsObject, function(key, val) {
7994					val.on(clickEvent, function() {
7995						vars.current = key;
7996						vars.next = iL.items[key + 1] ? key + 1 : null;
7997						vars.prev = iL.items[key - 1] ? key - 1 : null;
7998
7999						iL.addContents();
8000						iL.patchEvents();
8001
8002						return false;
8003					}).on(vEvent, function() {
8004						return false;
8005					});
8006				});
8007		},
8008
8009		dispatchItemsEvents: function() {
8010			var iL = this,
8011				vars = iL.vars,
8012				opts = iL.options;
8013
8014			if (iL.context && iL.selector)
8015				$(iL.context).off('.iL', iL.selector);
8016			else
8017				$.each(iL.itemsObject, function(key, val) {
8018					val.off('.iL');
8019				});
8020		},
8021
8022		refresh: function() {
8023			var iL = this;
8024
8025			iL.dispatchItemsEvents();
8026			iL.attachItems();
8027			iL.normalizeItems();
8028			iL.patchItemsEvents();
8029		},
8030
8031		patchEvents: function() {
8032			var iL = this,
8033				vars = iL.vars,
8034				opts = iL.options,
8035				path = opts.path.toLowerCase(),
8036				holders = $('.ilightbox-holder'),
8037				fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox',
8038				durationThreshold = 1000,
8039				horizontalDistanceThreshold =
8040				verticalDistanceThreshold = 100,
8041				buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild];
8042
8043			$win.bind('resize.iLightBox', function() {
8044				var viewport = getViewport();
8045
8046				if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth;
8047				vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
8048
8049				iL.repositionPhoto(null);
8050				if (supportTouch) {
8051					clearTimeout(vars.setTime);
8052					vars.setTime = setTimeout(function() {
8053						var scrollTop = getScrollXY().y;
8054						window.scrollTo(0, scrollTop - 30);
8055						window.scrollTo(0, scrollTop + 30);
8056						window.scrollTo(0, scrollTop);
8057					}, 2000);
8058				}
8059				if (vars.thumbs) iL.positionThumbnails();
8060			}).bind('keydown.iLightBox', function(event) {
8061				if (opts.controls.keyboard) {
8062					switch (event.keyCode) {
8063						case 13:
8064							if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction();
8065							break;
8066						case 27:
8067							if (opts.keyboard.esc) iL.closeAction();
8068							break;
8069						case 37:
8070							if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev');
8071							break;
8072						case 38:
8073							if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev');
8074							break;
8075						case 39:
8076							if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next');
8077							break;
8078						case 40:
8079							if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next');
8080							break;
8081					}
8082				}
8083			});
8084
8085			if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() {
8086				iL.doFullscreen();
8087			});
8088
8089			var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) {
8090					return arr.lastIndexOf(e) === i;
8091				}),
8092				holderEvents = "";
8093
8094			$.each(holderEventsArr, function(key, val) {
8095				if (key != 0) holderEvents += ' ';
8096				holderEvents += val;
8097			});
8098
8099			$doc.on(clickEvent, '.ilightbox-overlay', function() {
8100				if (opts.overlay.blur) iL.closeAction();
8101			}).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() {
8102				iL.moveTo('next');
8103			}).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() {
8104				iL.moveTo('prev');
8105			}).on(clickEvent, '.ilightbox-thumbnail', function() {
8106				var t = $(this),
8107					thumbs = $('.ilightbox-thumbnail', vars.thumbnails),
8108					index = thumbs.index(t);
8109
8110				if (index != vars.current) iL.goTo(index);
8111			}).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
8112				var caption = $('div.ilightbox-caption', vars.holder),
8113					social = $('div.ilightbox-social', vars.holder),
8114					fadeSpeed = opts.effects.fadeSpeed;
8115
8116				if (vars.nextLock || vars.prevLock) {
8117					if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed);
8118					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed);
8119
8120					if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed);
8121					else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed);
8122				} else {
8123					if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed);
8124					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed);
8125
8126					if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed);
8127					else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed);
8128				}
8129			}).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) {
8130				if (e.type == 'mouseenter') vars.lockWheel = true;
8131				else vars.lockWheel = false;
8132			}).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() {
8133				var t = $(this);
8134
8135				if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction();
8136				else if (t.hasClass('ilightbox-play')) {
8137					iL.resume();
8138					t.addClass('ilightbox-pause').removeClass('ilightbox-play');
8139				} else if (t.hasClass('ilightbox-pause')) {
8140					iL.pause();
8141					t.addClass('ilightbox-play').removeClass('ilightbox-pause');
8142				} else iL.closeAction();
8143			}).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) {
8144				// prevent scrolling
8145				e.preventDefault();
8146			});
8147
8148			function mouseMoveHandler(e) {
8149				if (!vars.isMobile) {
8150					if (!vars.mouseID) {
8151						vars.hideableElements.show();
8152					}
8153
8154					vars.mouseID = clearTimeout(vars.mouseID);
8155
8156					if (buttonsArray.indexOf(e.target) === -1)
8157						vars.mouseID = setTimeout(function() {
8158							vars.hideableElements.hide();
8159							vars.mouseID = clearTimeout(vars.mouseID);
8160						}, 3000);
8161				}
8162			}
8163
8164			if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler);
8165
8166			if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
8167				if (e.type == 'mouseenter' && vars.cycleID) iL.pause();
8168				else if (e.type == 'mouseleave' && vars.isPaused) iL.resume();
8169			});
8170
8171			var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails');
8172
8173			if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) {
8174				if (!vars.lockWheel) {
8175					event.preventDefault();
8176					if (delta < 0) iL.moveTo('next');
8177					else if (delta > 0) iL.moveTo('prev');
8178				}
8179			});
8180
8181			if (opts.controls.swipe) holders.on(touchStartEvent, function(event) {
8182				if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return;
8183
8184				vars.BODY.addClass('ilightbox-closedhand');
8185
8186				var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event,
8187					scrollTop = $doc.scrollTop(),
8188					scrollLeft = $doc.scrollLeft(),
8189					offsets = [
8190						holders.eq(0).offset(),
8191						holders.eq(1).offset(),
8192						holders.eq(2).offset()
8193					],
8194					offSet = [{
8195						top: offsets[0].top - scrollTop,
8196						left: offsets[0].left - scrollLeft
8197					}, {
8198						top: offsets[1].top - scrollTop,
8199						left: offsets[1].left - scrollLeft
8200					}, {
8201						top: offsets[2].top - scrollTop,
8202						left: offsets[2].left - scrollLeft
8203					}],
8204					start = {
8205						time: (new Date()).getTime(),
8206						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
8207					},
8208					stop;
8209
8210				function moveEachHandler(i) {
8211					var t = $(this),
8212						offset = offSet[i],
8213						scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])];
8214
8215					t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px';
8216				}
8217
8218				function moveHandler(event) {
8219
8220					if (!start) return;
8221
8222					var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event;
8223
8224					stop = {
8225						time: (new Date()).getTime(),
8226						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
8227					};
8228
8229					holders.each(moveEachHandler);
8230
8231					// prevent scrolling
8232					event.preventDefault();
8233				}
8234
8235				function repositionHolders() {
8236					holders.each(function() {
8237						var t = $(this),
8238							offset = t.data('offset') || {
8239								top: t.offset().top - scrollTop,
8240								left: t.offset().left - scrollLeft
8241							},
8242							top = offset.top,
8243							left = offset.left;
8244
8245						t.css(transform, gpuAcceleration).stop().animate({
8246							top: top,
8247							left: left
8248						}, 500, 'easeOutCirc', function() {
8249							t.css(transform, '');
8250						});
8251					});
8252				}
8253
8254				holders.bind(touchMoveEvent, moveHandler);
8255				$doc.one(touchStopEvent, function(event) {
8256					holders.unbind(touchMoveEvent, moveHandler);
8257
8258					vars.BODY.removeClass('ilightbox-closedhand');
8259
8260					if (start && stop) {
8261						if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) {
8262							if (start.coords[0] > stop.coords[0]) {
8263								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
8264								else {
8265									vars.isSwipe = true;
8266									iL.moveTo('next');
8267								}
8268							} else {
8269								if (vars.current == 0 && !opts.infinite) repositionHolders();
8270								else {
8271									vars.isSwipe = true;
8272									iL.moveTo('prev');
8273								}
8274							}
8275						} 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) {
8276							if (start.coords[1] > stop.coords[1]) {
8277								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
8278								else {
8279									vars.isSwipe = true;
8280									iL.moveTo('next');
8281								}
8282							} else {
8283								if (vars.current == 0 && !opts.infinite) repositionHolders();
8284								else {
8285									vars.isSwipe = true;
8286									iL.moveTo('prev');
8287								}
8288							}
8289						} else repositionHolders();
8290					}
8291					start = stop = undefined;
8292				});
8293			});
8294
8295		},
8296
8297		goTo: function(index) {
8298			var iL = this,
8299				vars = iL.vars,
8300				opts = iL.options,
8301				diff = (index - vars.current);
8302
8303			if (opts.infinite) {
8304				if (index == vars.total - 1 && vars.current == 0) diff = -1;
8305				if (vars.current == vars.total - 1 && index == 0) diff = 1;
8306			}
8307
8308			if (diff == 1) iL.moveTo('next');
8309			else if (diff == -1) iL.moveTo('prev');
8310			else {
8311
8312				if (vars.nextLock || vars.prevLock) return false;
8313
8314				//Trigger the onBeforeChange callback
8315				if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui);
8316
8317				if (opts.linkId) {
8318					vars.hashLock = true;
8319					window.location.hash = opts.linkId + '/' + index;
8320				}
8321
8322				if (iL.items[index]) {
8323					if (!iL.items[index].options.mousewheel) vars.lockWheel = true;
8324					else iL.vars.lockWheel = false;
8325
8326					if (!iL.items[index].options.swipe) vars.lockSwipe = true;
8327					else vars.lockSwipe = false;
8328				}
8329
8330				$.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) {
8331					val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed);
8332				});
8333
8334				vars.current = index;
8335				vars.next = index + 1;
8336				vars.prev = index - 1;
8337
8338				iL.createUI();
8339
8340				setTimeout(function() {
8341					iL.generateBoxes();
8342				}, opts.effects.loadedFadeSpeed + 50);
8343
8344				$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active');
8345				iL.positionThumbnails();
8346
8347				if (opts.linkId) setTimeout(function() {
8348					vars.hashLock = false;
8349				}, 55);
8350
8351				// Configure arrow buttons
8352				if (!opts.infinite) {
8353					vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8354
8355					if (vars.current == 0) {
8356						vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8357					}
8358					if (vars.current >= vars.total - 1) {
8359						vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8360					}
8361				}
8362
8363				// Reset next cycle timeout
8364				iL.resetCycle();
8365
8366				//Trigger the onAfterChange callback
8367				if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui);
8368			}
8369		},
8370
8371		moveTo: function(side) {
8372			var iL = this,
8373				vars = iL.vars,
8374				opts = iL.options,
8375				path = opts.path.toLowerCase(),
8376				viewport = getViewport(),
8377				switchSpeed = opts.effects.switchSpeed;
8378
8379			if (vars.nextLock || vars.prevLock) return false;
8380			else {
8381
8382				var item = (side == "next") ? vars.next : vars.prev;
8383
8384				if (opts.linkId) {
8385					vars.hashLock = true;
8386					window.location.hash = opts.linkId + '/' + item;
8387				}
8388
8389				if (side == "next") {
8390					if (!iL.items[item]) return false;
8391					var firstHolder = vars.nextPhoto,
8392						secondHolder = vars.holder,
8393						lastHolder = vars.prevPhoto,
8394						firstClass = 'ilightbox-prev',
8395						secondClass = 'ilightbox-next';
8396				} else if (side == "prev") {
8397					if (!iL.items[item]) return false;
8398					var firstHolder = vars.prevPhoto,
8399						secondHolder = vars.holder,
8400						lastHolder = vars.nextPhoto,
8401						firstClass = 'ilightbox-next',
8402						secondClass = 'ilightbox-prev';
8403				}
8404
8405				//Trigger the onBeforeChange callback
8406				if (typeof opts.callback.onBeforeChange == 'function')
8407					opts.callback.onBeforeChange.call(iL, iL.ui);
8408
8409				(side == "next") ? vars.nextLock = true: vars.prevLock = true;
8410
8411				var captionFirst = $('div.ilightbox-caption', secondHolder),
8412					socialFirst = $('div.ilightbox-social', secondHolder);
8413
8414				if (captionFirst.length)
8415					captionFirst.stop().fadeOut(switchSpeed, function() {
8416						$(this).remove();
8417					});
8418				if (socialFirst.length)
8419					socialFirst.stop().fadeOut(switchSpeed, function() {
8420						$(this).remove();
8421					});
8422
8423				if (iL.items[item].caption) {
8424					iL.setCaption(iL.items[item], firstHolder);
8425					var caption = $('div.ilightbox-caption', firstHolder),
8426						percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100);
8427					if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed);
8428				}
8429
8430				var social = iL.items[item].options.social;
8431				if (social) {
8432					iL.setSocial(social, iL.items[item].URL, firstHolder);
8433					if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed);
8434				}
8435
8436				$.each([firstHolder, secondHolder, lastHolder], function(key, val) {
8437					val.removeClass('ilightbox-next ilightbox-prev');
8438				});
8439
8440				var firstOffset = firstHolder.data('offset'),
8441					winW = (viewport.width - (opts.styles.pageOffsetX)),
8442					winH = (viewport.height - (opts.styles.pageOffsetY)),
8443					width = firstOffset.newDims.width,
8444					height = firstOffset.newDims.height,
8445					thumbsOffset = firstOffset.thumbsOffset,
8446					diff = firstOffset.diff,
8447					top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)),
8448					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
8449
8450				var secondOffset = secondHolder.data('offset'),
8451					object = secondOffset.object;
8452
8453				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
8454					var objRatio = width / height;
8455					height = height - vars.captionHeight;
8456					width = height * objRatio;
8457					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top,
8458					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
8459				}*/
8460
8461				firstHolder.show().css(transform, gpuAcceleration).animate({
8462					top: top,
8463					left: left,
8464					opacity: 1
8465				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8466					firstHolder.css(transform, '');
8467				});
8468
8469				$('div.ilightbox-container', firstHolder).animate({
8470					width: width,
8471					height: height
8472				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
8473
8474				diff = secondOffset.diff;
8475
8476				width = secondOffset.newDims.width,
8477					height = secondOffset.newDims.height;
8478
8479				width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
8480					height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
8481					top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2));
8482
8483				if (side == 'prev')
8484					left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2));
8485				else {
8486					top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)),
8487					left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2));
8488				}
8489
8490				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
8491					var objRatio = width / height;
8492					height = height - vars.captionHeight;
8493					width = height * objRatio;
8494					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top;
8495				}*/
8496
8497				$('div.ilightbox-container', secondHolder).animate({
8498					width: width,
8499					height: height
8500				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
8501
8502				secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({
8503					top: top,
8504					left: left,
8505					opacity: opts.styles.prevOpacity,
8506				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8507					secondHolder.css(transform, '');
8508
8509					$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active');
8510					iL.positionThumbnails();
8511
8512					if (iL.items[item]) {
8513						if (!iL.items[item].options.mousewheel) vars.lockWheel = true;
8514						else vars.lockWheel = false;
8515
8516						if (!iL.items[item].options.swipe) vars.lockSwipe = true;
8517						else vars.lockSwipe = false;
8518					}
8519
8520					vars.isSwipe = false;
8521
8522					// Remove iframe & video from previous slide
8523					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
8524						$('div.ilightbox-container', secondHolder).empty();
8525					}
8526
8527					if (side == "next") {
8528						vars.nextPhoto = lastHolder,
8529							vars.prevPhoto = secondHolder,
8530							vars.holder = firstHolder;
8531
8532						vars.nextPhoto.hide();
8533
8534						vars.next = vars.next + 1,
8535							vars.prev = vars.current,
8536							vars.current = vars.current + 1;
8537
8538						if (opts.infinite) {
8539							if (vars.current > vars.total - 1) vars.current = 0;
8540							if (vars.current == vars.total - 1) vars.next = 0;
8541							if (vars.current == 0) vars.prev = vars.total - 1;
8542						}
8543
8544						iL.createUI();
8545
8546						if (!iL.items[vars.next])
8547							vars.nextLock = false;
8548						else
8549							iL.loadContent(iL.items[vars.next], 'next');
8550					} else {
8551						vars.prevPhoto = lastHolder;
8552						vars.nextPhoto = secondHolder;
8553						vars.holder = firstHolder;
8554
8555						vars.prevPhoto.hide();
8556
8557						vars.next = vars.current;
8558						vars.current = vars.prev;
8559						vars.prev = vars.current - 1;
8560
8561						if (opts.infinite) {
8562							if (vars.current == vars.total - 1) vars.next = 0;
8563							if (vars.current == 0) vars.prev = vars.total - 1;
8564						}
8565
8566						iL.createUI();
8567
8568						if (!iL.items[vars.prev])
8569							vars.prevLock = false;
8570						else
8571							iL.loadContent(iL.items[vars.prev], 'prev');
8572					}
8573
8574					// Add iframe & video content for current slide
8575					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
8576						iL.loadContent(iL.items[vars.current], 'current');
8577					}
8578
8579					if (opts.linkId) setTimeout(function() {
8580						vars.hashLock = false;
8581					}, 55);
8582
8583					// Configure arrow buttons
8584					if (!opts.infinite) {
8585						vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8586
8587						if (vars.current == 0)
8588							vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8589						if (vars.current >= vars.total - 1)
8590							vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8591					}
8592
8593					iL.repositionPhoto();
8594
8595					// Reset next cycle timeout
8596					iL.resetCycle();
8597
8598					//Trigger the onAfterChange callback
8599					if (typeof opts.callback.onAfterChange == 'function')
8600						opts.callback.onAfterChange.call(iL, iL.ui);
8601				});
8602
8603				top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)),
8604					left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left');
8605
8606				lastHolder.css(transform, gpuAcceleration).animate({
8607					top: top,
8608					left: left,
8609					opacity: opts.styles.nextOpacity
8610				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8611					lastHolder.css(transform, '');
8612				}).addClass(secondClass);
8613			}
8614		},
8615
8616		setCaption: function(obj, target) {
8617			var iL = this,
8618				caption = $('<div class="ilightbox-caption"></div>');
8619
8620			if (obj.caption) {
8621				caption.html(obj.caption);
8622				$('div.ilightbox-container', target).append(caption);
8623			}
8624		},
8625
8626		normalizeSocial: function(obj, url) {
8627			var iL = this,
8628				vars = iL.vars,
8629				opts = iL.options,
8630				baseURL = window.location.href;
8631
8632			$.each(obj, function(key, value) {
8633				if (!value)
8634					return true;
8635
8636				var item = key.toLowerCase(),
8637					source, text;
8638
8639				switch (item) {
8640					case 'facebook':
8641						source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}",
8642							text = "Share on Facebook";
8643						break;
8644					case 'twitter':
8645						source = "http://twitter.com/home?status={URL}",
8646							text = "Share on Twitter";
8647						break;
8648					case 'googleplus':
8649						source = "https://plus.google.com/share?url={URL}",
8650							text = "Share on Google+";
8651						break;
8652					case 'delicious':
8653						source = "http://delicious.com/post?url={URL}",
8654							text = "Share on Delicious";
8655						break;
8656					case 'digg':
8657						source = "http://digg.com/submit?phase=2&url={URL}",
8658							text = "Share on Digg";
8659						break;
8660					case 'reddit':
8661						source = "http://reddit.com/submit?url={URL}",
8662							text = "Share on reddit";
8663						break;
8664				}
8665
8666				obj[key] = {
8667					URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL,
8668					source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url),
8669					text: value.text || text || "Share on " + key,
8670					width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640,
8671					height: value.height || 360
8672				};
8673
8674			});
8675
8676			return obj;
8677		},
8678
8679		setSocial: function(obj, url, target) {
8680			var iL = this,
8681				socialBar = $('<div class="ilightbox-social"></div>'),
8682				buttons = '<ul>';
8683
8684			obj = iL.normalizeSocial(obj, url);
8685
8686			$.each(obj, function(key, value) {
8687				var item = key.toLowerCase(),
8688					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, '+'));
8689				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>';
8690			});
8691
8692			buttons += '</ul>';
8693
8694			socialBar.html(buttons);
8695			$('div.ilightbox-container', target).append(socialBar);
8696		},
8697
8698		fullScreenAction: function() {
8699			var iL = this,
8700				vars = iL.vars;
8701
8702			if (fullScreenApi.supportsFullScreen) {
8703				if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement);
8704				else fullScreenApi.requestFullScreen(document.documentElement);
8705			} else {
8706				iL.doFullscreen();
8707			}
8708		},
8709
8710		doFullscreen: function() {
8711			var iL = this,
8712				vars = iL.vars,
8713				viewport = getViewport(),
8714				opts = iL.options;
8715
8716			if (opts.fullAlone) {
8717				var currentHolder = vars.holder,
8718					current = iL.items[vars.current],
8719					windowWidth = viewport.width,
8720					windowHeight = viewport.height,
8721					elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader],
8722					hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
8723
8724				if (!vars.isInFullScreen) {
8725					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true;
8726					vars.overlay.css({
8727						opacity: 1
8728					});
8729
8730					$.each(hideElements, function(i, element) {
8731						element.hide();
8732					});
8733
8734					vars.fullScreenButton.attr('title', opts.text.exitFullscreen);
8735
8736					if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
8737						naturalWidthOld: currentHolder.data('naturalWidth'),
8738						naturalHeightOld: currentHolder.data('naturalHeight'),
8739						naturalWidth: windowWidth,
8740						naturalHeight: windowHeight
8741					});
8742					else {
8743						var viewport = current.options.fullViewPort || opts.fullViewPort || '',
8744							newWidth = windowWidth,
8745							newHeight = windowHeight,
8746							width = currentHolder.data('naturalWidth'),
8747							height = currentHolder.data('naturalHeight');
8748
8749						if (viewport.toLowerCase() == 'fill') {
8750							newHeight = (newWidth / width) * height;
8751
8752							if (newHeight < windowHeight) {
8753								newWidth = (windowHeight / height) * width,
8754									newHeight = windowHeight;
8755							}
8756						} else if (viewport.toLowerCase() == 'fit') {
8757							var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true);
8758
8759							newWidth = dims.width,
8760								newHeight = dims.height;
8761						} else if (viewport.toLowerCase() == 'stretch') {
8762							newWidth = newWidth,
8763								newHeight = newHeight;
8764						} else {
8765							var scale = (width > newWidth || height > newHeight) ? true : false,
8766								dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale);
8767							newWidth = dims.width,
8768								newHeight = dims.height;
8769						}
8770
8771						currentHolder.data({
8772							naturalWidthOld: currentHolder.data('naturalWidth'),
8773							naturalHeightOld: currentHolder.data('naturalHeight'),
8774							naturalWidth: newWidth,
8775							naturalHeight: newHeight
8776						});
8777					}
8778
8779					$.each(elements, function(key, val) {
8780						val.addClass('ilightbox-fullscreen');
8781					});
8782
8783					//Trigger the onEnterFullScreen callback
8784					if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui);
8785				} else {
8786					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false;
8787					vars.overlay.css({
8788						opacity: iL.options.overlay.opacity
8789					});
8790
8791					$.each(hideElements, function(i, element) {
8792						element.show();
8793					});
8794
8795					vars.fullScreenButton.attr('title', opts.text.enterFullscreen);
8796
8797					currentHolder.data({
8798						naturalWidth: currentHolder.data('naturalWidthOld'),
8799						naturalHeight: currentHolder.data('naturalHeightOld'),
8800						naturalWidthOld: null,
8801						naturalHeightOld: null
8802					});
8803
8804					$.each(elements, function(key, val) {
8805						val.removeClass('ilightbox-fullscreen');
8806					});
8807
8808					//Trigger the onExitFullScreen callback
8809					if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui);
8810				}
8811			} else {
8812				if (!vars.isInFullScreen) vars.isInFullScreen = true;
8813				else vars.isInFullScreen = false;
8814			}
8815			iL.repositionPhoto(true);
8816		},
8817
8818		closeAction: function() {
8819			var iL = this,
8820				vars = iL.vars,
8821				opts = iL.options;
8822
8823			$win.unbind('.iLightBox');
8824			$doc.off('.iLightBox');
8825
8826			if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement);
8827
8828			$('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox');
8829
8830			if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() {
8831				vars.overlay.remove();
8832				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
8833			});
8834			else {
8835				vars.overlay.remove();
8836				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
8837			}
8838
8839			var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
8840
8841			$.each(fadeOuts, function(i, element) {
8842				element.removeAttr('style').remove();
8843			});
8844
8845			vars.dontGenerateThumbs = vars.isInFullScreen = false;
8846
8847			window.iLightBox = null;
8848
8849			if (opts.linkId) {
8850				vars.hashLock = true;
8851				removeHash();
8852				setTimeout(function() {
8853					vars.hashLock = false;
8854				}, 55);
8855			}
8856
8857			//Trigger the onHide callback
8858			if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui);
8859		},
8860
8861		repositionPhoto: function() {
8862			var iL = this,
8863				vars = iL.vars,
8864				opts = iL.options,
8865				path = opts.path.toLowerCase(),
8866				viewport = getViewport(),
8867				winWidth = viewport.width,
8868				winHeight = viewport.height;
8869
8870			if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0;
8871
8872			var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()),
8873				thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)),
8874				width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)),
8875				height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)),
8876				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,
8877				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)));
8878
8879			var elObject = {
8880				type: 'current',
8881				width: width,
8882				height: height,
8883				item: iL.items[vars.current],
8884				offsetW: offsetW,
8885				offsetH: offsetH,
8886				thumbsOffsetW: thumbsOffsetW,
8887				thumbsOffsetH: thumbsOffsetH,
8888				animate: arguments.length,
8889				holder: vars.holder
8890			};
8891
8892			iL.repositionEl(elObject);
8893
8894			if (iL.items[vars.next]) {
8895				elObject = $.extend(elObject, {
8896					type: 'next',
8897					item: iL.items[vars.next],
8898					offsetX: opts.styles.nextOffsetX,
8899					offsetY: opts.styles.nextOffsetY,
8900					holder: vars.nextPhoto
8901				});
8902
8903				iL.repositionEl(elObject);
8904			}
8905
8906			if (iL.items[vars.prev]) {
8907				elObject = $.extend(elObject, {
8908					type: 'prev',
8909					item: iL.items[vars.prev],
8910					offsetX: opts.styles.nextOffsetX,
8911					offsetY: opts.styles.prevOffsetY,
8912					holder: vars.prevPhoto
8913				});
8914
8915				iL.repositionEl(elObject);
8916			}
8917
8918			var loaderCss = (path == "horizontal") ? {
8919				left: parseInt((width / 2) - (vars.loader.outerWidth() / 2))
8920			} : {
8921				top: parseInt((height / 2) - (vars.loader.outerHeight() / 2))
8922			};
8923			vars.loader.css(loaderCss);
8924		},
8925
8926		repositionEl: function(obj) {
8927			var iL = this,
8928				vars = iL.vars,
8929				opts = iL.options,
8930				path = opts.path.toLowerCase(),
8931				widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW),
8932				heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH),
8933				itemParent = obj.item,
8934				item = obj.item.options,
8935				holder = obj.holder,
8936				offsetX = obj.offsetX || 0,
8937				offsetY = obj.offsetY || 0,
8938				thumbsOffsetW = obj.thumbsOffsetW,
8939				thumbsOffsetH = obj.thumbsOffsetH;
8940
8941			if (obj.type == 'current') {
8942				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);
8943				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);
8944			} else {
8945				if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width;
8946				if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height;
8947			}
8948
8949			heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight());
8950
8951			var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'),
8952				height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight');
8953
8954			var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? {
8955					width: width,
8956					height: height
8957				} : iL.getNewDimenstions(widthAvail, heightAvail, width, height)),
8958				newDims = $.extend({}, dims, {});
8959
8960			if (obj.type == 'prev' || obj.type == 'next')
8961				width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)),
8962				height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale));
8963			else
8964				width = dims.width,
8965				height = dims.height;
8966
8967			var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2),
8968				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);
8969
8970			switch (obj.type) {
8971				case 'current':
8972					var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)),
8973						left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2));
8974					break;
8975
8976				case 'next':
8977					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)),
8978						left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2));
8979					break;
8980
8981				case 'prev':
8982					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)),
8983						left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2));
8984					break;
8985			}
8986
8987			holder.data('offset', {
8988				top: top,
8989				left: left,
8990				newDims: newDims,
8991				diff: {
8992					W: widthDiff,
8993					H: heightDiff
8994				},
8995				thumbsOffset: {
8996					W: thumbsOffsetW,
8997					H: thumbsOffsetH
8998				},
8999				object: obj
9000			});
9001
9002			var opacityMobile;
9003			if ( isMobile ) {
9004				opacityMobile = {
9005					opacity: 1,
9006					top: top,
9007					left: left
9008				};
9009			} else {
9010				opacityMobile = {
9011					top: top,
9012					left: left
9013				};
9014			}
9015
9016			if (obj.animate > 0 && opts.effects.reposition) {
9017				holder.css(transform, gpuAcceleration).stop().animate(
9018					opacityMobile, 
9019					opts.effects.repositionSpeed, 'easeOutCirc', function() {
9020					holder.css(transform, '');
9021				});
9022				$('div.ilightbox-container', holder).stop().animate({
9023					width: width,
9024					height: height
9025				}, opts.effects.repositionSpeed, 'easeOutCirc');
9026				$('div.ilightbox-inner-toolbar', holder).stop().animate({
9027					width: width
9028				}, opts.effects.repositionSpeed, 'easeOutCirc', function() {
9029					$(this).css('overflow', 'visible');
9030				});
9031			} else {
9032				holder.css(opacityMobile);
9033				$('div.ilightbox-container', holder).css({
9034					width: width,
9035					height: height
9036				});
9037				$('div.ilightbox-inner-toolbar', holder).css({
9038					width: width
9039				});
9040			}
9041		},
9042
9043
9044		resume: function(priority) {
9045			var iL = this,
9046				vars = iL.vars,
9047				opts = iL.options;
9048
9049			if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) {
9050				return;
9051			}
9052
9053			vars.isPaused = 0;
9054
9055			if (vars.cycleID) {
9056				vars.cycleID = clearTimeout(vars.cycleID);
9057			}
9058
9059			vars.cycleID = setTimeout(function() {
9060				if (vars.current == vars.total - 1) iL.goTo(0);
9061				else iL.moveTo('next');
9062			}, opts.slideshow.pauseTime);
9063		},
9064
9065		pause: function(priority) {
9066			var iL = this,
9067				vars = iL.vars,
9068				opts = iL.options;
9069
9070			if (priority < vars.isPaused) {
9071				return;
9072			}
9073
9074			vars.isPaused = priority || 100;
9075
9076			if (vars.cycleID) {
9077				vars.cycleID = clearTimeout(vars.cycleID);
9078			}
9079		},
9080
9081		resetCycle: function() {
9082			var iL = this,
9083				vars = iL.vars,
9084				opts = iL.options;
9085
9086			if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) {
9087				iL.resume();
9088			}
9089		},
9090
9091		getNewDimenstions: function(width, height, width_old, height_old, thumb) {
9092			var iL = this;
9093
9094			if (!width) factor = height / height_old;
9095			else if (!height) factor = width / width_old;
9096			else factor = min(width / width_old, height / height_old);
9097
9098			if (!thumb) {
9099				if (factor > iL.options.maxScale) factor = iL.options.maxScale;
9100				else if (factor < iL.options.minScale) factor = iL.options.minScale;
9101			}
9102
9103			var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width,
9104				final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height;
9105
9106			return {
9107				width: final_width,
9108				height: final_height,
9109				ratio: factor
9110			};
9111		},
9112
9113		setOption: function(options) {
9114			var iL = this;
9115
9116			iL.options = $.extend(true, iL.options, options || {});
9117			iL.refresh();
9118		},
9119
9120		availPlugins: function() {
9121			var iL = this,
9122				testEl = document.createElement("video");
9123
9124			iL.plugins = {
9125				flash: !isMobile,
9126				quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false,
9127				html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')),
9128				html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')),
9129				html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')),
9130				html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, ''))
9131			};
9132		},
9133
9134		addContent: function(element, obj) {
9135			var iL = this,
9136				el;
9137
9138			switch (obj.type) {
9139				case 'video':
9140					var HTML5 = false,
9141						videoType = obj.videoType,
9142						html5video = obj.options.html5video;
9143
9144					if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264)
9145						obj.ext = 'mp4',
9146						obj.URL = html5video.h264 || obj.URL;
9147					else if (html5video.webm && iL.plugins.html5WebM)
9148						obj.ext = 'webm',
9149						obj.URL = html5video.webm || obj.URL;
9150					else if (html5video.ogg && iL.plugins.html5Vorbis)
9151						obj.ext = 'ogv',
9152						obj.URL = html5video.ogg || obj.URL;
9153
9154					if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4";
9155					else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm";
9156					else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg";
9157					else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime";
9158
9159					if (HTML5) {
9160						el = $('<video />
9160', {
9161							"width": "100%",
9162							"height": "100%",
9163							"preload": html5video.preload,
9164							"autoplay": html5video.autoplay,
9165							"loop": html5video.loop,
9166							"poster": html5video.poster,
9167							"controls": html5video.controls,
9168							"controlslist": "nodownload"
9169						}).append($('<source />', {
9170							"src": obj.URL,
9171							"type": videoType
9172						}));
9173					} else {
9174						if (!iL.plugins.quicktime) el = $('<span />', {
9175							"class": "ilightbox-alert",
9176							html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime')
9177						});
9178						else {
9179
9180							el = $('<object />', {
9181								"type": "video/quicktime",
9182								"pluginspage": pluginspages.quicktime
9183							}).attr({
9184								"data": obj.URL,
9185								"width": "100%",
9186								"height": "100%"
9187							}).append($('<param />', {
9188								"name": "src",
9189								"value": obj.URL
9190							})).append($('<param />', {
9191								"name": "autoplay",
9192								"value": "false"
9193							})).append($('<param />', {
9194								"name": "loop",
9195								"value": "false"
9196							})).append($('<param />', {
9197								"name": "scale",
9198								"value": "tofit"
9199							}));
9200
9201							if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false');
9202						}
9203					}
9204
9205					break;
9206
9207				case 'flash':
9208					if (!iL.plugins.flash) el = $('<span />', {
9209						"class": "ilightbox-alert",
9210						html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player')
9211					});
9212					else {
9213						var flashvars = "",
9214							i = 0;
9215
9216						if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) {
9217							if (i != 0) flashvars += "&";
9218							flashvars += k + "=" + encodeURIComponent(v);
9219							i++;
9220						});
9221						else flashvars = null;
9222
9223						el = $('<embed />').attr({
9224							"type": "application/x-shockwave-flash",
9225							"src": obj.URL,
9226							"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
9227							"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
9228							"quality": "high",
9229							"bgcolor": "#000000",
9230							"play": "true",
9231							"loop": "true",
9232							"menu": "true",
9233							"wmode": "transparent",
9234							"scale": "showall",
9235							"allowScriptAccess": "always",
9236							"allowFullScreen": "true",
9237							"flashvars": flashvars,
9238							"fullscreen": "yes"
9239						});
9240					}
9241
9242					break;
9243
9244				case 'iframe':
9245					el = $('<iframe />').attr({
9246						"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
9247						"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
9248						src: obj.URL,
9249						frameborder: 0,
9250						'hspace': 0,
9251						'vspace': 0,
9252						'scrolling': supportTouch ? 'auto' : 'scroll',
9253						'webkitAllowFullScreen': '',
9254						'mozallowfullscreen': '',
9255						'allowFullScreen': ''
9256					});
9257
9258					break;
9259
9260				case 'inline':
9261					el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true));
9262
9263					break;
9264
9265				case 'html':
9266					var object = obj.URL,
9267						el;
9268
9269					if (object[0].nodeName) {
9270						el = $('<div class="ilightbox-wrapper"></div>').html(object);
9271					} else {
9272						var dom = $(obj.URL),
9273							html = (dom.selector) ? $('<div>' + dom + '</div>') : dom;
9274						el = $('<div class="ilightbox-wrapper"></div>').html(html);
9275					}
9276
9277					break;
9278			}
9279
9280			$('div.ilightbox-container', element).empty().html(el);
9281
9282			// For fixing Chrome about just playing the video for first time
9283			if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() {
9284				var src = el[0].currentSrc + '?' + floor(random() * 30000);
9285				el[0].currentSrc = src;
9286				el[0].src = src;
9287			});
9288
9289			return el;
9290		},
9291
9292		ogpRecognition: function(obj, callback) {
9293			var iL = this,
9294				url = obj.URL;
9295
9296			iL.showLoader();
9297			doAjax(url, function(data) {
9298				iL.hideLoader();
9299				if (data) {
9300					var object = new Object();
9301
9302					object.length = false,
9303					object.url = data.url;
9304
9305					if (data.status == 200) {
9306						var result = data.results,
9307							type = result.type,
9308							source = result.source;
9309
9310						object.source = source.src,
9311						object.width = source.width && parseInt(source.width) || 0,
9312						object.height = source.height && parseInt(source.height) || 0,
9313						object.type = type,
9314						object.thumbnail = source.thumbnail || result.images && result.images[0],
9315						object.html5video = result.html5video || {},
9316						object.length = true;
9317
9318						if (source.type == 'application/x-shockwave-flash') object.type = "flash";
9319						else if (source.type.indexOf("video/") != -1) object.type = "video";
9320						else if (source.type.indexOf("/html") != -1) object.type = "iframe";
9321						else if (source.type.indexOf("image/") != -1) object.type = "image";
9322
9323					} else if (typeof data.response != 'undefined')
9324						throw data.response;
9325
9326					callback.call(this, object.length ? object : false);
9327				}
9328			});
9329		},
9330
9331		hashChangeHandler: function(url) {
9332			var iL = this,
9333				vars = iL.vars,
9334				opts = iL.options,
9335				URL = url || window.location.href,
9336				hash = parseURI(URL).hash,
9337				split = hash.split('/'),
9338				index = split[1];
9339
9340			if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return;
9341
9342			if (index) {
9343				var target = split[1] || 0;
9344				if (iL.items[target]) {
9345					var overlay = $('.ilightbox-overlay');
9346					if (overlay.length && overlay.attr('linkid') == opts.linkId) {
9347						iL.goTo(target);
9348					} else {
9349						iL.itemsObject[target].trigger(supportTouch ? 'itap' : 'click');
9350						//iL.goTo(target);
9351					}
9352				} else {
9353					var overlay = $('.ilightbox-overlay');
9354					if (overlay.length) iL.closeAction();
9355				}
9356			} else {
9357				var overlay = $('.ilightbox-overlay');
9358				if (overlay.length) iL.closeAction();
9359			}
9360		}
9361	};
9362
9363	/**
9364	 * Parse style to pixels.
9365	 *
9366	 * @param {Object}   $element   jQuery object with element.
9367	 * @param {Property} property   CSS property to get the pixels from.
9368	 *
9369	 * @return {Int}
9370	 */
9371	function getPixel($element, property) {
9372		return parseInt($element.css(property), 10) || 0;
9373	}
9374
9375	/**
9376	 * Make sure that number is within the limits.
9377	 *
9378	 * @param {Number} number
9379	 * @param {Number} min
9380	 * @param {Number} max
9381	 *
9382	 * @return {Number}
9383	 */
9384	function within(number, min, max) {
9385		return number < min ? min : number > max ? max : number;
9386	}
9387
9388	/**
9389	 * Get viewport/window size (width and height).
9390	 *
9391	 * @return {Object}
9392	 */
9393	function getViewport() {
9394		var e = window,
9395			a = 'inner';
9396		if (!('innerWidth' in window)) {
9397			a = 'client';
9398			e = document.documentElement || document.body;
9399		}
9400		return {
9401			width: e[a + 'Width'],
9402			height: e[a + 'Height']
9403		}
9404	}
9405
9406	/**
9407	 * Remove hash tag from the URL
9408	 *
9409	 * @return {Void}
9410	 */
9411	function removeHash() {
9412		var scroll = getScrollXY();
9413
9414		//UNCODE change		
9415		//window.location.hash = "";
9416		history.pushState("", document.title, window.location.pathname + window.location.search);
9417
9418		// Restore the scroll offset, should be flicker free
9419		window.scrollTo(scroll.x, scroll.y);
9420	}
9421
9422	/**
9423	 * Do the ajax requests with callback.
9424	 *
9425	 * @param {String}   url
9426	 * @param {Function} callback
9427	 *
9428	 * @return {Void}
9429	 */
9430	function doAjax(url, callback) {
9431		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');
9432		$.ajax({
9433			url: url,
9434			dataType: 'jsonp'
9435		});
9436
9437		iLCallback = function(data) {
9438			callback.call(this, data);
9439		};
9440	}
9441
9442	/**
9443	 * Find image from DOM elements
9444	 *
9445	 * @param {Element} element
9446	 *
9447	 * @return {Void}
9448	 */
9449	function findImageInElement(element) {
9450		var elements = $('*', element),
9451			imagesArr = new Array();
9452
9453		elements.each(function() {
9454			var url = "",
9455				element = this;
9456
9457			if ($(element).css("background-image") != "none") {
9458				url = $(element).css("background-image");
9459			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
9460				url = $(element).attr("src");
9461			}
9462
9463			if (url.indexOf("gradient") == -1) {
9464				url = url.replace(/url\(\"/g, "");
9465				url = url.replace(/url\(/g, "");
9466				url = url.replace(/\"\)/g, "");
9467				url = url.replace(/\)/g, "");
9468
9469				var urls = url.split(",");
9470
9471				for (var i = 0; i < urls.length; i++) {
9472					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
9473						var extra = "";
9474						if (browser.msie && browser.version < 9) {
9475							extra = "?" + floor(random() * 3000);
9476						}
9477						imagesArr.push(urls[i] + extra);
9478					}
9479				}
9480			}
9481		});
9482
9483		return imagesArr;
9484	}
9485
9486	/**
9487	 * Get file extension.
9488	 *
9489	 * @param {String} URL
9490	 *
9491	 * @return {String}
9492	 */
9493	function getExtension(URL) {
9494		if (URL !== null) {
9495			var ext = URL.split('.').pop().toLowerCase(),
9496				extra = ext.indexOf('?') !== -1 ? ext.split('?').pop() : '';
9497
9498			//UNCODE: fix issue to detect media type with query strings
9499			ext = ext.replace('?'+extra, '');
9500
9501			return ext.replace(extra, '');
9502		}
9503	}
9504
9505	/**
9506	 * Get type via extension.
9507	 *
9508	 * @param {String} URL
9509	 *
9510	 * @return {String}
9511	 */
9512	function getTypeByExtension(URL) {
9513		var type,
9514			ext = getExtension(URL);
9515
9516		if (extensions.image.indexOf(ext) !== -1) type = 'image';
9517		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
9518		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
9519		else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition
9520		else type = 'iframe';
9521		
9522		return type;
9523	}
9524
9525	/**
9526	 * Return value from percent of a number.
9527	 *
9528	 * @param {Number} percent
9529	 * @param {Number} total
9530	 *
9531	 * @return {Number}
9532	 */
9533	function percentToValue(percent, total) {
9534		return parseInt((total / 100) * percent);
9535	}
9536
9537	/**
9538	 * A JavaScript equivalent of PHP’s parse_url.
9539	 *
9540	 * @param {String} url           The URL to parse.
9541	 *
9542	 * @return {Mixed}
9543	 */
9544	function parseURI(url) {
9545		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
9546		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
9547		return (m ? {
9548			href: m[0] || '',
9549			protocol: m[1] || '',
9550			authority: m[2] || '',
9551			host: m[3] || '',
9552			hostname: m[4] || '',
9553			port: m[5] || '',
9554			pathname: m[6] || '',
9555			search: m[7] || '',
9556			hash: m[8] || ''
9557		} : null);
9558	}
9559
9560	/**
9561	 * Gets the absolute URI.
9562	 *
9563	 * @param {String} href     The relative URL.
9564	 * @param {String} base     The base URL.
9565	 *
9566	 * @return {String}         The absolute URL.
9567	 */
9568	function absolutizeURI(base, href) { // RFC 3986
9569		var iL = this;
9570
9571		function removeDotSegments(input) {
9572			var output = [];
9573			input.replace(/^(\.\.?(\/|$))+/, '')
9574				.replace(/\/(\.(\/|$))+/g, '/')
9575				.replace(/\/\.\.$/, '/../')
9576				.replace(/\/?[^\/]*/g, function(p) {
9577					if (p === '/..') {
9578						output.pop();
9579					} else {
9580						output.push(p);
9581					}
9582				});
9583			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
9584		}
9585
9586		href = parseURI(href || '');
9587		base = parseURI(base || '');
9588
9589		return !href || !base ? null : (href.protocol || base.protocol) +
9590			(href.protocol || href.authority ? href.authority : base.authority) +
9591			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)) +
9592			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
9593			href.hash;
9594	}
9595
9596	/**
9597	 * A JavaScript equivalent of PHP’s version_compare.
9598	 *
9599	 * @param {String} v1
9600	 * @param {String} v2
9601	 * @param {String} operator
9602	 *
9603	 * @return {Boolean}
9604	 */
9605	function version_compare(v1, v2, operator) {
9606		this.php_js = this.php_js || {};
9607		this.php_js.ENV = this.php_js.ENV || {};
9608		var i = 0,
9609			x = 0,
9610			compare = 0,
9611			vm = {
9612				'dev': -6,
9613				'alpha': -5,
9614				'a': -5,
9615				'beta': -4,
9616				'b': -4,
9617				'RC': -3,
9618				'rc': -3,
9619				'#': -2,
9620				'p': 1,
9621				'pl': 1
9622			},
9623			prepVersion = function(v) {
9624				v = ('' + v).replace(/[_\-+]/g, '.');
9625				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
9626				return (!v.length ? [-8] : v.split('.'));
9627			},
9628			numVersion = function(v) {
9629				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
9630			};
9631		v1 = prepVersion(v1);
9632		v2 = prepVersion(v2);
9633		x = max(v1.length, v2.length);
9634		for (i = 0; i < x; i++) {
9635			if (v1[i] == v2[i]) {
9636				continue;
9637			}
9638			v1[i] = numVersion(v1[i]);
9639			v2[i] = numVersion(v2[i]);
9640			if (v1[i] < v2[i]) {
9641				compare = -1;
9642				break;
9643			} else if (v1[i] > v2[i]) {
9644				compare = 1;
9645				break;
9646			}
9647		}
9648		if (!operator) {
9649			return compare;
9650		}
9651
9652		switch (operator) {
9653			case '>':
9654			case 'gt':
9655				return (compare > 0);
9656			case '>=':
9657			case 'ge':
9658				return (compare >= 0);
9659			case '<=':
9660			case 'le':
9661				return (compare <= 0);
9662			case '==':
9663			case '=':
9664			case 'eq':
9665				return (compare === 0);
9666			case '<>':
9667			case '!=':
9668			case 'ne':
9669				return (compare !== 0);
9670			case '':
9671			case '<':
9672			case 'lt':
9673				return (compare < 0);
9674			default:
9675				return null;
9676		}
9677	}
9678
9679
9680	// Begin the iLightBox plugin
9681	$.fn.iLightBox = function() {
9682
9683		var args = arguments,
9684			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
9685			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
9686
9687		if (!opt) opt = {};
9688
9689		// Default options. Play carefully.
9690		var options = $.extend(true, {
9691			attr: 'href',
9692			path: 'vertical',
9693			skin: 'dark',
9694			linkId: false,
9695			infinite: false,
9696			startFrom: 0,
9697			randomStart: false,
9698			keepAspectRatio: true,
9699			maxScale: 1,
9700			minScale: .2,
9701			innerToolbar: false,
9702			smartRecognition: false,
9703			mobileOptimizer: true,
9704			fullAlone: true,
9705			fullViewPort: null,
9706			fullStretchTypes: 'flash, video',
9707			overlay: {
9708				blur: true,
9709				opacity: .85
9710			},
9711			controls: {
9712				arrows: false,
9713				slideshow: false,
9714				toolbar: true,
9715				fullscreen: true,
9716				thumbnail: true,
9717				keyboard: true,
9718				mousewheel: true,
9719				swipe: true
9720			},
9721			keyboard: {
9722				left: true, // previous
9723				right: true, // next
9724				up: true, // previous
9725				down: true, // next
9726				esc: true, // close
9727				shift_enter: true // fullscreen
9728			},
9729			show: {
9730				effect: true,
9731				speed: 300,
9732				title: true
9733			},
9734			hide: {
9735				effect: true,
9736				speed: 300
9737			},
9738			caption: {
9739				start: true,
9740				show: 'mouseenter',
9741				hide: 'mouseleave'
9742			},
9743			social: {
9744				start: true,
9745				show: 'mouseenter',
9746				hide: 'mouseleave',
9747				buttons: false
9748			},
9749			styles: {
9750				pageOffsetX: 0,
9751				pageOffsetY: 0,
9752				nextOffsetX: 45,
9753				nextOffsetY: 0,
9754				nextOpacity: 1,
9755				nextScale: 1,
9756				prevOffsetX: 45,
9757				prevOffsetY: 0,
9758				prevOpacity: 1,
9759				prevScale: 1
9760			},
9761			thumbnails: {
9762				maxWidth: 120,
9763				maxHeight: 80,
9764				normalOpacity: 1,
9765				activeOpacity: .6
9766			},
9767			effects: {
9768				reposition: true,
9769				repositionSpeed: 200,
9770				switchSpeed: 500,
9771				loadedFadeSpeed: 180,
9772				fadeSpeed: 200
9773			},
9774			slideshow: {
9775				pauseTime: 5000,
9776				pauseOnHover: false,
9777				startPaused: true
9778			},
9779			text: {
9780				close: "Press Esc to close",
9781				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
9782				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
9783				slideShow: "Slideshow",
9784				next: "Next",
9785				previous: "Previous"
9786			},
9787			errors: {
9788				loadImage: "An error occurred when trying to load photo.",
9789				loadContents: "An error occurred when trying to load contents.",
9790				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
9791			},
9792			ajaxSetup: {
9793				url: '',
9794				beforeSend: function(jqXHR, settings) {},
9795				cache: false,
9796				complete: function(jqXHR, textStatus) {},
9797				crossDomain: false,
9798				error: function(jqXHR, textStatus, errorThrown) {},
9799				success: function(data, textStatus, jqXHR) {},
9800				global: true,
9801				ifModified: false,
9802				username: null,
9803				password: null,
9804				type: 'GET'
9805			},
9806			callback: {}
9807		}, opt);
9808
9809		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
9810
9811		items = $.isArray(items) ? items : new Array();
9812
9813		if (typeof args[0] == 'string') items[0] = args[0];
9814
9815		if (version_compare($.fn.jquery, '1.8', '>=')) {
9816			var iLB = new iLightBox($(this), options, items, instant);
9817			return {
9818				close: function() {
9819					iLB.closeAction();
9820				},
9821				fullscreen: function() {
9822					iLB.fullScreenAction();
9823				},
9824				moveNext: function() {
9825					iLB.moveTo('next');
9826				},
9827				movePrev: function() {
9828					iLB.moveTo('prev');
9829				},
9830				goTo: function(index) {
9831					iLB.goTo(index);
9832				},
9833				refresh: function() {
9834					iLB.refresh();
9835				},
9836				reposition: function() {
9837					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
9838				},
9839				setOption: function(options) {
9840					iLB.setOption(options);
9841				},
9842				destroy: function() {
9843					iLB.closeAction();
9844					iLB.dispatchItemsEvents();
9845				}
9846			};
9847		} else {
9848			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
9849		}
9850
9851	};
9852
9853
9854	$.iLightBox = function() {
9855		return $.fn.iLightBox(arguments[0], arguments[1]);
9856	};
9857
9858
9859	$.extend($.easing, {
9860		easeInCirc: function(x, t, b, c, d) {
9861			return -c * (sqrt(1 - (t /= d) * t) - 1) + b;
9862		},
9863		easeOutCirc: function(x, t, b, c, d) {
9864			return c * sqrt(1 - (t = t / d - 1) * t) + b;
9865		},
9866		easeInOutCirc: function(x, t, b, c, d) {
9867			if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b;
9868			return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b;
9869		}
9870	});
9871
9872	function getScrollXY() {
9873		var scrOfX = 0,
9874			scrOfY = 0;
9875		if (typeof(window.pageYOffset) == 'number') {
9876			//Netscape compliant
9877			scrOfY = window.pageYOffset;
9878			scrOfX = window.pageXOffset;
9879		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
9880			//DOM compliant
9881			scrOfY = document.body.scrollTop;
9882			scrOfX = document.body.scrollLeft;
9883		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
9884			//IE6 standards compliant mode
9885			scrOfY = document.documentElement.scrollTop;
9886			scrOfX = document.documentElement.scrollLeft;
9887		}
9888		return {
9889			x: scrOfX,
9890			y: scrOfY
9891		};
9892	}
9893
9894	(function() {
9895		// add new event shortcuts
9896		$.each(("touchstart touchmove touchend " +
9897			"tap taphold " +
9898			"swipe swipeleft swiperight " +
9899			"scrollstart scrollstop").split(" "), function(i, name) {
9900
9901			$.fn[name] = function(fn) {
9902				return fn ? this.bind(name, fn) : this.trigger(name);
9903			};
9904
9905			// jQuery < 1.8
9906			// if ($.attrFn) {
9907			// 	$.attrFn[name] = true;
9908			// }
9909		});
9910
9911		var tapSettings = {
9912			startEvent: 'touchstart.iTap',
9913			endEvent: 'touchend.iTap'
9914		};
9915
9916		// tap Event:
9917		$.event.special.itap = {
9918			setup: function() {
9919
9920				var self = this,
9921					$self = $(this),
9922					start, stop;
9923
9924				$self.bind(tapSettings.startEvent, function(event) {
9925					start = getScrollXY();
9926
9927					$self.one(tapSettings.endEvent, function(event) {
9928						stop = getScrollXY();
9929
9930						var orgEvent = event || window.event;
9931						event = $.event.fix(orgEvent);
9932						event.type = "itap";
9933
9934						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
9935
9936						start = stop = undefined;
9937					});
9938				});
9939			},
9940
9941			teardown: function() {
9942				$(this).unbind(tapSettings.startEvent);
9943			}
9944		};
9945	}());
9946
9947
9948	//Fullscreen API
9949	(function() {
9950		fullScreenApi = {
9951				supportsFullScreen: false,
9952				isFullScreen: function() {
9953					return false;
9954				},
9955				requestFullScreen: function() {},
9956				cancelFullScreen: function() {},
9957				fullScreenEventName: '',
9958				prefix: ''
9959			},
9960			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
9961
9962		// check for native support
9963		if (typeof document.cancelFullScreen != 'undefined') {
9964			fullScreenApi.supportsFullScreen = true;
9965		} else {
9966			// check for fullscreen support by vendor prefix
9967			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
9968				fullScreenApi.prefix = browserPrefixes[i];
9969
9970				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
9971					fullScreenApi.supportsFullScreen = true;
9972
9973					break;
9974				}
9975			}
9976		}
9977
9978		// update methods to do something useful
9979		if (fullScreenApi.supportsFullScreen) {
9980			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
9981
9982			fullScreenApi.isFullScreen = function() {
9983				switch (this.prefix) {
9984					case '':
9985						return document.fullScreen;
9986					case 'webkit':
9987						return document.webkitIsFullScreen;
9988					default:
9989						return document[this.prefix + 'FullScreen'];
9990				}
9991			}
9992			fullScreenApi.requestFullScreen = function(el) {
9993				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
9994			}
9995			fullScreenApi.cancelFullScreen = function(el) {
9996				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
9997			}
9998		}
9999	}());
10000
10001	// Browser detect
10002	(function() {
10003		function uaMatch(ua) {
10004			ua = ua.toLowerCase();
10005
10006			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
10007				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
10008				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
10009				/(msie) ([\w.]+)/.exec(ua) ||
10010				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
10011
10012			return {
10013				browser: match[1] || "",
10014				version: match[2] || "0"
10015			};
10016		}
10017
10018		var matched = uaMatch(navigator.userAgent);
10019		browser = {};
10020
10021		if (matched.browser) {
10022			browser[matched.browser] = true;
10023			browser.version = matched.version;
10024		}
10025
10026		// Chrome is Webkit, but Webkit is also Safari.
10027		if (browser.chrome) {
10028			browser.webkit = true;
10029		} else if (browser.webkit) {
10030			browser.safari = true;
10031		}
10032	}());
10033
10034	// Feature detects
10035	(function() {
10036		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
10037		var el = document.createElement('div');
10038
10039		function testProp(prop) {
10040			for (var p = 0, pl = prefixes.length; p < pl; p++) {
10041				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
10042				if (el.style[prefixedProp] !== undefined) {
10043					return prefixedProp;
10044				}
10045			}
10046		}
10047
10048		// Global support indicators
10049		transform = testProp('transform') || '';
10050		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
10051	}());
10052
10053
10054	/*
10055		PluginDetect v0.7.9
10056		www.pinlady.net/PluginDetect/license/
10057		[ getVersion onWindowLoaded BetterIE ]
10058		[ Flash QuickTime Shockwave ]
10059	*/
10060	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;
10060d++){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);
10060d.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)}
10060c.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;
10060if(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();
10061
10062	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)};
10063
10064
10065	/*
10066		jQuery hashchange event v1.3
10067		https://github.com/cowboy/jquery-hashchange
10068		Copyright (c) 2010 "Cowboy" Ben Alman
10069		Dual licensed under the MIT and GPL licenses.
10070	*/
10071	(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=
10072	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||
10073	"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;
10073a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
10074
10075	if (!Array.prototype.filter) {
10076		Array.prototype.filter = function(fun /*, thisp */ ) {
10077			"use strict";
10078
10079			if (this == null)
10080				throw new TypeError();
10081
10082			var t = Object(this);
10083			var len = t.length >>> 0;
10084			if (typeof fun != "function")
10085				throw new TypeError();
10086
10087			var res = [];
10088			var thisp = arguments[1];
10089			for (var i = 0; i < len; i++) {
10090				if (i in t) {
10091					var val = t[i]; // in case fun mutates this
10092					if (fun.call(thisp, val, i, t))
10093						res.push(val);
10094				}
10095			}
10096
10097			return res;
10098		};
10099	}
10100
10101	if (!Array.prototype.indexOf) {
10102		Array.prototype.indexOf = function(searchElement, fromIndex) {
10103			var k;
10104
10105			if (this == null) {
10106				throw new TypeError('"this" is null or not defined');
10107			}
10108
10109			var O = Object(this);
10110
10111			var len = O.length >>> 0;
10112
10113			if (len === 0) {
10114				return -1;
10115			}
10116
10117			var n = +fromIndex || 0;
10118
10119			if (abs(n) === Infinity) {
10120				n = 0;
10121			}
10122
10123			if (n >= len) {
10124				return -1;
10125			}
10126
10127			k = max(n >= 0 ? n : len - abs(n), 0);
10128
10129			while (k < len) {
10130				var kValue;
10131				if (k in O && O[k] === searchElement) {
10132					return k;
10133				}
10134				k++;
10135			}
10136			return -1;
10137		};
10138	}
10139
10140	if (!Array.prototype.lastIndexOf) {
10141		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
10142			"use strict";
10143
10144			if (this == null)
10145				throw new TypeError();
10146
10147			var t = Object(this);
10148			var len = t.length >>> 0;
10149			if (len === 0)
10150				return -1;
10151
10152			var n = len;
10153			if (arguments.length > 1) {
10154				n = Number(arguments[1]);
10155				if (n != n)
10156					n = 0;
10157				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
10158					n = (n > 0 || -1) * floor(abs(n));
10159			}
10160
10161			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
10162
10163			for (; k >= 0; k--) {
10164				if (k in t && t[k] === searchElement)
10165					return k;
10166			}
10167			return -1;
10168		};
10169	}
10170})(jQuery, this);
10171
10172/**
10173 * Owl carousel
vendor: 12,109 bytes, lines 10174-10680
10174 * @version 2.0.0-beta.3
10175 * @author Bartosz Wojciechowski
10176 * @license The MIT License (MIT)
10177 * @todo Lazy Load Icon
10178 * @todo prevent animationend bubling
10179 * @todo itemsScaleUp
10180 * @todo Test Zepto
10181 * @todo stagePadding calculate wrong active classes
10182 */
10183;(function($, window, document, undefined) {
10184
10185	/**
10186	 * Creates a carousel.
10187	 * @class The Owl Carousel.
10188	 * @public
10189	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
10190	 * @param {Object} [options] - The options
10191	 */
10192	function Owl(element, options) {
10193
10194		/**
10195		 * Current settings for the carousel.
10196		 * @public
10197		 */
10198		this.settings = null;
10199
10200		/**
10201		 * Current options set by the caller including defaults.
10202		 * @public
10203		 */
10204		this.options = $.extend({}, Owl.Defaults, options);
10205 
10206		/**
10207		 * Plugin element.
10208		 * @public
10209		 */
10210		this.$element = $(element);
10211
10212		/**
10213		 * Proxied event handlers.
10214		 * @protected
10215		 */
10216		this._handlers = {};
10217
10218		/**
10219		 * References to the running plugins of this carousel.
10220		 * @protected
10221		 */
10222		this._plugins = {};
10223
10224		/**
10225		 * Currently suppressed events to prevent them from beeing retriggered.
10226		 * @protected
10227		 */
10228		this._supress = {};
10229
10230		/**
10231		 * Absolute current position.
10232		 * @protected
10233		 */
10234		this._current = null;
10235
10236		/**
10237		 * Animation speed in milliseconds.
10238		 * @protected
10239		 */
10240		this._speed = null;
10241
10242		/**
10243		 * Coordinates of all items in pixel.
10244		 * @todo The name of this member is missleading.
10245		 * @protected
10246		 */
10247		this._coordinates = [];
10248
10249		/**
10250		 * Current breakpoint.
10251		 * @todo Real media queries would be nice.
10252		 * @protected
10253		 */
10254		this._breakpoint = null;
10255
10256		/**
10257		 * Current width of the plugin element.
10258		 */
10259		this._width = null;
10260
10261		/**
10262		 * All real items.
10263		 * @protected
10264		 */
10265		this._items = [];
10266
10267		/**
10268		 * All cloned items.
10269		 * @protected
10270		 */
10271		this._clones = [];
10272
10273		/**
10274		 * Merge values of all items.
10275		 * @todo Maybe this could be part of a plugin.
10276		 * @protected
10277		 */
10278		this._mergers = [];
10279
10280		/**
10281		 * Widths of all items.
10282		 */
10283		this._widths = [];
10284
10285		/**
10286		 * Invalidated parts within the update process.
10287		 * @protected
10288		 */
10289		this._invalidated = {};
10290
10291		/**
10292		 * Ordered list of workers for the update process.
10293		 * @protected
10294		 */
10295		this._pipe = [];
10296
10297		/**
10298		 * Current state information for the drag operation.
10299		 * @todo #261
10300		 * @protected
10301		 */
10302		this._drag = {
10303			time: null,
10304			target: null,
10305			pointer: null,
10306			stage: {
10307				start: null,
10308				current: null
10309			},
10310			direction: null
10311		};
10312
10313		/**
10314		 * Current state information and their tags.
10315		 * @type {Object}
10316		 * @protected
10317		 */
10318		this._states = {
10319			current: {},
10320			tags: {
10321				'initializing': [ 'busy' ],
10322				'animating': [ 'busy' ],
10323				'dragging': [ 'interacting' ]
10324			}
10325		};
10326
10327		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
10328			this._handlers[handler] = $.proxy(this[handler], this);
10329		}, this));
10330
10331		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
10332			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
10333				= new plugin(this);
10334		}, this));
10335
10336		$.each(Owl.Workers, $.proxy(function(priority, worker) {
10337			this._pipe.push({
10338				'filter': worker.filter,
10339				'run': $.proxy(worker.run, this)
10340			});
10341		}, this));
10342
10343		this.setup();
10344		this.initialize();
10345	}
10346
10347	/**
10348	 * Default options for the carousel.
10349	 * @public
10350	 */
10351	Owl.Defaults = {
10352		items: 3,
10353		loop: false,
10354		center: false,
10355		rewind: false,
10356
10357		mouseDrag: true,
10358		touchDrag: true,
10359		pullDrag: true,
10360		freeDrag: false,
10361
10362		margin: 0,
10363		stagePadding: 0,
10364
10365		merge: false,
10366		mergeFit: true,
10367		autoWidth: false,
10368
10369		startPosition: 0,
10370		rtl: false,
10371
10372		smartSpeed: 250,
10373		fluidSpeed: false,
10374		dragEndSpeed: false,
10375
10376		responsive: {},
10377		responsiveRefreshRate: 200,
10378		responsiveBaseElement: window,
10379
10380		fallbackEasing: 'swing',
10381
10382		info: false,
10383
10384		nestedItemSelector: false,
10385		itemElement: 'div',
10386		stageElement: 'div',
10387
10388		refreshClass: 'owl-refresh',
10389		loadedClass: 'owl-loaded',
10390		loadingClass: 'owl-loading',
10391		rtlClass: 'owl-rtl',
10392		responsiveClass: 'owl-responsive',
10393		dragClass: 'owl-drag',
10394		itemClass: 'owl-item',
10395		stageClass: 'owl-stage',
10396		stageOuterClass: 'owl-stage-outer',
10397		grabClass: 'owl-grab'
10398	};
10399
10400	/**
10401	 * Enumeration for width.
10402	 * @public
10403	 * @readonly
10404	 * @enum {String}
10405	 */
10406	Owl.Width = {
10407		Default: 'default',
10408		Inner: 'inner',
10409		Outer: 'outer'
10410	};
10411
10412	/**
10413	 * Enumeration for types.
10414	 * @public
10415	 * @readonly
10416	 * @enum {String}
10417	 */
10418	Owl.Type = {
10419		Event: 'event',
10420		State: 'state'
10421	};
10422
10423	/**
10424	 * Contains all registered plugins.
10425	 * @public
10426	 */
10427	Owl.Plugins = {};
10428
10429	/**
10430	 * List of workers involved in the update process.
10431	 */
10432	Owl.Workers = [ {
10433		filter: [ 'width', 'settings' ],
10434		run: function() {
10435			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
10436			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
10437		}
10438	}, {
10439		filter: [ 'width', 'items', 'settings' ],
10440		run: function(cache) {
10441			cache.current = this._items && this._items[this.relative(this._current)];
10442		}
10443	}, {
10444		filter: [ 'items', 'settings' ],
10445		run: function() {
10446			this.$stage.children('.cloned').remove();
10447		}
10448	}, {
10449		filter: [ 'width', 'items', 'settings' ],
10450		run: function(cache) {
10451			var margin = this.settings.margin || '',
10452				grid = !this.settings.autoWidth,
10453				rtl = this.settings.rtl,
10454				css = {
10455					'width': 'auto',
10456					'margin-left': rtl ? margin : '',
10457					'margin-right': rtl ? '' : margin
10458				};
10459
10460			!grid && this.$stage.children().css(css);
10461
10462			cache.css = css;
10463		}
10464	}, {
10465		filter: [ 'width', 'items', 'settings' ],
10466		run: function(cache) {
10467			//UNCODE edit to fix Chrome stage padding issue
10468			var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin),
10469				merge = null,
10470				iterator = this._items.length,
10471				grid = !this.settings.autoWidth,
10472				widths = [];
10473
10474			cache.items = {
10475				merge: false,
10476				width: width
10477			};
10478
10479			while (iterator--) {
10480				merge = this._mergers[iterator];
10481				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
10482
10483				cache.items.merge = merge > 1 || cache.items.merge;
10484
10485				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
10486			}
10487
10488			this._widths = widths;
10489		}
10490	}, {
10491		filter: [ 'items', 'settings' ],
10492		run: function() {
10493			var clones = [],
10494				items = this._items,
10495				settings = this.settings,
10496				view = Math.max(settings.items * 2, 4),
10497				size = Math.ceil(items.length / 2) * 2,
10498				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
10499				append = '',
10500				prepend = '';
10501
10502			repeat /= 2;
10503
10504			while (repeat--) {
10505				clones.push(this.normalize(clones.length / 2, true));
10506				append = append + items[clones[clones.length - 1]][0].outerHTML;
10507				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
10508				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
10509			}
10510
10511			this._clones = clones;
10512
10513			// var appendVideo = $(append).find('.uncode-video-container');
10514			// if (appendVideo.length) {
10515			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
10516			// }
10517			// var prependVideo = $(prepend).find('.uncode-video-container');
10518			// if (prependVideo.length) {
10519			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
10520			// }
10521			$(append).addClass('cloned').appendTo(this.$stage);
10522			$(prepend).addClass('cloned').prependTo(this.$stage);
10523		}
10524	}, {
10525		filter: [ 'width', 'items', 'settings' ],
10526		run: function() {
10527			var rtl = this.settings.rtl ? 1 : -1,
10528				size = this._clones.length + this._items.length,
10529				iterator = -1,
10530				previous = 0,
10531				current = 0,
10532				coordinates = [];
10533
10534			while (++iterator < size) {
10535				previous = coordinates[iterator - 1] || 0;
10536				current = this._widths[this.relative(iterator)] + this.settings.margin;
10537				coordinates.push(previous + current * rtl);
10538			}
10539
10540			this._coordinates = coordinates;
10541		}
10542	}, {
10543		filter: [ 'width', 'items', 'settings' ],
10544		run: function() {
10545			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
10546				padding = stagePadding,
10547				coordinates = this._coordinates,
10548				css = {
10549					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
10550					'padding-left': padding || '',
10551					'padding-right': padding || ''
10552				};
10553
10554			this.$stage.css(css);
10555		}
10556	}, {
10557		filter: [ 'width', 'items', 'settings' ],
10558		run: function(cache) {
10559			var iterator = this._coordinates.length,
10560				grid = !this.settings.autoWidth,
10561				items = this.$stage.children();
10562
10563			if (grid && cache.items.merge) {
10564				while (iterator--) {
10565					cache.css.width = this._widths[this.relative(iterator)];
10566					items.eq(iterator).css(cache.css);
10567				}
10568			} else if (grid) {
10569				cache.css.width = cache.items.width;
10570				items.css(cache.css);
10571			}
10572		}
10573	}, {
10574		filter: [ 'items' ],
10575		run: function() {
10576			this._coordinates.length < 1 && this.$stage.removeAttr('style');
10577		}
10578	}, {
10579		filter: [ 'width', 'items', 'settings' ],
10580		run: function(cache) {
10581			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
10582			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
10583			this.reset(cache.current);
10584		}
10585	}, {
10586		filter: [ 'position' ],
10587		run: function() {
10588			this.animate(this.coordinates(this._current));
10589		}
10590	}, {
10591		filter: [ 'width', 'position', 'items', 'settings' ],
10592		run: function() {
10593			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
10594				rtl = this.settings.rtl ? 1 : -1,
10595				padding = this.settings.stagePadding * 2,
10596				begin = this.coordinates(this.current()) + padding,
10597				end = begin + this.width() * rtl,
10598				inner, outer, matches = [], i, n;
10599
10600			for (i = 0, n = this._coordinates.length; i < n; i++) {
10601				inner = this._coordinates[i - 1] || 0;
10602				outer = Math.abs(this._coordinates[i]) + padding * rtl;
10603
10604				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
10605					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
10606					matches.push(i);
10607				}
10608			}
10609
10610			this.$stage.children('.active').removeClass('active');
10611			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
10612
10613			if (this.settings.center) {
10614				this.$stage.children('.center').removeClass('center');
10615				this.$stage.children().eq(this.current()).addClass('center');
10616			}
10617		}
10618	} ];
10619
10620	/**
10621	 * Initializes the carousel.
10622	 * @protected
10623	 */
10624	Owl.prototype.initialize = function() {
10625		this.enter('initializing');
10626		this.trigger('initialize');
10627
10628		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
10629
10630		if (this.settings.autoWidth && !this.is('pre-loading')) {
10631			var imgs, nestedSelector, width;
10632			imgs = this.$element.find('img');
10633			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
10634			width = this.$element.children(nestedSelector).width();
10635
10636			if (imgs.length && width <= 0) {
10637				this.preloadAutoWidthImages(imgs);
10638			}
10639		}
10640
10641		this.$element.addClass(this.options.loadingClass);
10642
10643		// create stage
10644		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
10645			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
10646
10647		// append stage
10648		this.$element.append(this.$stage.parent());
10649
10650		// append content
10651		this.replace(this.$element.children().not(this.$stage.parent()));
10652
10653		// check visibility
10654		if (this.$element.is(':visible')) {
10655			// update view
10656			this.refresh();
10657		} else {
10658			// invalidate width
10659			this.invalidate('width');
10660		}
10661
10662		this.$element
10663			.removeClass(this.options.loadingClass)
10664			.addClass(this.options.loadedClass);
10665
10666		// register event handlers
10667		this.registerEventHandlers();
10668
10669		this.leave('initializing');
10670		this.trigger('initialized');
10671	};
10672
10673	/**
10674	 * Setups the current settings.
10675	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
10676	 * @todo Support for media queries by using `matchMedia` would be nice.
10677	 * @public
10678	 */
10679	Owl.prototype.setup = function() {
10680		var viewport = this.viewport(),
10681			overwrites = this.options.responsive,
10682			match = -1,
10683			settings = null;
10684
10685		if (!overwrites) {
10686			settings = $.extend({}, this.options);
10687		} else {
10688			$.each(overwrites, function(breakpoint) {
10689				if (breakpoint <= viewport && breakpoint > match) {
10690					match = Number(breakpoint);
10691				}
10692			});
10693
10694			settings = $.extend({}, this.options, overwrites[match]);
10695			delete settings.responsive;
10696
10697			// responsive class
10698			if (settings.responsiveClass) {
10699				this.$element.attr('class',
10700					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
10701				);
10702			}
10703		}
10704
10705		if (this.settings === null || this._breakpoint !== match) {
10706			this.trigger('change', { property: { name: 'settings', value: settings } });
10707			this._breakpoint = match;
10708			this.settings = settings;
10709			this.invalidate('settings');
10710			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
10711		}
10712	};
10713
10714	/**
10715	 * Updates option logic if necessery.
10716	 * @protected
10717	 */
10718	Owl.prototype.optionsLogic = function() {
10719		if (this.settings.autoWidth) {
10720			this.settings.stagePadding = false;
10721			this.settings.merge = false;
10722		}
10723	};
10724
10725	/**
10726	 * Prepares an item before add.
10727	 * @todo Rename event parameter `content` to `item`.
10728	 * @protected
10729	 * @returns {jQuery|HTMLElement} - The item container.
10730	 */
10731	Owl.prototype.prepare = function(item, index) {
10732		var event = this.trigger('prepare', { content: item });
10733		if (!event.data) {
10734			event.data = $('<' + this.settings.itemElement + '/>')
10735				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
10736		}
10737
10738		this.trigger('prepared', { content: event.data });
10739
10740		return event.data;
10741	};
10742
10743	/**
10744	 * Updates the view.
10745	 * @public
10746	 */
10747	Owl.prototype.update = function() {
10748		var i = 0,
10749			n = this._pipe.length,
10750			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
10751			cache = {};
10752
10753		while (i < n) {
10754			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
10755				this._pipe[i].run(cache);
10756			}
10757			i++;
10758		}
10759
10760		this._invalidated = {};
10761
10762		!this.is('valid') && this.enter('valid');
10763	};
10764
10765	/**
10766	 * Gets the width of the view.
10767	 * @public
10768	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
10769	 * @returns {Number} - The width of the view in pixel.
10770	 */
10771	Owl.prototype.width = function(dimension) {
10772		dimension = dimension || Owl.Width.Default;
10773		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
10774		switch (dimension) {
10775			case Owl.Width.Inner:
10776			case Owl.Width.Outer:
10777				return this._width;
10778			default:
10779				return this._width - stagePadding * 2 + this.settings.margin;
10780		}
10781	};
10782
10783	/**
10784	 * Refreshes the carousel primarily for adaptive purposes.
10785	 * @public
10786	 */
10787	Owl.prototype.refresh = function() {
10788		this.enter('refreshing');
10789		this.trigger('refresh');
10790
10791		this.setup();
10792
10793		this.optionsLogic();
10794
10795		this.$element.addClass(this.options.refreshClass);
10796
10797		this.update();
10798
10799		this.$element.removeClass(this.options.refreshClass);
10800
10801		this.leave('refreshing');
10802		this.trigger('refreshed');
10803	};
10804
10805	/**
10806	 * Checks window `resize` event.
10807	 * @protected
10808	 */
10809	Owl.prototype.onThrottledResize = function() {
10810		window.clearTimeout(this.resizeTimer);
10811		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
10812	};
10813
10814	/**
10815	 * Checks window `resize` event.
10816	 * @protected
10817	 */
10818	Owl.prototype.onResize = function() {
10819		if (!this._items.length) {
10820			return false;
10821		}
10822
10823		if (this._width === this.$element.width()) {
10824			return false;
10825		}
10826
10827		if (!this.$element.is(':visible')) {
10828			return false;
10829		}
10830
10831		this.enter('resizing');
10832
10833		if (this.trigger('resize').isDefaultPrevented()) {
10834			this.leave('resizing');
10835			return false;
10836		}
10837
10838		this.invalidate('width');
10839
10840		this.refresh();
10841
10842		this.leave('resizing');
10843		this.trigger('resized');
10844	};
10845
10846	/**
10847	 * Registers event handlers.
10848	 * @todo Check `msPointerEnabled`
10849	 * @todo #261
10850	 * @protected
10851	 */
10852	Owl.prototype.registerEventHandlers = function() {
10853		if ($.support.transition) {
10854			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
10855		}
10856
10857		if (this.settings.responsive !== false) {
10858			this.on(window, 'resize', this._handlers.onThrottledResize);
10859		}
10860
10861		if (this.settings.mouseDrag) {
10862			this.$element.addClass(this.options.dragClass);
10863			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
10864			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
10865		}
10866
10867		if (this.settings.touchDrag){
10868			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
10869			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
10870		}
10871	};
10872
10873	/**
10874	 * Handles `touchstart` and `mousedown` events.
10875	 * @todo Horizontal swipe threshold as option
10876	 * @todo #261
10877	 * @protected
10878	 * @param {Event} event - The event arguments.
10879	 */
10880	Owl.prototype.onDragStart = function(event) {
10881		var stage = null;
10882
10883		if (event.which === 3) {
10884			return;
10885		}
10886
vendor: 9,106 bytes, lines 10887-11202
10887		if ($.support.transform) {
10888			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
10889			stage = {
10890				x: stage[stage.length === 16 ? 12 : 4],
10891				y: stage[stage.length === 16 ? 13 : 5]
10892			};
10893		} else {
10894			stage = this.$stage.position();
10895			stage = {
10896				x: this.settings.rtl ?
10897					stage.left + this.$stage.width() - this.width() + this.settings.margin :
10898					stage.left,
10899				y: stage.top
10900			};
10901		}
10902
10903		if (this.is('animating')) {
10904			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
10905			this.invalidate('position');
10906		}
10907
10908		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
10909
10910		this.speed(0);
10911
10912		this._drag.time = new Date().getTime();
10913		this._drag.target = $(event.target);
10914		this._drag.stage.start = stage;
10915		this._drag.stage.current = stage;
10916		this._drag.pointer = this.pointer(event);
10917
10918		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
10919
10920		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
10921			var delta = this.difference(this._drag.pointer, this.pointer(event));
10922
10923			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
10924
10925			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
10926				return;
10927			}
10928
10929			event.preventDefault();
10930
10931			this.enter('dragging');
10932			this.trigger('drag');
10933		}, this));
10934	};
10935
10936	/**
10937	 * Handles the `touchmove` and `mousemove` events.
10938	 * @todo #261
10939	 * @protected
10940	 * @param {Event} event - The event arguments.
10941	 */
10942	Owl.prototype.onDragMove = function(event) {
10943		var minimum = null,
10944			maximum = null,
10945			pull = null,
10946			delta = this.difference(this._drag.pointer, this.pointer(event)),
10947			stage = this.difference(this._drag.stage.start, delta);
10948
10949		if (!this.is('dragging')) {
10950			return;
10951		}
10952
10953		event.preventDefault();
10954
10955		if (this.settings.loop) {
10956			minimum = this.coordinates(this.minimum());
10957			maximum = this.coordinates(this.maximum() + 1) - minimum;
10958			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
10959		} else {
10960			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
10961			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
10962			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
10963			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
10964		}
10965
10966		this._drag.stage.current = stage;
10967
10968		this.animate(stage.x);
10969	};
10970
10971	/**
10972	 * Handles the `touchend` and `mouseup` events.
10973	 * @todo #261
10974	 * @todo Threshold for click event
10975	 * @protected
10976	 * @param {Event} event - The event arguments.
10977	 */
10978	Owl.prototype.onDragEnd = function(event) {
10979		var delta = this.difference(this._drag.pointer, this.pointer(event)),
10980			stage = this._drag.stage.current,
10981			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
10982
10983		$(document).off('.owl.core');
10984
10985		this.$element.removeClass(this.options.grabClass);
10986
10987		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
10988			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
10989			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
10990			this.invalidate('position');
10991			this.update();
10992
10993			this._drag.direction = direction;
10994
10995			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
10996				this._drag.target.one('click.owl.core', function() { return false; });
10997			}
10998		}
10999
11000		if (!this.is('dragging')) {
11001			return;
11002		}
11003
11004		this.leave('dragging');
11005		this.trigger('dragged');
11006	};
11007
11008	/**
11009	 * Gets absolute position of the closest item for a coordinate.
11010	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
11011	 * @protected
11012	 * @param {Number} coordinate - The coordinate in pixel.
11013	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
11014	 * @return {Number} - The absolute position of the closest item.
11015	 */
11016	Owl.prototype.closest = function(coordinate, direction) {
11017		var position = -1,
11018			pull = 30,
11019			width = this.width(),
11020			coordinates = this.coordinates();
11021
11022		if (!this.settings.freeDrag) {
11023			// check closest item
11024			$.each(coordinates, $.proxy(function(index, value) {
11025				if (coordinate > value - pull && coordinate < value + pull) {
11026					position = index;
11027				} else if (this.op(coordinate, '<', value)
11028					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
11029					position = direction === 'left' ? index + 1 : index;
11030				}
11031				return position === -1;
11032			}, this));
11033		}
11034
11035		if (!this.settings.loop) {
11036			// non loop boundries
11037			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
11038				position = coordinate = this.minimum();
11039			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
11040				position = coordinate = this.maximum();
11041			}
11042		}
11043
11044		return position;
11045	};
11046
11047	/**
11048	 * Animates the stage.
11049	 * @todo #270
11050	 * @public
11051	 * @param {Number} coordinate - The coordinate in pixels.
11052	 */
11053	Owl.prototype.animate = function(coordinate) {
11054		var animate = this.speed() > 0;
11055
11056		this.is('animating') && this.onTransitionEnd();
11057
11058		if (animate) {
11059			this.enter('animating');
11060			this.trigger('translate');
11061		}
11062
11063		if ($.support.transform3d && $.support.transition) {
11064			this.$stage.css({
11065				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
11066				transition: (this.speed() / 1000) + 's'
11067			});
11068		} else if (animate) {
11069			this.$stage.animate({
11070				left: coordinate + 'px'
11071			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
11072		} else {
11073			this.$stage.css({
11074				left: coordinate + 'px'
11075			});
11076		}
11077	};
11078
11079	/**
11080	 * Checks whether the carousel is in a specific state or not.
11081	 * @param {String} state - The state to check.
11082	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
11083	 */
11084	Owl.prototype.is = function(state) {
11085		return this._states.current[state] && this._states.current[state] > 0;
11086	};
11087
11088	/**
11089	 * Sets the absolute position of the current item.
11090	 * @public
11091	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
11092	 * @returns {Number} - The absolute position of the current item.
11093	 */
11094	Owl.prototype.current = function(position) {
11095		if (position === undefined) {
11096			return this._current;
11097		}
11098
11099		if (this._items.length === 0) {
11100			return undefined;
11101		}
11102
11103		position = this.normalize(position);
11104
11105		if (this._current !== position) {
11106			var event = this.trigger('change', { property: { name: 'position', value: position } });
11107
11108			if (event.data !== undefined) {
11109				position = this.normalize(event.data);
11110			}
11111
11112			this._current = position;
11113
11114			this.invalidate('position');
11115
11116			this.trigger('changed', { property: { name: 'position', value: this._current } });
11117		}
11118
11119		return this._current;
11120	};
11121
11122	/**
11123	 * Invalidates the given part of the update routine.
11124	 * @param {String} [part] - The part to invalidate.
11125	 * @returns {Array.<String>} - The invalidated parts.
11126	 */
11127	Owl.prototype.invalidate = function(part) {
11128		if ($.type(part) === 'string') {
11129			this._invalidated[part] = true;
11130			this.is('valid') && this.leave('valid');
11131		}
11132		return $.map(this._invalidated, function(v, i) { return i });
11133	};
11134
11135	/**
11136	 * Resets the absolute position of the current item.
11137	 * @public
11138	 * @param {Number} position - The absolute position of the new item.
11139	 */
11140	Owl.prototype.reset = function(position) {
11141		position = this.normalize(position);
11142
11143		if (position === undefined) {
11144			return;
11145		}
11146
11147		this._speed = 0;
11148		this._current = position;
11149
11150		this.suppress([ 'translate', 'translated' ]);
11151
11152		this.animate(this.coordinates(position));
11153
11154		this.release([ 'translate', 'translated' ]);
11155	};
11156
11157	/**
11158	 * Normalizes an absolute or a relative position of an item.
11159	 * @public
11160	 * @param {Number} position - The absolute or relative position to normalize.
11161	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
11162	 * @returns {Number} - The normalized position.
11163	 */
11164	Owl.prototype.normalize = function(position, relative) {
11165		var n = this._items.length,
11166			m = relative ? 0 : this._clones.length;
11167
11168		if (!$.isNumeric(position) || n < 1) {
11169			position = undefined;
11170		} else if (position < 0 || position >= n + m) {
11171			position = ((position - m / 2) % n + n) % n + m / 2;
11172		}
11173
11174		return position;
11175	};
11176
11177	/**
11178	 * Converts an absolute position of an item into a relative one.
11179	 * @public
11180	 * @param {Number} position - The absolute position to convert.
11181	 * @returns {Number} - The converted position.
11182	 */
11183	Owl.prototype.relative = function(position) {
11184		position -= this._clones.length / 2;
11185		return this.normalize(position, true);
11186	};
11187
11188	/**
11189	 * Gets the maximum position for the current item.
11190	 * @public
11191	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
11192	 * @returns {Number}
11193	 */
11194	Owl.prototype.maximum = function(relative) {
11195		var settings = this.settings,
11196			maximum = this._coordinates.length,
11197			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
11198			i = -1, j;
11199
11200		if (settings.loop) {
11201			maximum = this._clones.length / 2 + this._items.length - 1;
11202		} else if (settings.autoWidth || settings.merge) {
11203			// binary search
11204			while (maximum - i > 1) {
11205				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
11206					? i = j : maximum = j;
11207			}
11208		} else if (settings.center) {
11209			maximum = this._items.length - 1;
11210		} else {
11211			maximum = this._items.length - settings.items;
11212		}
11213
11214		if (relative) {
11215			maximum -= this._clones.length / 2;
11216		}
11217
11218		return Math.max(maximum, 0);
11219	};
11220
11221	/**
11222	 * Gets the minimum position for the current item.
11223	 * @public
11224	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
11225	 * @returns {Number}
11226	 */
11227	Owl.prototype.minimum = function(relative) {
11228		return relative ? 0 : this._clones.length / 2;
11229	};
11230
11231	/**
11232	 * Gets an item at the specified relative position.
11233	 * @public
11234	 * @param {Number} [position] - The relative position of the item.
11235	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
11236	 */
11237	Owl.prototype.items = function(position) {
11238		if (position === undefined) {
11239			return this._items.slice();
11240		}
11241
11242		position = this.normalize(position, true);
11243		return this._items[position];
11244	};
11245
11246	/**
11247	 * Gets an item at the specified relative position.
11248	 * @public
11249	 * @param {Number} [position] - The relative position of the item.
11250	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
11251	 */
11252	Owl.prototype.mergers = function(position) {
11253		if (position === undefined) {
11254			return this._mergers.slice();
11255		}
11256
11257		position = this.normalize(position, true);
11258		return this._mergers[position];
11259	};
11260
11261	/**
11262	 * Gets the absolute positions of clones for an item.
11263	 * @public
11264	 * @param {Number} [position] - The relative position of the item.
11265	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
11266	 */
11267	Owl.prototype.clones = function(position) {
11268		var odd = this._clones.length / 2,
11269			even = odd + this._items.length,
11270			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
11271
11272		if (position === undefined) {
11273			return $.map(this._clones, function(v, i) { return map(i) });
11274		}
11275
11276		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
11277	};
11278
11279	/**
11280	 * Sets the current animation speed.
11281	 * @public
11282	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
11283	 * @returns {Number} - The current animation speed in milliseconds.
11284	 */
11285	Owl.prototype.speed = function(speed) {
11286		if (speed !== undefined) {
11287			this._speed = speed;
11288		}
11289
11290		return this._speed;
11291	};
11292
11293	/**
11294	 * Gets the coordinate of an item.
11295	 * @todo The name of this method is missleanding.
11296	 * @public
11297	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
11298	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
11299	 */
11300	Owl.prototype.coordinates = function(position) {
11301		var coordinate = null;
11302
11303		if (position === undefined) {
11304			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
11305				return this.coordinates(index);
11306			}, this));
11307		}
11308
11309		if (this.settings.center) {
11310			coordinate = this._coordinates[position];
11311			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
11312		} else {
11313			coordinate = this._coordinates[position - 1] || 0;
11314		}
11315
11316		return coordinate;
11317	};
11318
11319	/**
11320	 * Calculates the speed for a translation.
11321	 * @protected
11322	 * @param {Number} from - The absolute position of the start item.
11323	 * @param {Number} to - The absolute position of the target item.
11324	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
11325	 * @returns {Number} - The time in milliseconds for the translation.
11326	 */
11327	Owl.prototype.duration = function(from, to, factor) {
11328		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
11329	};
11330
11331	/**
11332	 * Slides to the specified item.
11333	 * @public
11334	 * @param {Number} position - The position of the item.
11335	 * @param {Number} [speed] - The time in milliseconds for the transition.
11336	 */
11337	Owl.prototype.to = function(position, speed) {
11338		var current = this.current(),
11339			revert = null,
11340			distance = position - this.relative(current),
11341			direction = (distance > 0) - (distance < 0),
11342			items = this._items.length,
11343			minimum = this.minimum(),
11344			maximum = this.maximum();
11345
11346		if (this.settings.loop) {
11347			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
11348				distance += direction * -1 * items;
11349			}
11350
11351			position = current + distance;
11352			revert = ((position - minimum) % items + items) % items + minimum;
11353
11354			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
11355				current = revert - distance;
11356				position = revert;
11357				this.reset(current);
11358			}
11359		} else if (this.settings.rewind) {
11360			maximum += 1;
11361			position = (position % maximum + maximum) % maximum;
11362		} else {
11363			position = Math.max(minimum, Math.min(maximum, position));
11364		}
11365
11366		this.speed(this.duration(current, position, speed));
11367		this.current(position);
11368
11369		if (this.$element.is(':visible')) {
11370			this.update();
11371		}
11372	};
11373
11374	/**
11375	 * Slides to the next item.
11376	 * @public
11377	 * @param {Number}
vendor: 12,284 bytes, lines 11377-11797
11377 [speed] - The time in milliseconds for the transition.
11378	 */
11379	Owl.prototype.next = function(speed) {
11380		speed = speed || false;
11381		this.to(this.relative(this.current()) + 1, speed);
11382	};
11383
11384	/**
11385	 * Slides to the previous item.
11386	 * @public
11387	 * @param {Number} [speed] - The time in milliseconds for the transition.
11388	 */
11389	Owl.prototype.prev = function(speed) {
11390		speed = speed || false;
11391		this.to(this.relative(this.current()) - 1, speed);
11392	};
11393
11394	/**
11395	 * Handles the end of an animation.
11396	 * @protected
11397	 * @param {Event} event - The event arguments.
11398	 */
11399	Owl.prototype.onTransitionEnd = function(event) {
11400
11401		// if css2 animation then event object is undefined
11402		if (event !== undefined) {
11403			event.stopPropagation();
11404
11405			// Catch only owl-stage transitionEnd event
11406			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
11407				return false;
11408			}
11409		}
11410
11411		this.leave('animating');
11412		this.trigger('translated');
11413	};
11414
11415	/**
11416	 * Gets viewport width.
11417	 * @protected
11418	 * @return {Number} - The width in pixel.
11419	 */
11420	Owl.prototype.viewport = function() {
11421		var width;
11422		if (this.options.responsiveBaseElement !== window) {
11423			width = $(this.options.responsiveBaseElement).width();
11424		} else if (window.innerWidth) {
11425			width = window.innerWidth;
11426		} else if (document.documentElement && document.documentElement.clientWidth) {
11427			width = document.documentElement.clientWidth;
11428		} else {
11429			throw 'Can not detect viewport width.';
11430		}
11431
11432		return width;
11433	};
11434
11435	/**
11436	 * Replaces the current content.
11437	 * @public
11438	 * @param {HTMLElement|jQuery|String} content - The new content.
11439	 */
11440	Owl.prototype.replace = function(content) {
11441		this.$stage.empty();
11442		this._items = [];
11443
11444		if (content) {
11445			content = (content instanceof jQuery) ? content : $(content);
11446		}
11447
11448		if (this.settings.nestedItemSelector) {
11449			content = content.find('.' + this.settings.nestedItemSelector);
11450		}
11451
11452		content.filter(function() {
11453			return this.nodeType === 1;
11454		}).each($.proxy(function(index, item) {
11455			item = this.prepare(item, index);
11456			this.$stage.append(item);
11457			this._items.push(item);
11458			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
11459		}, this));
11460
11461		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
11462
11463		this.invalidate('items');
11464	};
11465
11466	/**
11467	 * Adds an item.
11468	 * @todo Use `item` instead of `content` for the event arguments.
11469	 * @public
11470	 * @param {HTMLElement|jQuery|String} content - The item content to add.
11471	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
11472	 */
11473	Owl.prototype.add = function(content, position) {
11474		var current = this.relative(this._current);
11475
11476		position = position === undefined ? this._items.length : this.normalize(position, true);
11477		content = content instanceof jQuery ? content : $(content);
11478
11479		this.trigger('add', { content: content, position: position });
11480
11481		content = this.prepare(content, this._items[current].index());
11482
11483		if (this._items.length === 0 || position === this._items.length) {
11484			this._items.length === 0 && this.$stage.append(content);
11485			this._items.length !== 0 && this._items[position - 1].after(content);
11486			this._items.push(content);
11487			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
11488		} else {
11489			this._items[position].before(content);
11490			this._items.splice(position, 0, content);
11491			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
11492		}
11493
11494		this._items[current] && this.reset(this._items[current].index());
11495
11496		this.invalidate('items');
11497
11498		this.trigger('added', { content: content, position: position });
11499	};
11500
11501	/**
11502	 * Removes an item by its position.
11503	 * @todo Use `item` instead of `content` for the event arguments.
11504	 * @public
11505	 * @param {Number} position - The relative position of the item to remove.
11506	 */
11507	Owl.prototype.remove = function(position) {
11508		position = this.normalize(position, true);
11509
11510		if (position === undefined) {
11511			return;
11512		}
11513
11514		this.trigger('remove', { content: this._items[position], position: position });
11515
11516		this._items[position].remove();
11517		this._items.splice(position, 1);
11518		this._mergers.splice(position, 1);
11519
11520		this.invalidate('items');
11521
11522		this.trigger('removed', { content: null, position: position });
11523	};
11524
11525	/**
11526	 * Preloads images with auto width.
11527	 * @todo Replace by a more generic approach
11528	 * @protected
11529	 */
11530	Owl.prototype.preloadAutoWidthImages = function(images) {
11531		images.each($.proxy(function(i, element) {
11532			this.enter('pre-loading');
11533			element = $(element);
11534			$(new Image()).one('load', $.proxy(function(e) {
11535				element.attr('src', e.target.src);
11536				element.css('opacity', 1);
11537				this.leave('pre-loading');
11538				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
11539			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
11540		}, this));
11541	};
11542
11543	/**
11544	 * Destroys the carousel.
11545	 * @public
11546	 */
11547	Owl.prototype.destroy = function() {
11548
11549		this.$element.off('.owl.core');
11550		this.$stage.off('.owl.core');
11551		$(document).off('.owl.core');
11552
11553		if (this.settings.responsive !== false) {
11554			window.clearTimeout(this.resizeTimer);
11555			this.off(window, 'resize', this._handlers.onThrottledResize);
11556		}
11557
11558		for (var i in this._plugins) {
11559			this._plugins[i].destroy();
11560		}
11561
11562		this.$stage.children('.cloned').remove();
11563
11564		this.$stage.unwrap();
11565		this.$stage.children().contents().unwrap();
11566		this.$stage.children().unwrap();
11567
11568		this.$element
11569			.removeClass(this.options.refreshClass)
11570			.removeClass(this.options.loadingClass)
11571			.removeClass(this.options.loadedClass)
11572			.removeClass(this.options.rtlClass)
11573			.removeClass(this.options.dragClass)
11574			.removeClass(this.options.grabClass)
11575			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
11576			.removeData('owl.carousel');
11577	};
11578
11579	/**
11580	 * Operators to calculate right-to-left and left-to-right.
11581	 * @protected
11582	 * @param {Number} [a] - The left side operand.
11583	 * @param {String} [o] - The operator.
11584	 * @param {Number} [b] - The right side operand.
11585	 */
11586	Owl.prototype.op = function(a, o, b) {
11587		var rtl = this.settings.rtl;
11588		switch (o) {
11589			case '<':
11590				return rtl ? a > b : a < b;
11591			case '>':
11592				return rtl ? a < b : a > b;
11593			case '>=':
11594				return rtl ? a <= b : a >= b;
11595			case '<=':
11596				return rtl ? a >= b : a <= b;
11597			default:
11598				break;
11599		}
11600	};
11601
11602	/**
11603	 * Attaches to an internal event.
11604	 * @protected
11605	 * @param {HTMLElement} element - The event source.
11606	 * @param {String} event - The event name.
11607	 * @param {Function} listener - The event handler to attach.
11608	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
11609	 */
11610	Owl.prototype.on = function(element, event, listener, capture) {
11611		if (element.addEventListener) {
11612			element.addEventListener(event, listener, capture);
11613		} else if (element.attachEvent) {
11614			element.attachEvent('on' + event, listener);
11615		}
11616	};
11617
11618	/**
11619	 * Detaches from an internal event.
11620	 * @protected
11621	 * @param {HTMLElement} element - The event source.
11622	 * @param {String} event - The event name.
11623	 * @param {Function} listener - The attached event handler to detach.
11624	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
11625	 */
11626	Owl.prototype.off = function(element, event, listener, capture) {
11627		if (element.removeEventListener) {
11628			element.removeEventListener(event, listener, capture);
11629		} else if (element.detachEvent) {
11630			element.detachEvent('on' + event, listener);
11631		}
11632	};
11633
11634	/**
11635	 * Triggers a public event.
11636	 * @todo Remove `status`, `relatedTarget` should be used instead.
11637	 * @protected
11638	 * @param {String} name - The event name.
11639	 * @param {*} [data=null] - The event data.
11640	 * @param {String} [namespace=carousel] - The event namespace.
11641	 * @param {String} [state] - The state which is associated with the event.
11642	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
11643	 * @returns {Event} - The event arguments.
11644	 */
11645	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
11646		var status = {
11647			item: { count: this._items.length, index: this.current() }
11648		}, handler = $.camelCase(
11649			$.grep([ 'on', name, namespace ], function(v) { return v })
11650				.join('-').toLowerCase()
11651		), event = $.Event(
11652			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
11653			$.extend({ relatedTarget: this }, status, data)
11654		);
11655
11656		if (!this._supress[name]) {
11657			$.each(this._plugins, function(name, plugin) {
11658				if (plugin.onTrigger) {
11659					plugin.onTrigger(event);
11660				}
11661			});
11662
11663			this.register({ type: Owl.Type.Event, name: name });
11664			this.$element.trigger(event);
11665
11666			if (this.settings && typeof this.settings[handler] === 'function') {
11667				this.settings[handler].call(this, event);
11668			}
11669		}
11670
11671		return event;
11672	};
11673
11674	/**
11675	 * Enters a state.
11676	 * @param name - The state name.
11677	 */
11678	Owl.prototype.enter = function(name) {
11679		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
11680			if (this._states.current[name] === undefined) {
11681				this._states.current[name] = 0;
11682			}
11683
11684			this._states.current[name]++;
11685		}, this));
11686	};
11687
11688	/**
11689	 * Leaves a state.
11690	 * @param name - The state name.
11691	 */
11692	Owl.prototype.leave = function(name) {
11693		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
11694			this._states.current[name]--;
11695		}, this));
11696	};
11697
11698	/**
11699	 * Registers an event or state.
11700	 * @public
11701	 * @param {Object} object - The event or state to register.
11702	 */
11703	Owl.prototype.register = function(object) {
11704		if (object.type === Owl.Type.Event) {
11705			if (!$.event.special[object.name]) {
11706				$.event.special[object.name] = {};
11707			}
11708
11709			if (!$.event.special[object.name].owl) {
11710				var _default = $.event.special[object.name]._default;
11711				$.event.special[object.name]._default = function(e) {
11712					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
11713						return _default.apply(this, arguments);
11714					}
11715					return e.namespace && e.namespace.indexOf('owl') > -1;
11716				};
11717				$.event.special[object.name].owl = true;
11718			}
11719		} else if (object.type === Owl.Type.State) {
11720			if (!this._states.tags[object.name]) {
11721				this._states.tags[object.name] = object.tags;
11722			} else {
11723				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
11724			}
11725
11726			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
11727				return $.inArray(tag, this._states.tags[object.name]) === i;
11728			}, this));
11729		}
11730	};
11731
11732	/**
11733	 * Suppresses events.
11734	 * @protected
11735	 * @param {Array.<String>} events - The events to suppress.
11736	 */
11737	Owl.prototype.suppress = function(events) {
11738		$.each(events, $.proxy(function(index, event) {
11739			this._supress[event] = true;
11740		}, this));
11741	};
11742
11743	/**
11744	 * Releases suppressed events.
11745	 * @protected
11746	 * @param {Array.<String>} events - The events to release.
11747	 */
11748	Owl.prototype.release = function(events) {
11749		$.each(events, $.proxy(function(index, event) {
11750			delete this._supress[event];
11751		}, this));
11752	};
11753
11754	/**
11755	 * Gets unified pointer coordinates from event.
11756	 * @todo #261
11757	 * @protected
11758	 * @param {Event} - The `mousedown` or `touchstart` event.
11759	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
11760	 */
11761	Owl.prototype.pointer = function(event) {
11762		var result = { x: null, y: null };
11763
11764		event = event.originalEvent || event || window.event;
11765
11766		event = event.touches && event.touches.length ?
11767			event.touches[0] : event.changedTouches && event.changedTouches.length ?
11768				event.changedTouches[0] : event;
11769
11770		if (event.pageX) {
11771			result.x = event.pageX;
11772			result.y = event.pageY;
11773		} else {
11774			result.x = event.clientX;
11775			result.y = event.clientY;
11776		}
11777
11778		return result;
11779	};
11780
11781	/**
11782	 * Gets the difference of two vectors.
11783	 * @todo #261
11784	 * @protected
11785	 * @param {Object} - The first vector.
11786	 * @param {Object} - The second vector.
11787	 * @returns {Object} - The difference.
11788	 */
11789	Owl.prototype.difference = function(first, second) {
11790		return {
11791			x: first.x - second.x,
11792			y: first.y - second.y
11793		};
11794	};
11795
11796	/**
11797	 * The jQuery Plugin for the Owl Carousel
vendor: 32,216 bytes, lines 11798-13080
11798	 * @todo Navigation plugin `next` and `prev`
11799	 * @public
11800	 */
11801	$.fn.owlCarousel = function(option) {
11802		var args = Array.prototype.slice.call(arguments, 1);
11803
11804		return this.each(function() {
11805			var $this = $(this),
11806				data = $this.data('owl.carousel');
11807
11808			if (!data) {
11809				data = new Owl(this, typeof option == 'object' && option);
11810				$this.data('owl.carousel', data);
11811
11812				$.each([
11813					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
11814				], function(i, event) {
11815					data.register({ type: Owl.Type.Event, name: event });
11816					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
11817						if (e.namespace && e.relatedTarget !== this) {
11818							this.suppress([ event ]);
11819							data[event].apply(this, [].slice.call(arguments, 1));
11820							this.release([ event ]);
11821						}
11822					}, data));
11823				});
11824			}
11825
11826			if (typeof option == 'string' && option.charAt(0) !== '_') {
11827				data[option].apply(data, args);
11828			}
11829		});
11830	};
11831
11832	/**
11833	 * The constructor for the jQuery Plugin
11834	 * @public
11835	 */
11836	$.fn.owlCarousel.Constructor = Owl;
11837
11838})(window.Zepto || window.jQuery, window, document);
11839
11840/**
11841 * AutoRefresh Plugin
11842 * @version 2.0.0-beta.3
11843 * @author Artus Kolanowski
11844 * @license The MIT License (MIT)
11845 */
11846;(function($, window, document, undefined) {
11847
11848	/**
11849	 * Creates the auto refresh plugin.
11850	 * @class The Auto Refresh Plugin
11851	 * @param {Owl} carousel - The Owl Carousel
11852	 */
11853	var AutoRefresh = function(carousel) {
11854		/**
11855		 * Reference to the core.
11856		 * @protected
11857		 * @type {Owl}
11858		 */
11859		this._core = carousel;
11860
11861		/**
11862		 * Refresh interval.
11863		 * @protected
11864		 * @type {number}
11865		 */
11866		this._interval = null;
11867
11868		/**
11869		 * Whether the element is currently visible or not.
11870		 * @protected
11871		 * @type {Boolean}
11872		 */
11873		this._visible = null;
11874
11875		/**
11876		 * All event handlers.
11877		 * @protected
11878		 * @type {Object}
11879		 */
11880		this._handlers = {
11881			'initialized.owl.carousel': $.proxy(function(e) {
11882				if (e.namespace && this._core.settings.autoRefresh) {
11883					this.watch();
11884				}
11885			}, this)
11886		};
11887
11888		// set default options
11889		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
11890
11891		// register event handlers
11892		this._core.$element.on(this._handlers);
11893	};
11894
11895	/**
11896	 * Default options.
11897	 * @public
11898	 */
11899	AutoRefresh.Defaults = {
11900		autoRefresh: true,
11901		autoRefreshInterval: 500
11902	};
11903
11904	/**
11905	 * Watches the element.
11906	 */
11907	AutoRefresh.prototype.watch = function() {
11908		if (this._interval) {
11909			return;
11910		}
11911
11912		this._visible = this._core.$element.is(':visible');
11913		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
11914	};
11915
11916	/**
11917	 * Refreshes the element.
11918	 */
11919	AutoRefresh.prototype.refresh = function() {
11920		if (this._core.$element.is(':visible') === this._visible) {
11921			return;
11922		}
11923
11924		this._visible = !this._visible;
11925
11926		this._core.$element.toggleClass('owl-hidden', !this._visible);
11927
11928		this._visible && (this._core.invalidate('width') && this._core.refresh());
11929	};
11930
11931	/**
11932	 * Destroys the plugin.
11933	 */
11934	AutoRefresh.prototype.destroy = function() {
11935		var handler, property;
11936
11937		window.clearInterval(this._interval);
11938
11939		for (handler in this._handlers) {
11940			this._core.$element.off(handler, this._handlers[handler]);
11941		}
11942		for (property in Object.getOwnPropertyNames(this)) {
11943			typeof this[property] != 'function' && (this[property] = null);
11944		}
11945	};
11946
11947	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
11948
11949})(window.Zepto || window.jQuery, window, document);
11950
11951/**
11952 * Lazy Plugin
11953 * @version 2.0.0-beta.3
11954 * @author Bartosz Wojciechowski
11955 * @license The MIT License (MIT)
11956 */
11957;(function($, window, document, undefined) {
11958
11959	/**
11960	 * Creates the lazy plugin.
11961	 * @class The Lazy Plugin
11962	 * @param {Owl} carousel - The Owl Carousel
11963	 */
11964	var Lazy = function(carousel) {
11965
11966		/**
11967		 * Reference to the core.
11968		 * @protected
11969		 * @type {Owl}
11970		 */
11971		this._core = carousel;
11972
11973		/**
11974		 * Already loaded items.
11975		 * @protected
11976		 * @type {Array.<jQuery>}
11977		 */
11978		this._loaded = [];
11979
11980		/**
11981		 * Event handlers.
11982		 * @protected
11983		 * @type {Object}
11984		 */
11985		this._handlers = {
11986			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
11987				if (!e.namespace) {
11988					return;
11989				}
11990
11991				if (!this._core.settings || !this._core.settings.lazyLoad) {
11992					return;
11993				}
11994
11995				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
11996					var settings = this._core.settings,
11997						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
11998						i = ((settings.center && n * -1) || 0),
11999						position = ((e.property && e.property.value) || this._core.current()) + i,
12000						clones = this._core.clones().length,
12001						load = $.proxy(function(i, v) { this.load(v) }, this);
12002
12003					while (i++ < n) {
12004						this.load(clones / 2 + this._core.relative(position));
12005						clones && $.each(this._core.clones(this._core.relative(position)), load);
12006						position++;
12007					}
12008				}
12009			}, this)
12010		};
12011
12012		// set the default options
12013		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
12014
12015		// register event handler
12016		this._core.$element.on(this._handlers);
12017	}
12018
12019	/**
12020	 * Default options.
12021	 * @public
12022	 */
12023	Lazy.Defaults = {
12024		lazyLoad: false
12025	}
12026
12027	/**
12028	 * Loads all resources of an item at the specified position.
12029	 * @param {Number} position - The absolute position of the item.
12030	 * @protected
12031	 */
12032	Lazy.prototype.load = function(position) {
12033		var $item = this._core.$stage.children().eq(position),
12034			$elements = $item && $item.find('.owl-lazy');
12035
12036		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
12037			return;
12038		}
12039
12040		$elements.each($.proxy(function(index, element) {
12041			var $element = $(element), image,
12042				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
12043
12044			this._core.trigger('load', { element: $element, url: url }, 'lazy');
12045
12046			if ($element.is('img')) {
12047				$element.one('load.owl.lazy', $.proxy(function() {
12048					$element.css('opacity', 1);
12049					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
12050				}, this)).attr('src', url);
12051			} else {
12052				image = new Image();
12053				image.onload = $.proxy(function() {
12054					$element.css({
12055						'background-image': 'url(' + url + ')',
12056						'opacity': '1'
12057					});
12058					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
12059				}, this);
12060				image.src = url;
12061			}
12062		}, this));
12063
12064		this._loaded.push($item.get(0));
12065	}
12066
12067	/**
12068	 * Destroys the plugin.
12069	 * @public
12070	 */
12071	Lazy.prototype.destroy = function() {
12072		var handler, property;
12073
12074		for (handler in this.handlers) {
12075			this._core.$element.off(handler, this.handlers[handler]);
12076		}
12077		for (property in Object.getOwnPropertyNames(this)) {
12078			typeof this[property] != 'function' && (this[property] = null);
12079		}
12080	};
12081
12082	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
12083
12084})(window.Zepto || window.jQuery, window, document);
12085
12086/**
12087 * AutoHeight Plugin
12088 * @version 2.0.0-beta.3
12089 * @author Bartosz Wojciechowski
12090 * @license The MIT License (MIT)
12091 */
12092;(function($, window, document, undefined) {
12093
12094	/**
12095	 * Creates the auto height plugin.
12096	 * @class The Auto Height Plugin
12097	 * @param {Owl} carousel - The Owl Carousel
12098	 */
12099	var AutoHeight = function(carousel) {
12100		/**
12101		 * Reference to the core.
12102		 * @protected
12103		 * @type {Owl}
12104		 */
12105		this._core = carousel;
12106
12107		/**
12108		 * All event handlers.
12109		 * @protected
12110		 * @type {Object}
12111		 */
12112		this._handlers = {
12113			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
12114				if (e.namespace && this._core.settings.autoHeight) {
12115					this.update();
12116				}
12117			}, this),
12118			'changed.owl.carousel': $.proxy(function(e) {
12119				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
12120					this.update();
12121				}
12122			}, this),
12123			'loaded.owl.lazy': $.proxy(function(e) {
12124				if (e.namespace && this._core.settings.autoHeight
12125					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
12126					this.update();
12127				}
12128			}, this)
12129		};
12130
12131		// set default options
12132		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
12133
12134		// register event handlers
12135		this._core.$element.on(this._handlers);
12136	};
12137
12138	/**
12139	 * Default options.
12140	 * @public
12141	 */
12142	AutoHeight.Defaults = {
12143		autoHeight: false,
12144		autoHeightClass: 'owl-height'
12145	};
12146
12147	/**
12148	 * Updates the view.
12149	 */
12150	AutoHeight.prototype.update = function() {
12151		var start = this._core._current,
12152			end = start + this._core.settings.items,
12153			visible = this._core.$stage.children().toArray().slice(start, end);
12154			heights = [],
12155			maxheight = 0;
12156
12157		$.each(visible, function(index, item) {
12158			heights.push($(item).height());
12159		});
12160
12161		maxheight = Math.max.apply(null, heights);
12162
12163		this._core.$stage.parent()
12164			.height(maxheight)
12165			.addClass(this._core.settings.autoHeightClass);
12166	};
12167
12168	AutoHeight.prototype.destroy = function() {
12169		var handler, property;
12170
12171		for (handler in this._handlers) {
12172			this._core.$element.off(handler, this._handlers[handler]);
12173		}
12174		for (property in Object.getOwnPropertyNames(this)) {
12175			typeof this[property] != 'function' && (this[property] = null);
12176		}
12177	};
12178
12179	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
12180
12181})(window.Zepto || window.jQuery, window, document);
12182
12183/**
12184 * Video Plugin
12185 * @version 2.0.0-beta.3
12186 * @author Bartosz Wojciechowski
12187 * @license The MIT License (MIT)
12188 */
12189;(function($, window, document, undefined) {
12190
12191	/**
12192	 * Creates the video plugin.
12193	 * @class The Video Plugin
12194	 * @param {Owl} carousel - The Owl Carousel
12195	 */
12196	var Video = function(carousel) {
12197		/**
12198		 * Reference to the core.
12199		 * @protected
12200		 * @type {Owl}
12201		 */
12202		this._core = carousel;
12203
12204		/**
12205		 * Cache all video URLs.
12206		 * @protected
12207		 * @type {Object}
12208		 */
12209		this._videos = {};
12210
12211		/**
12212		 * Current playing item.
12213		 * @protected
12214		 * @type {jQuery}
12215		 */
12216		this._playing = null;
12217
12218		/**
12219		 * All event handlers.
12220		 * @todo The cloned content removale is too late
12221		 * @protected
12222		 * @type {Object}
12223		 */
12224		this._handlers = {
12225			'initialized.owl.carousel': $.proxy(function(e) {
12226				if (e.namespace) {
12227					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
12228				}
12229			}, this),
12230			'resize.owl.carousel': $.proxy(function(e) {
12231				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
12232					e.preventDefault();
12233				}
12234			}, this),
12235			'refreshed.owl.carousel': $.proxy(function(e) {
12236				if (e.namespace && this._core.is('resizing')) {
12237					this._core.$stage.find('.cloned .owl-video-frame').remove();
12238				}
12239			}, this),
12240			'changed.owl.carousel': $.proxy(function(e) {
12241				if (e.namespace && e.property.name === 'position' && this._playing) {
12242					this.stop();
12243				}
12244			}, this),
12245			'prepared.owl.carousel': $.proxy(function(e) {
12246				if (!e.namespace) {
12247					return;
12248				}
12249
12250				var $element = $(e.content).find('.owl-video');
12251
12252				if ($element.length) {
12253					$element.css('display', 'none');
12254					this.fetch($element, $(e.content));
12255				}
12256			}, this)
12257		};
12258
12259		// set default options
12260		this._core.options = $.extend({}, Video.Defaults, this._core.options);
12261
12262		// register event handlers
12263		this._core.$element.on(this._handlers);
12264
12265		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
12266			this.play(e);
12267		}, this));
12268	};
12269
12270	/**
12271	 * Default options.
12272	 * @public
12273	 */
12274	Video.Defaults = {
12275		video: false,
12276		videoHeight: false,
12277		videoWidth: false
12278	};
12279
12280	/**
12281	 * Gets the video ID and the type (YouTube/Vimeo only).
12282	 * @protected
12283	 * @param {jQuery} target - The target containing the video data.
12284	 * @param {jQuery} item - The item containing the video.
12285	 */
12286	Video.prototype.fetch = function(target, item) {
12287		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
12288			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
12289			width = target.attr('data-width') || this._core.settings.videoWidth,
12290			height = target.attr('data-height') || this._core.settings.videoHeight,
12291			url = target.attr('href');
12292
12293		if (url) {
12294			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+)?/);
12295
12296			if (id[3].indexOf('youtu') > -1) {
12297				type = 'youtube';
12298			} else if (id[3].indexOf('vimeo') > -1) {
12299				type = 'vimeo';
12300			} else {
12301				throw new Error('Video URL not supported.');
12302			}
12303			id = id[6];
12304		} else {
12305			throw new Error('Missing video URL.');
12306		}
12307
12308		this._videos[url] = {
12309			type: type,
12310			id: id,
12311			width: width,
12312			height: height
12313		};
12314
12315		item.attr('data-video', url);
12316
12317		this.thumbnail(target, this._videos[url]);
12318	};
12319
12320	/**
12321	 * Creates video thumbnail.
12322	 * @protected
12323	 * @param {jQuery} target - The target containing the video data.
12324	 * @param {Object} info - The video info object.
12325	 * @see `fetch`
12326	 */
12327	Video.prototype.thumbnail = function(target, video) {
12328		var tnLink,
12329			icon,
12330			path,
12331			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
12332			customTn = target.find('img'),
12333			srcType = 'src',
12334			lazyClass = '',
12335			settings = this._core.settings,
12336			create = function(path) {
12337				icon = '<div class="owl-video-play-icon"></div>';
12338
12339				if (settings.lazyLoad) {
12340					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
12341				} else {
12342					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
12343				}
12344				target.after(tnLink);
12345				target.after(icon);
12346			};
12347
12348		// wrap video content into owl-video-wrapper div
12349		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
12350
12351		if (this._core.settings.lazyLoad) {
12352			srcType = 'data-src';
12353			lazyClass = 'owl-lazy';
12354		}
12355
12356		// custom thumbnail
12357		if (customTn.length) {
12358			create(customTn.attr(srcType));
12359			customTn.remove();
12360			return false;
12361		}
12362
12363		if (video.type === 'youtube') {
12364			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
12365			create(path);
12366		} else if (video.type === 'vimeo') {
12367			$.ajax({
12368				type: 'GET',
12369				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
12370				jsonp: 'callback',
12371				dataType: 'jsonp',
12372				success: function(data) {
12373					path = data[0].thumbnail_large;
12374					create(path);
12375				}
12376			});
12377		}
12378	};
12379
12380	/**
12381	 * Stops the current video.
12382	 * @public
12383	 */
12384	Video.prototype.stop = function() {
12385		this._core.trigger('stop', null, 'video');
12386		this._playing.find('.owl-video-frame').remove();
12387		this._playing.removeClass('owl-video-playing');
12388		this._playing = null;
12389		this._core.leave('playing');
12390		this._core.trigger('stopped', null, 'video');
12391	};
12392
12393	/**
12394	 * Starts the current video.
12395	 * @public
12396	 * @param {Event} event - The event arguments.
12397	 */
12398	Video.prototype.play = function(event) {
12399		var target = $(event.target),
12400			item = target.closest('.' + this._core.settings.itemClass),
12401			video = this._videos[item.attr('data-video')],
12402			width = video.width || '100%',
12403			height = video.height || this._core.$stage.height(),
12404			html;
12405
12406		if (this._playing) {
12407			return;
12408		}
12409
12410		this._core.enter('playing');
12411		this._core.trigger('play', null, 'video');
12412
12413		item = this._core.items(this._core.relative(item.index()));
12414
12415		this._core.reset(item.index());
12416
12417		if (video.type === 'youtube') {
12418			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
12419				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
12420		} else if (video.type === 'vimeo') {
12421			html = '<iframe src="//player.vimeo.com/video/' + video.id +
12422				'?autoplay=1" width="' + width + '" height="' + height +
12423				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
12424		}
12425
12426		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
12427
12428		this._playing = item.addClass('owl-video-playing');
12429	};
12430
12431	/**
12432	 * Checks whether an video is currently in full screen mode or not.
12433	 * @todo Bad style because looks like a readonly method but changes members.
12434	 * @protected
12435	 * @returns {Boolean}
12436	 */
12437	Video.prototype.isInFullScreen = function() {
12438		var element = document.fullscreenElement || document.mozFullScreenElement ||
12439				document.webkitFullscreenElement;
12440
12441		return element && $(element).parent().hasClass('owl-video-frame');
12442	};
12443
12444	/**
12445	 * Destroys the plugin.
12446	 */
12447	Video.prototype.destroy = function() {
12448		var handler, property;
12449
12450		this._core.$element.off('click.owl.video');
12451
12452		for (handler in this._handlers) {
12453			this._core.$element.off(handler, this._handlers[handler]);
12454		}
12455		for (property in Object.getOwnPropertyNames(this)) {
12456			typeof this[property] != 'function' && (this[property] = null);
12457		}
12458	};
12459
12460	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
12461
12462})(window.Zepto || window.jQuery, window, document);
12463
12464/**
12465 * Animate Plugin
12466 * @version 2.0.0-beta.3
12467 * @author Bartosz Wojciechowski
12468 * @license The MIT License (MIT)
12469 */
12470;(function($, window, document, undefined) {
12471
12472	/**
12473	 * Creates the animate plugin.
12474	 * @class The Navigation Plugin
12475	 * @param {Owl} scope - The Owl Carousel
12476	 */
12477	var Animate = function(scope) {
12478		this.core = scope;
12479		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
12480		this.swapping = true;
12481		this.previous = undefined;
12482		this.next = undefined;
12483
12484		this.handlers = {
12485			'change.owl.carousel': $.proxy(function(e) {
12486				if (e.namespace && e.property.name == 'position') {
12487					this.previous = this.core.current();
12488					this.next = e.property.value;
12489				}
12490			}, this),
12491			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
12492				if (e.namespace) {
12493					this.swapping = e.type == 'translated';
12494				}
12495			}, this),
12496			'translate.owl.carousel': $.proxy(function(e) {
12497				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
12498					this.swap();
12499				}
12500			}, this)
12501		};
12502
12503		this.core.$element.on(this.handlers);
12504	};
12505
12506	/**
12507	 * Default options.
12508	 * @public
12509	 */
12510	Animate.Defaults = {
12511		animateOut: false,
12512		animateIn: false
12513	};
12514
12515	/**
12516	 * Toggles the animation classes whenever an translations starts.
12517	 * @protected
12518	 * @returns {Boolean|undefined}
12519	 */
12520	Animate.prototype.swap = function() {
12521
12522		if (this.core.settings.items !== 1) {
12523			return;
12524		}
12525
12526		if (!$.support.animation || !$.support.transition) {
12527			return;
12528		}
12529
12530		this.core.speed(0);
12531
12532		var left,
12533			clear = $.proxy(this.clear, this),
12534			previous = this.core.$stage.children().eq(this.previous),
12535			next = this.core.$stage.children().eq(this.next),
12536			incoming = this.core.settings.animateIn,
12537			outgoing = this.core.settings.animateOut;
12538
12539		if (this.core.current() === this.previous) {
12540			return;
12541		}
12542
12543		if (outgoing) {
12544			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
12545			previous.css( { 'left': left + 'px' } )
12546				.addClass('animated owl-animated-out')
12547				.addClass(outgoing)
12548				.on($.support.animation.end, clear);
12549		}
12550
12551		if (incoming) {
12552			next.addClass('animated owl-animated-in')
12553				.addClass(incoming)
12554				.on($.support.animation.end, clear);
12555		}
12556	};
12557
12558	Animate.prototype.clear = function(e) {
12559		if ($(e.target).hasClass('animated')) {
12560			$(e.target).css( { 'left': '' } )
12561				.removeClass('animated owl-animated-out owl-animated-in')
12562				.removeClass(this.core.settings.animateIn)
12563				.removeClass(this.core.settings.animateOut);
12564			this.core.onTransitionEnd();
12565		}
12566	};
12567
12568	/**
12569	 * Destroys the plugin.
12570	 * @public
12571	 */
12572	Animate.prototype.destroy = function() {
12573		var handler, property;
12574
12575		for (handler in this.handlers) {
12576			this.core.$element.off(handler, this.handlers[handler]);
12577		}
12578		for (property in Object.getOwnPropertyNames(this)) {
12579			typeof this[property] != 'function' && (this[property] = null);
12580		}
12581	};
12582
12583	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
12584
12585})(window.Zepto || window.jQuery, window, document);
12586
12587/**
12588 * Autoplay Plugin
12589 * @version 2.0.0-beta.3
12590 * @author Bartosz Wojciechowski
12591 * @author Artus Kolanowski
12592 * @license The MIT License (MIT)
12593 */
12594;(function($, window, document, undefined) {
12595
12596	/**
12597	 * Creates the autoplay plugin.
12598	 * @class The Autoplay Plugin
12599	 * @param {Owl} scope - The Owl Carousel
12600	 */
12601	var Autoplay = function(carousel) {
12602		/**
12603		 * Reference to the core.
12604		 * @protected
12605		 * @type {Owl}
12606		 */
12607		this._core = carousel;
12608
12609		/**
12610		 * The autoplay interval.
12611		 * @type {Number}
12612		 */
12613		this._interval = null;
12614
12615		/**
12616		 * Indicates whenever the autoplay is paused.
12617		 * @type {Boolean}
12618		 */
12619		this._paused = false;
12620
12621		/**
12622		 * All event handlers.
12623		 * @protected
12624		 * @type {Object}
12625		 */
12626		this._handlers = {
12627			'changed.owl.carousel': $.proxy(function(e) {
12628				if (e.namespace && e.property.name === 'settings') {
12629					if (this._core.settings.autoplay) {
12630						this.play();
12631					} else {
12632						this.stop();
12633					}
12634				}
12635			}, this),
12636			'initialized.owl.carousel': $.proxy(function(e) {
12637				if (e.namespace && this._core.settings.autoplay) {
12638					this.play();
12639				}
12640			}, this),
12641			'play.owl.autoplay': $.proxy(function(e, t, s) {
12642				if (e.namespace) {
12643					this.play(t, s);
12644				}
12645			}, this),
12646			'stop.owl.autoplay': $.proxy(function(e) {
12647				if (e.namespace) {
12648					this.stop();
12649				}
12650			}, this),
12651			'mouseover.owl.autoplay': $.proxy(function() {
12652				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
12653					this.pause();
12654				}
12655			}, this),
12656			'mouseleave.owl.autoplay': $.proxy(function() {
12657				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
12658					this.play();
12659				}
12660			}, this)
12661		};
12662
12663		// register event handlers
12664		this._core.$element.on(this._handlers);
12665
12666		// set default options
12667		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
12668	};
12669
12670	/**
12671	 * Default options.
12672	 * @public
12673	 */
12674	Autoplay.Defaults = {
12675		autoplay: false,
12676		autoplayTimeout: 5000,
12677		autoplayHoverPause: false,
12678		autoplaySpeed: false
12679	};
12680
12681	/**
12682	 * Starts the autoplay.
12683	 * @public
12684	 * @param {Number} [timeout] - The interval before the next animation starts.
12685	 * @param {Number} [speed] - The animation speed for the animations.
12686	 */
12687	Autoplay.prototype.play = function(timeout, speed) {
12688		this._paused = false;
12689
12690		if (this._core.is('rotating')) {
12691			return;
12692		}
12693
12694		this._core.enter('rotating');
12695
12696		this._interval = window.setInterval($.proxy(function() {
12697			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
12698				return;
12699			}
12700			this._core.next(speed || this._core.settings.autoplaySpeed);
12701		}, this), timeout || this._core.settings.autoplayTimeout);
12702	};
12703
12704	/**
12705	 * Stops the autoplay.
12706	 * @public
12707	 */
12708	Autoplay.prototype.stop = function() {
12709		if (!this._core.is('rotating')) {
12710			return;
12711		}
12712
12713		window.clearInterval(this._interval);
12714		this._core.leave('rotating');
12715	};
12716
12717	/**
12718	 * Stops the autoplay.
12719	 * @public
12720	 */
12721	Autoplay.prototype.pause = function() {
12722		if (!this._core.is('rotating')) {
12723			return;
12724		}
12725
12726		this._paused = true;
12727	};
12728
12729	/**
12730	 * Destroys the plugin.
12731	 */
12732	Autoplay.prototype.destroy = function() {
12733		var handler, property;
12734
12735		this.stop();
12736
12737		for (handler in this._handlers) {
12738			this._core.$element.off(handler, this._handlers[handler]);
12739		}
12740		for (property in Object.getOwnPropertyNames(this)) {
12741			typeof this[property] != 'function' && (this[property] = null);
12742		}
12743	};
12744
12745	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
12746
12747})(window.Zepto || window.jQuery, window, document);
12748
12749/**
12750 * Navigation Plugin
12751 * @version 2.0.0-beta.3
12752 * @author Artus Kolanowski
12753 * @license The MIT License (MIT)
12754 */
12755;(function($, window, document, undefined) {
12756	'use strict';
12757
12758	/**
12759	 * Creates the navigation plugin.
12760	 * @class The Navigation Plugin
12761	 * @param {Owl} carousel - The Owl Carousel.
12762	 */
12763	var Navigation = function(carousel) {
12764		/**
12765		 * Reference to the core.
12766		 * @protected
12767		 * @type {Owl}
12768		 */
12769		this._core = carousel;
12770
12771		/**
12772		 * Indicates whether the plugin is initialized or not.
12773		 * @protected
12774		 * @type {Boolean}
12775		 */
12776		this._initialized = false;
12777
12778		/**
12779		 * The current paging indexes.
12780		 * @protected
12781		 * @type {Array}
12782		 */
12783		this._pages = [];
12784
12785		/**
12786		 * All DOM elements of the user interface.
12787		 * @protected
12788		 * @type {Object}
12789		 */
12790		this._controls = {};
12791
12792		/**
12793		 * Markup for an indicator.
12794		 * @protected
12795		 * @type {Array.<String>}
12796		 */
12797		this._templates = [];
12798
12799		/**
12800		 * The carousel element.
12801		 * @type {jQuery}
12802		 */
12803		this.$element = this._core.$element;
12804
12805		/**
12806		 * Overridden methods of the carousel.
12807		 * @protected
12808		 * @type {Object}
12809		 */
12810		this._overrides = {
12811			next: this._core.next,
12812			prev: this._core.prev,
12813			to: this._core.to
12814		};
12815
12816		/**
12817		 * All event handlers.
12818		 * @protected
12819		 * @type {Object}
12820		 */
12821		this._handlers = {
12822			'prepared.owl.carousel': $.proxy(function(e) {
12823				if (e.namespace && this._core.settings.dotsData) {
12824					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
12825						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
12826				}
12827			}, this),
12828			'added.owl.carousel': $.proxy(function(e) {
12829				if (e.namespace && this._core.settings.dotsData) {
12830					this._templates.splice(e.position, 0, this._templates.pop());
12831				}
12832			}, this),
12833			'remove.owl.carousel': $.proxy(function(e) {
12834				if (e.namespace && this._core.settings.dotsData) {
12835					this._templates.splice(e.position, 1);
12836				}
12837			}, this),
12838			'changed.owl.carousel': $.proxy(function(e) {
12839				if (e.namespace && e.property.name == 'position') {
12840					this.draw();
12841				}
12842			}, this),
12843			'initialized.owl.carousel': $.proxy(function(e) {
12844				if (e.namespace && !this._initialized) {
12845					this._core.trigger('initialize', null, 'navigation');
12846					this.initialize();
12847					this.update();
12848					this.draw();
12849					this._initialized = true;
12850					this._core.trigger('initialized', null, 'navigation');
12851				}
12852			}, this),
12853			'refreshed.owl.carousel': $.proxy(function(e) {
12854				if (e.namespace && this._initialized) {
12855					this._core.trigger('refresh', null, 'navigation');
12856					this.update();
12857					this.draw();
12858					this._core.trigger('refreshed', null, 'navigation');
12859				}
12860			}, this)
12861		};
12862
12863		// set default options
12864		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
12865
12866		// register event handlers
12867		this.$element.on(this._handlers);
12868	};
12869
12870	/**
12871	 * Default options.
12872	 * @public
12873	 * @todo Rename `slideBy` to `navBy`
12874	 */
12875	Navigation.Defaults = {
12876		nav: false,
12877		navText: [ 'prev', 'next' ],
12878		navSpeed: false,
12879		navElement: 'div',
12880		navContainer: false,
12881		navContainerClass: 'owl-nav',
12882		navClass: [ 'owl-prev', 'owl-next' ],
12883		slideBy: 1,
12884		dotClass: 'owl-dot',
12885		dotsClass: 'owl-dots',
12886		dots: true,
12887		dotsEach: false,
12888		dotsData: false,
12889		dotsSpeed: false,
12890		dotsContainer: false
12891	};
12892
12893	/**
12894	 * Initializes the layout of the plugin and extends the carousel.
12895	 * @protected
12896	 */
12897	Navigation.prototype.initialize = function() {
12898		var override,
12899			settings = this._core.settings;
12900
12901		// create DOM structure for relative navigation
12902		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
12903			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
12904
12905		this._controls.$previous = $('<' + settings.navElement + '>')
12906			.addClass(settings.navClass[0])
12907			.html(settings.navText[0])
12908			.prependTo(this._controls.$relative)
12909			.on('click', $.proxy(function(e) {
12910				this.prev(settings.navSpeed);
12911			}, this));
12912		this._controls.$next = $('<' + settings.navElement + '>')
12913			.addClass(settings.navClass[1])
12914			.html(settings.navText[1])
12915			.appendTo(this._controls.$relative)
12916			.on('click', $.proxy(function(e) {
12917				this.next(settings.navSpeed);
12918			}, this));
12919
12920		// create DOM structure for absolute navigation
12921		if (!settings.dotsData) {
12922			this._templates = [ $('<div>')
12923				.addClass(settings.dotClass)
12924				.append($('<span>'))
12925				.prop('outerHTML') ];
12926		}
12927
12928		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
12929			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
12930
12931		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
12932			var index = $(e.target).parent().is(this._controls.$absolute)
12933				? $(e.target).index() : $(e.target).parent().index();
12934
12935			e.preventDefault();
12936
12937			this.to(index, settings.dotsSpeed);
12938		}, this));
12939
12940		// override public methods of the carousel
12941		for (override in this._overrides) {
12942			this._core[override] = $.proxy(this[override], this);
12943		}
12944	};
12945
12946	/**
12947	 * Destroys the plugin.
12948	 * @protected
12949	 */
12950	Navigation.prototype.destroy = function() {
12951		var handler, control, property, override;
12952
12953		for (handler in this._handlers) {
12954			this.$element.off(handler, this._handlers[handler]);
12955		}
12956		for (control in this._controls) {
12957			this._controls[control].remove();
12958		}
12959		for (override in this.overides) {
12960			this._core[override] = this._overrides[override];
12961		}
12962		for (property in Object.getOwnPropertyNames(this)) {
12963			typeof this[property] != 'function' && (this[property] = null);
12964		}
12965	};
12966
12967	/**
12968	 * Updates the internal state.
12969	 * @protected
12970	 */
12971	Navigation.prototype.update = function() {
12972		var i, j, k,
12973			lower = this._core.clones().length / 2,
12974			upper = lower + this._core.items().length,
12975			maximum = this._core.maximum(true),
12976			settings = this._core.settings,
12977			size = settings.center || settings.autoWidth || settings.dotsData
12978				? 1 : settings.dotsEach || settings.items;
12979
12980		if (settings.slideBy !== 'page') {
12981			settings.slideBy = Math.min(settings.slideBy, settings.items);
12982		}
12983
12984		if (settings.dots || settings.slideBy == 'page') {
12985			this._pages = [];
12986
12987			for (i = lower, j = 0, k = 0; i < upper; i++) {
12988				if (j >= size || j === 0) {
12989					this._pages.push({
12990						start: Math.min(maximum, i - lower),
12991						end: i - lower + size - 1
12992					});
12993					if (Math.min(maximum, i - lower) === maximum) {
12994						break;
12995					}
12996					j = 0, ++k;
12997				}
12998				j += this._core.mergers(this._core.relative(i));
12999			}
13000		}
13001	};
13002
13003	/**
13004	 * Draws the user interface.
13005	 * @todo The option `dotsData` wont work.
13006	 * @protected
13007	 */
13008	Navigation.prototype.draw = function() {
13009		var difference,
13010			settings = this._core.settings,
13011			disabled = this._core.items().length <= settings.items,
13012			index = this._core.relative(this._core.current()),
13013			loop = settings.loop || settings.rewind;
13014
13015		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
13016
13017		if (settings.nav) {
13018			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
13019			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
13020		}
13021
13022		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
13023
13024		if (settings.dots) {
13025			difference = this._pages.length - this._controls.$absolute.children().length;
13026
13027			if (settings.dotsData && difference !== 0) {
13028				this._controls.$absolute.html(this._templates.join(''));
13029			} else if (difference > 0) {
13030				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
13031			} else if (difference < 0) {
13032				this._controls.$absolute.children().slice(difference).remove();
13033			}
13034
13035			this._controls.$absolute.find('.active').removeClass('active');
13036			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
13037		}
13038	};
13039
13040	/**
13041	 * Extends event data.
13042	 * @protected
13043	 * @param {Event} event - The event object which gets thrown.
13044	 */
13045	Navigation.prototype.onTrigger = function(event) {
13046		var settings = this._core.settings;
13047
13048		event.page = {
13049			index: $.inArray(this.current(), this._pages),
13050			count: this._pages.length,
13051			size: settings && (settings.center || settings.autoWidth || settings.dotsData
13052				? 1 : settings.dotsEach || settings.items)
13053		};
13054	};
13055
13056	/**
13057	 * Gets the current page position of the carousel.
13058	 * @protected
13059	 * @returns {Number}
13060	 */
13061	Navigation.prototype.current = function() {
13062		var current = this._core.relative(this._core.current());
13063		return $.grep(this._pages, $.proxy(function(page, index) {
13064			return page.start <= current && page.end >= current;
13065		}, this)).pop();
13066	};
13067
13068	/**
13069	 * Gets the current succesor/predecessor position.
13070	 * @protected
13071	 * @returns {Number}
13072	 */
13073	Navigation.prototype.getPosition = function(successor) {
13074		var position, length,
13075			settings = this._core.settings;
13076
13077		if (settings.slideBy == 'page') {
13078			position = $.inArray(this.current(), this._pages);
13079			length = this._pages.length;
13080			successor ? ++position : --position;
vendor: 5,678 bytes, lines 13081-13305
13081			position = this._pages[((position % length) + length) % length].start;
13082		} else {
13083			position = this._core.relative(this._core.current());
13084			length = this._core.items().length;
13085			successor ? position += settings.slideBy : position -= settings.slideBy;
13086		}
13087
13088		return position;
13089	};
13090
13091	/**
13092	 * Slides to the next item or page.
13093	 * @public
13094	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
13095	 */
13096	Navigation.prototype.next = function(speed) {
13097		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
13098	};
13099
13100	/**
13101	 * Slides to the previous item or page.
13102	 * @public
13103	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
13104	 */
13105	Navigation.prototype.prev = function(speed) {
13106		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
13107	};
13108
13109	/**
13110	 * Slides to the specified item or page.
13111	 * @public
13112	 * @param {Number} position - The position of the item or page.
13113	 * @param {Number} [speed] - The time in milliseconds for the transition.
13114	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
13115	 */
13116	Navigation.prototype.to = function(position, speed, standard) {
13117		var length;
13118
13119		if (!standard) {
13120			length = this._pages.length;
13121			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
13122		} else {
13123			$.proxy(this._overrides.to, this._core)(position, speed);
13124		}
13125	};
13126
13127	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
13128
13129})(window.Zepto || window.jQuery, window, document);
13130
13131/**
13132 * Hash Plugin
13133 * @version 2.0.0-beta.3
13134 * @author Artus Kolanowski
13135 * @license The MIT License (MIT)
13136 */
13137;(function($, window, document, undefined) {
13138	'use strict';
13139
13140	/**
13141	 * Creates the hash plugin.
13142	 * @class The Hash Plugin
13143	 * @param {Owl} carousel - The Owl Carousel
13144	 */
13145	var Hash = function(carousel) {
13146		/**
13147		 * Reference to the core.
13148		 * @protected
13149		 * @type {Owl}
13150		 */
13151		this._core = carousel;
13152
13153		/**
13154		 * Hash index for the items.
13155		 * @protected
13156		 * @type {Object}
13157		 */
13158		this._hashes = {};
13159
13160		/**
13161		 * The carousel element.
13162		 * @type {jQuery}
13163		 */
13164		this.$element = this._core.$element;
13165
13166		/**
13167		 * All event handlers.
13168		 * @protected
13169		 * @type {Object}
13170		 */
13171		this._handlers = {
13172			/*'initialized.owl.carousel': $.proxy(function(e) {
13173				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
13174					$(window).trigger('hashchange.owl.navigation');
13175				}
13176			}, this),*/
13177			'prepared.owl.carousel': $.proxy(function(e) {
13178				if (e.namespace) {
13179					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
13180
13181					if (!hash) {
13182						return;
13183					}
13184
13185					this._hashes[hash] = e.content;
13186				}
13187			}, this),
13188			'changed.owl.carousel': $.proxy(function(e) {
13189				if (e.namespace && e.property.name === 'position') {
13190					var current = this._core.items(this._core.relative(this._core.current())),
13191						hash = $.map(this._hashes, function(item, hash) {
13192							return item === current ? hash : null;
13193						}).join();
13194
13195					if (!hash || window.location.hash.slice(1) === hash) {
13196						return;
13197					}
13198
13199					window.location.hash = hash;
13200				}
13201			}, this)
13202		};
13203
13204		// set default options
13205		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
13206
13207		// register the event handlers
13208		this.$element.on(this._handlers);
13209
13210		// register event listener for hash navigation
13211		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
13212			var hash = window.location.hash.substring(1),
13213				items = this._core.$stage.children(),
13214				position = this._hashes[hash] && items.index(this._hashes[hash]);
13215
13216			if (position === undefined || position === this._core.current()) {
13217				return;
13218			}
13219
13220			this._core.to(this._core.relative(position), false, true);
13221		}, this));*/
13222	};
13223
13224	/**
13225	 * Default options.
13226	 * @public
13227	 */
13228	Hash.Defaults = {
13229		URLhashListener: false
13230	};
13231
13232	/**
13233	 * Destroys the plugin.
13234	 * @public
13235	 */
13236	Hash.prototype.destroy = function() {
13237		var handler, property;
13238
13239		$(window).off('hashchange.owl.navigation');
13240
13241		for (handler in this._handlers) {
13242			this._core.$element.off(handler, this._handlers[handler]);
13243		}
13244		for (property in Object.getOwnPropertyNames(this)) {
13245			typeof this[property] != 'function' && (this[property] = null);
13246		}
13247	};
13248
13249	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
13250
13251})(window.Zepto || window.jQuery, window, document);
13252
13253/**
13254 * Support Plugin
13255 *
13256 * @version 2.0.0-beta.3
13257 * @author Vivid Planet Software GmbH
13258 * @author Artus Kolanowski
13259 * @license The MIT License (MIT)
13260 */
13261;(function($, window, document, undefined) {
13262
13263	var style = $('<support>').get(0).style,
13264		prefixes = 'Webkit Moz O ms'.split(' '),
13265		events = {
13266			transition: {
13267				end: {
13268					WebkitTransition: 'webkitTransitionEnd',
13269					MozTransition: 'transitionend',
13270					OTransition: 'oTransitionEnd',
13271					transition: 'transitionend'
13272				}
13273			},
13274			animation: {
13275				end: {
13276					WebkitAnimation: 'webkitAnimationEnd',
13277					MozAnimation: 'animationend',
13278					OAnimation: 'oAnimationEnd',
13279					animation: 'animationend'
13280				}
13281			}
13282		},
13283		tests = {
13284			csstransforms: function() {
13285				return !!test('transform');
13286			},
13287			csstransforms3d: function() {
13288				return !!test('perspective');
13289			},
13290			csstransitions: function() {
13291				return !!test('transition');
13292			},
13293			cssanimations: function() {
13294				return !!test('animation');
13295			}
13296		};
13297
13298	function test(property, prefixed) {
13299		var result = false,
13300			upper = property.charAt(0).toUpperCase() + property.slice(1);
13301
13302		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
13303			if (style[property] !== undefined) {
13304				result = prefixed ? property : true;
13305				return false;
13306			}
13307		});
13308
13309		return result;
13310	}
13311
13312	function prefixed(property) {
13313		return test(property, true);
13314	}
13315
13316	if (tests.csstransitions()) {
13317		/* jshint -W053 */
13318		$.support.transition = new String(prefixed('transition'))
13319		$.support.transition.end = events.transition.end[ $.support.transition ];
13320	}
13321
13322	if (tests.cssanimations()) {
13323		/* jshint -W053 */
13324		$.support.animation = new String(prefixed('animation'))
13325		$.support.animation.end = events.animation.end[ $.support.animation ];
13326	}
13327
13328	if (tests.csstransforms()) {
13329		/* jshint -W053 */
13330		$.support.transform = new String(prefixed('transform'));
13331		$.support.transform3d = tests.csstransforms3d();
13332	}
13333
13334})(window.Zepto || window.jQuery, window, document);
13335
13336(function(window, document, undefined) {
13337
13338    /**
13339     * Find the absolute position of an element
13340     */
13341    var absPos = function(element) {
13342        var offsetLeft, offsetTop;
13343        offsetLeft = offsetTop = 0;
13344        if (element.offsetParent) {
13345            do {
13346                offsetLeft += element.offsetLeft;
13347                offsetTop += element.offsetTop;
13348            } while (element = element.offsetParent);
13349        }
13350        return [offsetLeft, offsetTop];
13351    };
13352
13353    /**
13354     * @constructor Progress Circle class
13355     * @param params.canvas Canvas on which the circles will be drawn.
13356     * @param params.minRadius Inner radius of the innermost circle, in px.
13357     * @param params.arcWidth Width of each circle(to be more accurate, ring).
13358     * @param params.gapWidth Space between each circle.
13359     * @param params.centerX X coordinate of the center of circles.
13360     * @param params.centerY Y coordinate of the center of circles.
13361     * @param params.infoLineBaseAngle Base angle of the info line.
13362     * @param params.infoLineAngleInterval Angles between the info lines.
13363     */
13364    var ProgressCircle = function(params) {
13365        this.canvas = params.canvas;
13366        this.minRadius = params.minRadius || 15;
13367        this.arcWidth = params.arcWidth || 5;
13368        this.gapWidth = params.gapWidth || 3;
13369        this.centerX = params.centerX || this.canvas.width / 2;
13370        this.centerY = params.centerY || this.canvas.height / 2;
13371        this.infoLineLength = params.infoLineLength || 60;
13372        this.horizLineLength = params.horizLineLength || 10;
13373        this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
13374        this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
13375
13376        this.context = this.canvas.getContext('2d');
13377
13378        this.width = this.canvas.width;
13379        this.height = this.canvas.height;
13380
13381        this.circles = [];
13382        this.runningCount = 0;
13383    };
13384
13385    ProgressCircle.prototype = {
13386        constructor: ProgressCircle,
13387
13388        /**
13389         * @method Adds an progress monitor entry.
13390         * @param params.fillColor Color to fill in the circle.
13391         * @param params.outlineColor Color to outline the circle.
13392         * @param params.progressListener Callback function to fetch the progress.
13393         * @param params.infoListener Callback function to fetch the info.
13394         * @returns this
13395         */
13396        addEntry: function(params) {
13397            this.circles.push(new Circle({
13398                canvas: this.canvas,
13399                context: this.context,
13400                centerX: this.centerX,
13401                centerY: this.centerY,
13402                innerRadius: this.minRadius + this.circles.length *
13403                    (this.gapWidth + this.arcWidth),
13404                arcWidth: this.arcWidth,
13405                infoLineLength: this.infoLineLength,
13406                horizLineLength: this.horizLineLength,
13407
13408                id: this.circles.length,
13409                fillColor: params.fillColor,
13410                outlineColor: params.outlineColor,
13411                progressListener: params.progressListener,
13412                infoListener: params.infoListener,
13413                infoLineAngle: this.infoLineBaseAngle +
13414                    this.circles.length * this.infoLineAngleInterval,
13415            }));
13416
13417            return this;
13418        },
13419
13420        /**
13421         * @method Starts the monitor and updates with the given interval.
13422         * @param interval Interval between updates, in millisecond.
13423         * @returns this
13424         */
13425        start: function(interval) {
13426            var self = this;
13427            this.timer = setInterval(function() {
13428                self._update();
13429            }, interval || 33);
13430
13431            return this;
13432        },
13433
13434        /**
13435         * @method Stop the animation.
13436         */
13437        stop: function() {
13438            clearTimeout(this.timer);
13439        },
13440
13441        /**
13442         * @private
13443         * @method Call update on each circle and redraw them.
13444         * @returns this
13445         */
13446        _update: function() {
13447            this._clear();
13448            this.circles.forEach(function(circle, idx, array) {
13449                circle.update();
13450            });
13451
13452            return this;
13453        },
13454
13455        /**
13456         * @private
13457         * @method Clear the canvas.
13458         * @returns this
13459         */
13460        _clear: function() {
13461            this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
13462
13463            return this;
13464        },
13465
13466    };
13467
13468    /**
13469     * @private
13470     * @class Individual progress circle.
13471     * @param params.canvas Canvas on which the circle will be drawn.
13472     * @param params.context Context of the canvas.
13473     * @param params.innerRadius Inner radius of the circle, in px.
13474     * @param params.arcWidth Width of each arc(circle).
13475     * @param params.gapWidth Distance between each arc.
13476     * @param params.centerX X coordinate of the center of circles.
13477     * @param params.centerY Y coordinate of the center of circles.
13478     * @param params.fillColor Color to fill in the circle.
13479     * @param params.outlineColor Color to outline the circle.
13480     * @param params.progressListener Callback function to fetch the progress.
13481     * @param params.infoListener Callback function to fetch the info.
13482     * @param params.infoLineAngle Angle of info line.
13483     */
13484    var Circle = function(params) {
13485        this.id = params.id;
13486        this.canvas = params.canvas;
13487        this.context = params.context;
13488        this.centerX = params.centerX;
13489        this.centerY = params.centerY;
13490        this.arcWidth = params.arcWidth;
13491        this.innerRadius = params.innerRadius || 0;
13492        this.fillColor = params.fillColor || '#fff';
13493        this.outlineColor = params.outlineColor || this.fillColor;
13494        this.progressListener = params.progressListener;
13495        this.infoLineLength = params.infoLineLength || 250;
13496        this.horizLineLength = params.horizLineLength || 50;
13497        this.infoListener = params.infoListener;
13498        this.infoLineAngle = params.infoLineAngle;
13499
13500        this.outerRadius = this.innerRadius + this.arcWidth;
13501
13502        // If the info listener is not registered, then don't calculate
13503        // the related coordinates
13504        if (!this.infoListener) return;
13505
13506        // calculate the info-line turning points
13507        var angle = this.infoLineAngle,
13508            arcDistance = (this.innerRadius + this.outerRadius) / 2,
13509
13510            sinA = Math.sin(angle),
13511            cosA = Math.cos(angle);
13512
13513        this.infoLineStartX = this.centerX + sinA * arcDistance;
13514        this.infoLineStartY = this.centerY - cosA * arcDistance;
13515
13516        this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
13517        this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
13518
13519        this.infoLineEndX = this.infoLineMidX +
13520             (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
13521        this.infoLineEndY = this.infoLineMidY;
13522
13523        var infoText = document.createElement('div'),
13524            style = infoText.style;
13525
13526        style.color = this.fillColor;
13527        style.position = 'absolute';
13528        style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
13529        // style.top will be calculated in the `drawInfo` method. Since
13530        // user may want to change the size of the font, so the top offset
13531        // must be updated in each loop.
13532        infoText.className = 'ProgressCircleInfo'; // For css styling
13533        infoText.id = 'progress_circle_info_' + this.id;
13534        document.body.appendChild(infoText);
13535        this.infoText = infoText;
13536    };
13537
13538    Circle.prototype = {
13539        constructor: Circle,
13540
13541        update: function() {
13542            this.progress = this.progressListener();
13543            this._draw();
13544
13545            if (this.infoListener) {
13546                this.info = this.infoListener();
13547                this._drawInfo();
13548            }
13549        },
13550
13551        /**
13552         * @private
13553         * @method Draw the circle on the canvas.
13554         * @returns this
13555         */
13556        _draw: function() {
13557            var ctx = this.context,
13558
13559                ANGLE_OFFSET = -Math.PI / 2,
13560
13561                startAngle = 0 + ANGLE_OFFSET,
13562                endAngle= startAngle + this.progress * Math.PI * 2,
13563
13564                x = this.centerX,
13565                y = this.centerY,
13566
13567                innerRadius = this.innerRadius - this.arcWidth - 1,
13568                outerRadius = this.outerRadius - this.arcWidth - 1;
13569
13570            ctx.fillStyle = this.fillColor;
13571            ctx.strokeStyle = this.outlineColor;
13572
13573            ctx.beginPath();
13574            ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
13575            ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
13576            ctx.closePath();
13577            ctx.stroke();
13578            ctx.fill();
13579
13580            return this;
13581        },
13582
13583        /**
13584         * @private
13585         * @method Draw the info lines and info text.
13586         * @returns this
13587         */
13588        _drawInfo: function() {
13589
13590            var pointList, lineHeight;
13591
13592            pointList = [
13593                [this.infoLineStartX, this.infoLineStartY],
13594                [this.infoLineMidX, this.infoLineMidY],
13595                [this.infoLineEndX, this.infoLineEndY],
13596            ];
13597            this._drawSegments(pointList, false);
13598
13599            this.infoText.innerHTML = this.info;
13600
13601            lineHeight = this.infoText.offsetHeight;
13602            this.infoText.style.top = this.infoLineEndY +
13603                absPos(this.canvas)[1] - lineHeight / 2 + 'px';
13604
13605            return this;
13606        },
13607
13608        /**
13609         * @private
13610         * @method Helper function to draw the segments
13611         * @param pointList An array of points in the form of [x, y].
13612         * @param close Whether to connect the first and last point.
13613         */
13614        _drawSegments: function(pointList, close) {
13615            var ctx = this.context;
13616
13617            ctx.beginPath();
13618            ctx.moveTo(pointList[0][0], pointList[0][1]);
13619            for (var i = 1; i < pointList.length; ++i) {
13620                ctx.lineTo(pointList[i][0], pointList[i][1]);
13621            }
13622
13623            if (close) {
13624                ctx.closePath();
13625            }
13626            ctx.stroke();
13627        },
13628    };
13629
13630    window.ProgressCircle = ProgressCircle;
13631
13632})(window, document);
13633
13634
13635
13636
13637/* =========================================================
13638 * jquery.vc_chart.js v1.0
13639 * =========================================================
13640 * Copyright 2013 Wpbakery
13641 *
13642 * Jquery chart plugin for the Visual Composer.
13643 * ========================================================= */
13644(function($){
13645    /**
13646     * Pie chart animated.
13647     * @param element - DOM element
13648     * @param options - settings object.
13649     * @constructor
13650     */
13651    var VcChart = function(element, options) {
13652        this.el = element;
13653        this.$el = $(this.el);
13654        this.options = $.extend({
13655            color: 'wpb_button',
13656            units: '',
13657            width: '',
13658            label_selector: '.vc_pie_chart_value',
13659            back_selector: '.vc_pie_chart_back',
13660            responsive: true
13661        }, options);
13662        this.init();
13663    };
13664    VcChart.prototype = {
13665        constructor: VcChart,
13666        _progress_v: 0,
13667        animated: false,
13668        colors: {
13669            'wpb_button': 'rgba(247, 247, 247, 1)',
13670            'btn-primary': 'rgba(0, 136, 204, 1)',
13671            'btn-info': 'rgba(88, 185, 218, 1)',
13672            'btn-success': 'rgba(106, 177, 101, 1)',
13673            'btn-warning': 'rgba(255, 153, 0, 1)',
13674            'btn-danger': 'rgba(255, 103, 91, 1)',
13675            'btn-inverse': 'rgba(85, 85, 85, 1)'
13676        },
13677        init: function() {
13678            this.setupColor();
13679            this.value = this.$el.data('pie-value')/100;
13680            this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
13681            this.$wrapper = $('.vc_pie_wrapper', this.$el);
13682            this.$label = $(this.options.label_selector, this.$el);
13683            this.$back = $(this.options.back_selector, this.$el);
13684            this.$canvas = this.$el.find('canvas');
13685            this.arcWidth = this.$el.data('pie-width') * 2;
13686            this.draw();
13687            this.setWayPoint();
13688            if(this.options.responsive === true) this.setResponsive();
13689            if (UNCODE.isMobile) this._progress_v = this.value;
13690        },
13691        setupColor: function() {
13692            // if(typeof this.colors[this.options.color] !== 'undefined') {
13693            //     this.color = this.colors[this.options.color];
13694            // } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
13695            //     this.color = this.options.color;
13696            // } else {
13697            //     this.color = 'rgba(247, 247, 247, 0.2)';
13698            // }
13699            if(typeof this.options.color !== 'undefined') {
13700                this.color = this.options.color;
13701            } else this.color = 'rgba(247, 247, 247, 0.2)';
13702
13703        },
13704        setResponsive: function() {
13705            var that = this;
13706            if (!UNCODE.isMobile) {
13707                $(window).resize(function(){
13708                    if(that.animated === true) that.circle.stop();
13709                    that.draw(true);
13710                });
13711            }
13712        },
13713          draw: function(redraw) {
13714            var w = this.$el.addClass('vc_ready').width() * 2,
13715                border_w = this.arcWidth,
13716                radius;
13717            if(!w) w = this.$el.parents(':visible').first().width()-2;
13718            //w = Math.round(w/100*80);
13719            //if (w < 250) w = 250;
13720            radius = w/2;
13721            this.$wrapper.css({"width" : (w / 2) + "px"});
13722            this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
13723            this.$back.css({"width" : (w / 2), "height" : (w / 2)});
13724            this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
13725            this.$el.addClass('vc_ready');
13726            this.circle = new ProgressCircle({
13727                canvas: this.$canvas.get(0),
13728                minRadius: radius,
13729                arcWidth: border_w
13730            });
13731            if(redraw === true && this.animated === true) {
13732                this._progress_v = this.value;
13733                this.circle.addEntry({
13734                    fillColor: this.color,
13735                    progressListener: $.proxy(this.setProgress, this)
13736                }).start();
13737            }
13738        },
13739        setProgress: function() {
13740            if (this._progress_v >= this.value) {
13741                this.circle.stop();
13742                this.$label.html(this.label_value + this.options.units);
13743                return this._progress_v;
13744            }
13745            this._progress_v += 0.01;
13746            if (!isNaN(this.label_value)) {
13747                var label_value = this._progress_v/this.value*this.label_value;
13748                var val = Math.round(label_value) + this.options.units;
13749                this.$label.html(val);
13750            } else this.$label.html(this.label_value + this.options.units);
13751            return this._progress_v;
13752        },
13753        animate: function() {
13754            if(this.animated !== true) {
13755                this.animated = true;
13756                this.circle.addEntry({
13757                    fillColor: this.color,
13758                    progressListener: $.proxy(this.setProgress, this)
13759                }).start(5);
13760            }
13761        },
13762        setWayPoint: function() {
13763            if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
13764                this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
13765            } else {
13766                this.animate();
13767            }
13768        }
13769    };
13770    /**
13771     * jQuery plugin
13772     * @param option - object with settings
13773     * @return {*}
13774     */
13775    $.fn.vcChat = function(option, value) {
13776        return this.each(function () {
13777            var $this = $(this),
13778                data = $this.data('vc_chart'),
13779                options = typeof option === 'object' ? option : {
13780                    color: $this.data('pie-color'),
13781                    units: $this.data('pie-units')
13782                };
13783            if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
13784            if (typeof option == 'string') data[option](value);
13785        });
13786    };
13787    /**
13788     * Allows users to rewrite function inside theme.
13789     */
13790    if ( typeof window['vc_pieChart'] !== 'function' ) {
13791        window.vc_pieChart = function() {
13792            $('.vc_pie_chart:visible').vcChat();
13793        }
13794    }
13795    $(document).ready(function(){
13796        !window.vc_iframe && vc_pieChart();
13797    });
13798
13799})(window.jQuery);
13800
13801
13802/* Progress bar
13803 ---------------------------------------------------------- */
13804function uncode_progress_bar() {    
13805	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
13806		if (!UNCODE.isMobile) {
13807			new Waypoint({
13808				element: val,
13809				handler: function() {
13810					var element = jQuery(this.element);
13811					element.find('.vc_single_bar').each(function(index) {          
13812						var $this = jQuery(this),
13813							            bar = $this.find('.vc_bar'),
13814							            val = bar.data('percentage-value');          
13815						setTimeout(function() {            
13816							bar.css({
13817								"width": val + '%'
13818							});          
13819						}, index * 200);        
13820					});
13821				},
13822				offset: '80%'
13823			});
13824		} else {
13825			var element = jQuery(val);
13826			element.find('.vc_single_bar').each(function(index) {          
13827				var $this = jQuery(this),
13828					            bar = $this.find('.vc_bar'),
13829					            val = bar.data('percentage-value');          
13830				setTimeout(function() {            
13831					bar.css({
13832						"width": val + '%'
13833					});          
13834				}, index * 200);        
13835			});
13836		}
13837	});
13838};
13839uncode_progress_bar();
13840
13841/*!
13842 * jquery.counterup.js 1.0
13843 *
13844 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
13845 * Released under the GPL v2 License
13846 *
13847 * Date: Nov 26, 2013
13848 */
13849(function($) {
13850	"use strict";
13851	$.fn.counterUp = function(options) {
13852		// Defaults
13853		var settings = $.extend({
13854			'time': 400,
13855			'delay': 10
13856		}, options);
13857		return this.each(function() {
13858			// Store the object
13859			var $this = $(this);
13860			var $settings = settings;
13861			var counterUpper = function() {
13862				var nums = [];
13863				var divisions = $settings.time / $settings.delay;
13864				var numReal = $this.attr('data-val'),
13865				num = numReal;
13866				var isComma = /[0-9]+,[0-9]+/.test(num);
13867				num = num.replace(/,/g, '');
13868				var isInt = /^[0-9]+$/.test(num);
13869				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
13870				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
13871				// Generate list of incremental numbers to display
13872				for (var i = divisions; i >= 1; i--) {
13873					// Preserve as int if input was int
13874					var newNum = parseInt(num / divisions * i);
13875					// Preserve float if input was float
13876					if (isFloat) {
13877						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
13878					}
13879					// Preserve commas if input had commas
13880					if (isComma) {
13881						while (/(\d+)(\d{3})/.test(newNum.toString())) {
13882							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
13883						}
13884					}
13885					nums.unshift(newNum);
13886				}
13887				nums.push(numReal);
13888				$this.data('counterup-nums', nums);
13889				$this.text('0');
13890				// Updates the number until we're done
13891				var f = function() {
13892					if ($this.data('counterup-nums') != null) {
13893						$this.text($this.data('counterup-nums').shift());
13894						if ($this.data('counterup-nums').length) {
13895							setTimeout($this.data('counterup-func'), $settings.delay);
13896						} else {
13897							delete $this.data('counterup-nums');
13898							$this.data('counterup-nums', null);
13899							$this.data('counterup-func', null);
13900						}
13901					}
13902				};
13903				$this.data('counterup-func', f);
13904				// Start the count up
13905				setTimeout($this.data('counterup-func'), $settings.delay);
13906			};
13907			// Perform counts when the element gets into view
13908			new Waypoint({
13909				element: this,
13910				handler: function() {
13911					counterUpper();
13912					this.destroy();
13913				},
13914				offset: '100%'
13915			});
13916		});
13917	};
13918})(jQuery);
13919
13920/*!
13921 * The Final Countdown for jQuery v2.0.4 (http://hilios.github.io/jQuery.countdown/)
13922 * Copyright (c) 2014 Edson Hilios
13923 * 
13924 * Permission is hereby granted, free of charge, to any person obtaining a copy of
13925 * this software and associated documentation files (the "Software"), to deal in
13926 * the Software without restriction, including without limitation the rights to
13927 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13928 * the Software, and to permit persons to whom the Software is furnished to do so,
13929 * subject to the following conditions:
13930 * 
13931 * The above copyright notice and this permission notice shall be included in all
13932 * copies or substantial portions of the Software.
13933 * 
13934 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13935 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
13936 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13937 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13938 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
13939 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13940 */
13941!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;
13941if(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])})}});
13942
13943/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05
13944* https://github.com/alexanderdickson/waitForImages
13945* Copyright (c) 2015 Alex Dickson; Licensed MIT */
13946;(function (factory) {
13947    if (typeof define === 'function' && define.amd) {
13948        // AMD. Register as an anonymous module.
13949        define(['jquery'], factory);
13950    } else if (typeof exports === 'object') {
13951        // CommonJS / nodejs module
13952        module.exports = factory(require('jquery'));
13953    } else {
13954        // Browser globals
13955        factory(jQuery);
13956    }
13957}(function ($) {
13958    // Namespace all events.
13959    var eventNamespace = 'waitForImages';
13960
13961    // CSS properties which contain references to images.
13962    $.waitForImages = {
13963        hasImageProperties: [
13964            'backgroundImage',
13965            'listStyleImage',
13966            'borderImage',
13967            'borderCornerImage',
13968            'cursor'
13969        ],
13970        hasImageAttributes: ['srcset']
13971    };
13972
13973    // Custom selector to find `img` elements that have a valid `src`
13974    // attribute and have not already loaded.
13975    $.expr[':'].uncached = function (obj) {
13976        // Ensure we are dealing with an `img` element with a valid
13977        // `src` attribute.
13978        if (!$(obj).is('img[src][src!=""]')) {
13979            return false;
13980        }
13981
13982        return !obj.complete;
13983    };
13984
13985    $.fn.waitForImages = function () {
13986
13987        var allImgsLength = 0;
13988        var allImgsLoaded = 0;
13989        var deferred = $.Deferred();
13990
13991        var finishedCallback;
13992        var eachCallback;
13993        var waitForAll;
13994
13995        // Handle options object (if passed).
13996        if ($.isPlainObject(arguments[0])) {
13997
13998            waitForAll = arguments[0].waitForAll;
13999            eachCallback = arguments[0].each;
14000            finishedCallback = arguments[0].finished;
14001
14002        } else {
14003
14004            // Handle if using deferred object and only one param was passed in.
14005            if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
14006                waitForAll = arguments[0];
14007            } else {
14008                finishedCallback = arguments[0];
14009                eachCallback = arguments[1];
14010                waitForAll = arguments[2];
14011            }
14012
14013        }
14014
14015        // Handle missing callbacks.
14016        finishedCallback = finishedCallback || $.noop;
14017        eachCallback = eachCallback || $.noop;
14018
14019        // Convert waitForAll to Boolean
14020        waitForAll = !! waitForAll;
14021
14022        // Ensure callbacks are functions.
14023        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
14024            throw new TypeError('An invalid callback was supplied.');
14025        }
14026
14027        this.each(function () {
14028            // Build a list of all imgs, dependent on what images will
14029            // be considered.
14030            var obj = $(this);
14031            var allImgs = [];
14032            // CSS properties which may contain an image.
14033            var hasImgProperties = $.waitForImages.hasImageProperties || [];
14034            // Element attributes which may contain an image.
14035            var hasImageAttributes = $.waitForImages.hasImageAttributes || [];
14036            // To match `url()` references.
14037            // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
14038            var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
14039
14040            if (waitForAll) {
14041
14042                // Get all elements (including the original), as any one of
14043                // them could have a background image.
14044                obj.find('*').addBack().each(function () {
14045                    var element = $(this);
14046
14047                    // If an `img` element, add it. But keep iterating in
14048                    // case it has a background image too.
14049                    if (element.is('img:uncached')) {
14050                        allImgs.push({
14051                            src: element.attr('src'),
14052                            element: element[0]
14053                        });
14054                    }
14055
14056                    $.each(hasImgProperties, function (i, property) {
14057                        var propertyValue = element.css(property);
14058                        var match;
14059
14060                        // If it doesn't contain this property, skip.
14061                        if (!propertyValue) {
14062                            return true;
14063                        }
14064
14065                        // Get all url() of this element.
14066                        while (match = matchUrl.exec(propertyValue)) {
14067                            allImgs.push({
14068                                src: match[2],
14069                                element: element[0]
14070                            });
14071                        }
14072                    });
14073
14074                    $.each(hasImageAttributes, function (i, attribute) {
14075                        var attributeValue = element.attr(attribute);
14076                        var attributeValues;
14077
14078                        // If it doesn't contain this property, skip.
14079                        if (!attributeValue) {
14080                            return true;
14081                        }
14082
14083                        // Check for multiple comma separated images
14084                        attributeValues = attributeValue.split(',');
14085
14086                        $.each(attributeValues, function(i, value) {
14087                            // Trim value and get string before first
14088                            // whitespace (for use with srcset).
14089                            value = $.trim(value).split(' ')[0];
14090                            allImgs.push({
14091                                src: value,
14092                                element: element[0]
14093                            });
14094                        });
14095                    });
14096                });
14097            } else {
14098                // For images only, the task is simpler.
14099                obj.find('img:uncached')
14100                    .each(function () {
14101                    allImgs.push({
14102                        src: this.src,
14103                        element: this
14104                    });
14105                });
14106            }
14107
14108            allImgsLength = allImgs.length;
14109            allImgsLoaded = 0;
14110
14111            // If no images found, don't bother.
14112            if (allImgsLength === 0) {
14113                finishedCallback.call(obj[0]);
14114                deferred.resolveWith(obj[0]);
14115            }
14116
14117            $.each(allImgs, function (i, img) {
14118
14119                var image = new Image();
14120                var events =
14121                  'load.' + eventNamespace + ' error.' + eventNamespace;
14122
14123                // Handle the image loading and error with the same callback.
14124                $(image).one(events, function me (event) {
14125                    // If an error occurred with loading the image, set the
14126                    // third argument accordingly.
14127                    var eachArguments = [
14128                        allImgsLoaded,
14129                        allImgsLength,
14130                        event.type == 'load'
14131                    ];
14132                    allImgsLoaded++;
14133
14134                    eachCallback.apply(img.element, eachArguments);
14135                    deferred.notifyWith(img.element, eachArguments);
14136
14137                    // Unbind the event listeners. I use this in addition to
14138                    // `one` as one of those events won't be called (either
14139                    // 'load' or 'error' will be called).
14140                    $(this).off(events, me);
14141
14142                    if (allImgsLoaded == allImgsLength) {
14143                        finishedCallback.call(obj[0]);
14144                        deferred.resolveWith(obj[0]);
14145                        return false;
14146                    }
14147
14148                });
14149
14150                image.src = img.src;
14151            });
14152        });
14153
14154        return deferred.promise();
14155
14156    };
14157}));
14158
14159/**
14160 * @preserve  textfill
14161 * @name      jquery.textfill.js
14162 * @author    Russ Painter
14163 * @author    Yu-Jie Lin
14164 * @author    Alexandre Dantas
14165 * @version   0.6.0
14166 * @date      2014-08-19
14167 * @copyright (c) 2014 Alexandre Dantas
14168 * @copyright (c) 2012-2013 Yu-Jie Lin
14169 * @copyright (c) 2009 Russ Painter
14170 * @license   MIT License
14171 * @homepage  https://github.com/jquery-textfill/jquery-textfill
14172 * @example   http://jquery-textfill.github.io/jquery-textfill/index.html
14173 */
14174; (function($) {
14175
14176	/**
14177	 * Resizes an inner element's font so that the
14178	 * inner element completely fills the outer element.
14179	 *
14180	 * @param {Object} options User options that take
14181	 *                         higher precedence when
14182	 *                         merging with the default ones.
14183	 *
14184	 * @return All outer elements processed
14185	 */
14186	$.fn.textfill = function(options) {
14187
14188		// ______  _______ _______ _______ _     _        _______ _______
14189		// |     \ |______ |______ |_____| |     | |         |    |______
14190		// |_____/ |______ |       |     | |_____| |_____    |    ______|
14191        //
14192		// Merging user options with the default values
14193
14194		var defaults = {
14195			debug            : false,
14196			maxFontPixels    : 40,
14197			minFontPixels    : 4,
14198			innerTag         : 'span',
14199			widthOnly        : false,
14200			success          : null, // callback when a resizing is done
14201			callback         : null, // callback when a resizing is done (deprecated, use success)
14202			fail             : null, // callback when a resizing is failed
14203			complete         : null, // callback when all is done
14204			explicitWidth    : null,
14205			explicitHeight   : null,
14206			changeLineHeight : false
14207		};
14208
14209		var Opts = $.extend(defaults, options);
14210
14211		// _______ _     _ __   _ _______ _______ _____  _____  __   _ _______
14212		// |______ |     | | \  | |          |      |   |     | | \  | |______
14213		// |       |_____| |  \_| |_____     |    __|__ |_____| |  \_| ______|
14214		//
14215		// Predefining the awesomeness
14216
14217		// Output arguments to the Debug console
14218		// if "Debug Mode" is enabled
14219		function _debug() {
14220			if (!Opts.debug
14221				||  typeof console       == 'undefined'
14222				||  typeof console.debug == 'undefined') {
14223				return;
14224			}
14225			console.debug.apply(console, arguments);
14226		}
14227
14228		// Output arguments to the Warning console
14229		function _warn() {
14230			if (typeof console      == 'undefined' ||
14231				typeof console.warn == 'undefined') {
14232				return;
14233			}
14234			console.warn.apply(console, arguments);
14235		}
14236
14237		// Outputs all information on the current sizing
14238		// of the font.
14239		function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
14240
14241			function _m(v1, v2) {
14242
14243				var marker = ' / ';
14244
14245				if (v1 > v2)
14246					marker = ' > ';
14247
14248				else if (v1 == v2)
14249					marker = ' = ';
14250
14251				return marker;
14252			}
14253
14254			_debug(
14255				'[TextFill] '  + prefix + ' { ' +
14256				'font-size: ' + ourText.css('font-size') + ',' +
14257				'Height: '    + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' +
14258				'Width: '     + ourText.width()  + _m(ourText.width() , maxWidth)  + maxWidth + ',' +
14259				'minFontPixels: ' + minFontPixels + 'px, ' +
14260				'maxFontPixels: ' + maxFontPixels + 'px }'
14261			);
14262		}
14263
14264		/**
14265		 * Calculates which size the font can get resized,
14266		 * according to constrains.
14267		 *
14268		 * @param {String} prefix Gets shown on the console before
14269		 *                        all the arguments, if debug mode is on.
14270		 * @param {Object} ourText The DOM element to resize,
14271		 *                         that contains the text.
14272		 * @param {function} func Function called on `ourText` that's
14273		 *                        used to compare with `max`.
14274		 * @param {number} max Maximum value, that gets compared with
14275		 *                     `func` called on `ourText`.
14276		 * @param {number} minFontPixels Minimum value the font can
14277		 *                               get resized to (in pixels).
14278		 * @param {number} maxFontPixels Maximum value the font can
14279		 *                               get resized to (in pixels).
14280		 *
14281		 * @return Size (in pixels) that the font can be resized.
14282		 */
14283		function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
14284
14285			_debug_sizing(
14286				prefix, ourText,
14287				maxHeight, maxWidth,
14288				minFontPixels, maxFontPixels
14289			);
14290
14291			// The kernel of the whole plugin, take most attention
14292			// on this part.
14293			//
14294			// This is a loop that keeps increasing the `font-size`
14295			// until it fits the parent element.
14296			//
14297			// - Start from the minimal allowed value (`minFontPixels`)
14298			// - Guesses an average font size (in pixels) for the font,
14299			// - Resizes the text and sees if its size is within the
14300			//   boundaries (`minFontPixels` and `maxFontPixels`).
14301			//   - If so, keep guessing until we break.
14302			//   - If not, return the last calculated size.
14303			//
14304			// I understand this is not optimized and we should
14305			// consider implementing something akin to
14306			// Daniel Hoffmann's answer here:
14307			//
14308			//     http://stackoverflow.com/a/17433451/1094964
14309			//
14310
14311			while (minFontPixels < (maxFontPixels - 1)) {
14312
14313				var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2);
14314				ourText.css('font-size', fontSize);
14315
14316				if (func.call(ourText) <= max) {
14317					minFontPixels = fontSize;
14318
14319					if (func.call(ourText) == max)
14320						break;
14321				}
14322				else
14323					maxFontPixels = fontSize;
14324
14325				_debug_sizing(
14326					prefix, ourText,
14327					maxHeight, maxWidth,
14328					minFontPixels, maxFontPixels
14329				);
14330			}
14331
14332			ourText.css('font-size', maxFontPixels);
14333
14334			if (func.call(ourText) <= max) {
14335				minFontPixels = maxFontPixels;
14336
14337				_debug_sizing(
14338					prefix + '* ', ourText,
14339					maxHeight, maxWidth,
14340					minFontPixels, maxFontPixels
14341				);
14342			}
14343			return minFontPixels;
14344		}
14345
14346		// _______ _______ _______  ______ _______
14347		// |______    |    |_____| |_____/    |
14348		// ______|    |    |     | |    \_    |
14349        //
14350		// Let's get it started (yeah)!
14351
14352		_debug('[TextFill] Start Debug');
14353
14354		this.each(function() {
14355
14356			// Contains the child element we will resize.
14357			// $(this) means the parent container
14358			var ourText = $(Opts.innerTag + ':visible:first', this);
14359
14360			// Will resize to this dimensions.
14361			// Use explicit dimensions when specified
14362			var maxHeight = Opts.explicitHeight || $(this).height();
14363			var maxWidth  = Opts.explicitWidth  || $(this).width();
14364
14365			var oldFontSize = ourText.css('font-size');
14366
14367			var lineHeight  = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize);
14368
14369			_debug('[TextFill] Inner text: ' + ourText.text());
14370			_debug('[TextFill] All options: ', Opts);
14371			_debug('[TextFill] Maximum sizes: { ' +
14372				   'Height: ' + maxHeight + 'px, ' +
14373				   'Width: '  + maxWidth  + 'px' + ' }'
14374				  );
14375
14376			var minFontPixels = Opts.minFontPixels;
14377
14378			// Remember, if this `maxFontPixels` is negative,
14379			// the text will resize to as long as the container
14380			// can accomodate
14381			var maxFontPixels = (Opts.maxFontPixels <= 0 ?
14382								 maxHeight :
14383								 Opts.maxFontPixels);
14384
14385
14386			// Let's start it all!
14387
14388			// 1. Calculate which `font-size` would
14389			//    be best for the Height
14390			var fontSizeHeight = undefined;
14391
14392			if (! Opts.widthOnly)
14393				fontSizeHeight = _sizing(
14394					'Height', ourText,
14395					$.fn.height, maxHeight,
14396					maxHeight, maxWidth,
14397					minFontPixels, maxFontPixels
14398				);
14399
14400			// 2. Calculate which `font-size` would
14401			//    be best for the Width
14402			var fontSizeWidth = undefined;
14403
14404			fontSizeWidth = _sizing(
14405				'Width', ourText,
14406				$.fn.width, maxWidth,
14407				maxHeight, maxWidth,
14408				minFontPixels, maxFontPixels
14409			);
14410
14411			// 3. Actually resize the text!
14412
14413			if (Opts.widthOnly) {
14414				ourText.css({
14415					'font-size'  : fontSizeWidth,
14416					'white-space': 'nowrap'
14417				});
14418
14419				if (Opts.changeLineHeight)
14420					ourText.parent().css(
14421						'line-height',
14422						(lineHeight * fontSizeWidth + 'px')
14423					);
14424			}
14425			else {
14426				var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth);
14427
14428				ourText.css('font-size', fontSizeFinal);
14429
14430				if (Opts.changeLineHeight)
14431					ourText.parent().css(
14432						'line-height',
14433						(lineHeight * fontSizeFinal) + 'px'
14434					);
14435			}
14436
14437			_debug(
14438				'[TextFill] Finished { ' +
14439				'Old font-size: ' + oldFontSize              + ', ' +
14440				'New font-size: ' + ourText.css('font-size') + ' }'
14441			);
14442
14443			// Oops, something wrong happened!
14444			// We weren't supposed to exceed the original size
14445			if ((ourText.width()  > maxWidth) ||
14446				(ourText.height() > maxHeight && !Opts.widthOnly)) {
14447
14448				ourText.css('font-size', oldFontSize);
14449
14450				// Failure callback
14451				if (Opts.fail)
14452					Opts.fail(this);
14453
14454				_debug(
14455					'[TextFill] Failure { ' +
14456					'Current Width: '  + ourText.width()  + ', ' +
14457					'Maximum Width: '  + maxWidth         + ', ' +
14458					'Current Height: ' + ourText.height() + ', ' +
14459					'Maximum Height: ' + maxHeight        + ' }'
14460				);
14461			}
14462			else if (Opts.success) {
14463				Opts.success(this);
14464			}
14465			else if (Opts.callback) {
14466				_warn('callback is deprecated, use success, instead');
14467
14468				// Success callback
14469				Opts.callback(this);
14470			}
14471		});
14472
14473		// Complete callback
14474		if (Opts.complete)
14475			Opts.complete(this);
14476
14477		_debug('[TextFill] End Debug');
14478		return this;
14479	};
14480
14481})(window.jQuery);
14482
14483
14484!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;
14485function getStyles(config){
14486  // 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;
14486left: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+"}"
14487};
14488  var ShareUtils;
14489
14490if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
14491  Object.defineProperty(HTMLElement.prototype, "classList", {
14492    get: function() {
14493      var ret, self, update;
14494      update = function(fn) {
14495        return function(value) {
14496          var classes, index;
14497          classes = self.className.split(/\s+/);
14498          index = classes.indexOf(value);
14499          fn(classes, index, value);
14500          self.className = classes.join(" ");
14501        };
14502      };
14503      self = this;
14504      ret = {
14505        add: update(function(classes, index, value) {
14506          ~index || classes.push(value);
14507        }),
14508        remove: update(function(classes, index) {
14509          ~index && classes.splice(index, 1);
14510        }),
14511        toggle: update(function(classes, index, value) {
14512          if (~index) {
14513            classes.splice(index, 1);
14514          } else {
14515            classes.push(value);
14516          }
14517        }),
14518        contains: function(value) {
14519          return !!~self.className.split(/\s+/).indexOf(value);
14520        },
14521        item: function(i) {
14522          return self.className.split(/\s+/)[i] || null;
14523        }
14524      };
14525      Object.defineProperty(ret, "length", {
14526        get: function() {
14527          return self.className.split(/\s+/).length;
14528        }
14529      });
14530      return ret;
14531    }
14532  });
14533}
14534
14535String.prototype.to_rfc3986 = function() {
14536  var tmp;
14537  tmp = encodeURIComponent(this);
14538  return tmp.replace(/[!'()*]/g, function(c) {
14539    return "%" + c.charCodeAt(0).toString(16);
14540  });
14541};
14542
14543ShareUtils = (function() {
14544  function ShareUtils() {}
14545
14546  ShareUtils.prototype.extend = function(to, from, overwrite) {
14547    var hasProp, prop;
14548    for (prop in from) {
14549      hasProp = to[prop] !== undefined;
14550      if (hasProp && typeof from[prop] === "object") {
14551        this.extend(to[prop], from[prop], overwrite);
14552      } else {
14553        if (overwrite || !hasProp) {
14554          to[prop] = from[prop];
14555        }
14556      }
14557    }
14558  };
14559
14560  ShareUtils.prototype.hide = function(el) {
14561    return el.style.display = "none";
14562  };
14563
14564  ShareUtils.prototype.show = function(el) {
14565    return el.style.display = "block";
14566  };
14567
14568  ShareUtils.prototype.has_class = function(el, class_name) {
14569    return el.classList.contains(class_name);
14570  };
14571
14572  ShareUtils.prototype.add_class = function(el, class_name) {
14573    return el.classList.add(class_name);
14574  };
14575
14576  ShareUtils.prototype.remove_class = function(el, class_name) {
14577    return el.classList.remove(class_name);
14578  };
14579
14580  ShareUtils.prototype.is_encoded = function(str) {
14581    str = str.to_rfc3986();
14582    return decodeURIComponent(str) !== str;
14583  };
14584
14585  ShareUtils.prototype.encode = function(str) {
14586    if (typeof str === "undefined" || this.is_encoded(str)) {
14587      return str;
14588    } else {
14589      return str.to_rfc3986();
14590    }
14591  };
14592
14593  ShareUtils.prototype.popup = function(url, params) {
14594    var k, popup, qs, v;
14595    if (params == null) {
14596      params = {};
14597    }
14598    popup = {
14599      width: 500,
14600      height: 350
14601    };
14602    popup.top = (screen.height / 2) - (popup.height / 2);
14603    popup.left = (screen.width / 2) - (popup.width / 2);
14604    qs = ((function() {
14605      var _results;
14606      _results = [];
14607      for (k in params) {
14608        v = params[k];
14609        _results.push("" + k + "=" + (this.encode(v)));
14610      }
14611      return _results;
14612    }).call(this)).join('&');
14613    if (qs) {
14614      qs = "?" + qs;
14615    }
14616    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=" 
14616+ popup.width + ",height=" + popup.height);
14617  };
14618
14619  return ShareUtils;
14620
14621})();
14622var Share,
14623  __hasProp = {}.hasOwnProperty,
14624  __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; };
14625
14626Share = (function(_super) {
14627  __extends(Share, _super);
14628
14629  function Share(element, options) {
14630    this.element = element;
14631    this.el = {
14632      head: document.getElementsByTagName('head')[0],
14633      body: document.getElementsByTagName('body')[0]
14634    };
14635    this.config = {
14636      enabled_networks: 0,
14637      protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
14638      url: window.location.href.replace("&", "%26"),
14639      caption: null,
14640      title: this.default_title(),
14641      image: this.default_image(),
14642      description: this.default_description(),
14643      ui: {
14644        flyout: 'top center',
14645        button_text: 'Share',
14646        button_font: true,
14647        icon_font: true
14648      },
14649      networks: {
14650        google_plus: {
14651          enabled: true,
14652          url: null
14653        },
14654        twitter: {
14655          enabled: true,
14656          url: null,
14657          title: null,
14658          description: null
14659        },
14660        facebook: {
14661          enabled: true,
14662          load_sdk: true,
14663          url: null,
14664          app_id: null,
14665          title: null,
14666          caption: null,
14667          description: null,
14668          image: null
14669        },
14670        pinterest: {
14671          enabled: true,
14672          url: null,
14673          image: null,
14674          description: null
14675        },
14676        reddit: {
14677          enabled: true,
14678          url: null,
14679          title: null
14680        },
14681        linkedin: {
14682          enabled: true,
14683          url: null,
14684          title: null,
14685          description: null
14686        },
14687        xing: {
14688          enabled: true,
14689          url: null,
14690          title: null,
14691          image: null,
14692          description: null
14693        },
14694        whatsapp: {
14695          enabled: true,
14696          description: null,
14697          url: null
14698        },
14699        email: {
14700          enabled: true,
14701          title: null,
14702          description: null,
14703          url: null
14704        }
14705      }
14706    };
14707    this.setup(element, options);
14708    return this;
14709  }
14710
14711  Share.prototype.setup = function(element, opts) {
14712    var index, instance, instances, _i, _len;
14713    instances = document.querySelectorAll(element);
14714    this.extend(this.config, opts, true);
14715    this.set_global_configuration();
14716    this.normalize_network_configuration();
14717    if (this.config.ui.icon_font) {
14718      this.inject_icons();
14719    }
14720    if (this.config.ui.button_font) {
14721      this.inject_fonts();
14722    }
14723    if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
14724      this.inject_facebook_sdk();
14725    }
14726    for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
14727      instance = instances[index];
14728      this.setup_instance(element, index);
14729    }
14730  };
14731
14732  Share.prototype.setup_instance = function(element, index) {
14733    var button, instance, label, network, networks, _i, _len, _results,
14734      _this = this;
14735    instance = document.querySelectorAll(element)[index];
14736    this.hide(instance);
14737    this.add_class(instance, "sharer-" + index);
14738    instance = document.querySelectorAll(element)[index];
14739    this.inject_css(instance);
14740    this.inject_html(instance);
14741    this.show(instance);
14742    label = instance.getElementsByTagName("label")[0];
14743    button = instance.getElementsByClassName("social")[0];
14744    networks = instance.getElementsByTagName('li');
14745    this.add_class(button, "networks-" + this.config.enabled_networks);
14746    label.addEventListener("click", function() {
14747      return _this.event_toggle(button);
14748    });
14749    _this = this;
14750    _results = [];
14751    for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
14752      network = networks[index];
14753      _results.push(network.addEventListener("click", function() {
14754        _this.event_network(instance, this);
14755        return _this.event_close(button);
14756      }));
14757    }
14758    return _results;
14759  };
14760
14761  Share.prototype.event_toggle = function(button) {
14762    if (this.has_class(button, "active")) {
14763      return this.event_close(button);
14764    } else {
14765      return this.event_open(button);
14766    }
14767  };
14768
14769  Share.prototype.event_open = function(button) {
14770    if (this.has_class(button, "load")) {
14771      this.remove_class(button, "load");
14772    }
14773    return this.add_class(button, "active");
14774  };
14775
14776  Share.prototype.event_close = function(button) {
14777    return this.remove_class(button, "active");
14778  };
14779
14780  Share.prototype.event_network = function(instance, network) {
14781    var name;
14782    name = network.getAttribute("data-network");
14783    this.hook("before", name, instance);
14784    this["network_" + name]();
14785    return this.hook("after", name, instance);
14786  };
14787
14788  Share.prototype.open = function() {
14789    return this["public"]("open");
14790  };
14791
14792  Share.prototype.close = function() {
14793    return this["public"]("close");
14794  };
14795
14796  Share.prototype.toggle = function() {
14797    return this["public"]("toggle");
14798  };
14799
14800  Share.prototype["public"] = function(action) {
14801    var button, index, instance, _i, _len, _ref, _results;
14802    _ref = document.querySelectorAll(this.element);
14803    _results = [];
14804    for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
14805      instance = _ref[index];
14806      button = instance.getElementsByClassName("social")[0];
14807      _results.push(this["event_" + action](button));
14808    }
14809    return _results;
14810  };
14811
14812  Share.prototype.network_facebook = function() {
14813    if (this.config.networks.facebook.load_sdk) {
14814      if (!window.FB) {
14815        return console.error("The Facebook JS SDK hasn't loaded yet.");
14816      }
14817      return FB.ui({
14818        method: 'feed',
14819        name: this.config.networks.facebook.title,
14820        link: this.config.networks.facebook.url,
14821        picture: this.config.networks.facebook.image,
14822        caption: this.config.networks.facebook.caption,
14823        description: this.config.networks.facebook.description
14824      });
14825    } else {
14826      return this.popup('https://www.facebook.com/sharer/sharer.php', {
14827        u: this.config.networks.facebook.url
14828      });
14829    }
14830  };
14831
14832  Share.prototype.network_twitter = function() {
14833    return this.popup('https://twitter.com/intent/tweet', {
14834      text: this.config.networks.twitter.title,
14835      url: this.config.networks.twitter.url
14836    });
14837  };
14838
14839  Share.prototype.network_google_plus = function() {
14840    return this.popup('https://plus.google.com/share', {
14841      url: this.config.networks.google_plus.url
14842    });
14843  };
14844
14845  Share.prototype.network_pinterest = function() {
14846    return this.popup('https://www.pinterest.com/pin/create/button', {
14847      url: this.config.networks.pinterest.url,
14848      media: this.config.networks.pinterest.image,
14849      description: this.config.networks.pinterest.description
14850    });
14851  };
14852
14853  Share.prototype.network_linkedin = function() {
14854    return this.popup('https://www.linkedin.com/shareArticle', {
14855      url: this.config.networks.linkedin.url,
14856      title: this.config.networks.linkedin.title,
14857      summary: this.config.networks.linkedin.description
14858    });
14859  }
14860
14861  Share.prototype.network_xing = function() {
14862    return this.popup('https://www.xing.com/spi/shares/new', {
14863      url: this.config.networks.xing.url,
14864      image: this.config.networks.xing.image,
14865      title: this.config.networks.xing.title,
14866      summary: this.config.networks.xing.description
14867    });
14868  }
14869
14870  Share.prototype.network_email = function() {
14871    return this.popup('mailto:', {
14872      subject: this.config.networks.email.title,
14873      body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
14874    });
14875  };
14876
14877  Share.prototype.inject_icons = function() {
14878  //  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
14879  };
14880
14881  Share.prototype.inject_fonts = function() {
14882   // return this.inject_stylesheet("https://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
14883  };
14884
14885  Share.prototype.inject_stylesheet = function(url) {
14886    var link;
14887    if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
14888      link = document.createElement("link");
14889      link.setAttribute("rel", "stylesheet");
14890      link.setAttribute("href", url);
14891      return this.el.head.appendChild(link);
14892    }
14893  };
14894
14895  Share.prototype.inject_css = function(instance) {
14896    var css, meta, selector, style;
14897    selector = "." + (instance.getAttribute('class').split(" ").join("."));
14898    if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
14899      this.config.selector = selector;
14900      css = getStyles(this.config);
14901      style = document.createElement("style");
14902      style.type = "text/css";
14903      if (style.styleSheet) {
14904        style.styleSheet.cssText = css;
14905      } else {
14906        style.appendChild(document.createTextNode(css));
14907      }
14908      this.el.head.appendChild(style);
14909      delete this.config.selector;
14910      meta = document.createElement("meta");
14911      meta.setAttribute("name", "sharer" + selector);
14912      return this.el.head.appendChild(meta);
14913    }
14914  };
14915
14916  Share.prototype.inject_html = function(instance) {
14917    //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>";
14918    return instance.innerHTML = "<label class='social-export'><span>" + this.config.ui.button_text + "</span></label><div class='social load " + this.config.ui.flyout + "'><ul><li class='social-facebook' data-network='facebook' tabindex='0'></li><li class='social-twitter' data-network='twitter' tabindex='0'></li><li class='social-pinterest' data-network='pinterest' tabindex='0'></li><li class='social-linkedin' data-network='linkedin' tabindex='0'></li><li class='social-xing' data-network='xing' tabindex='0'></li><li class='social-paper-plane' data-network='email' tabindex='0'></li></ul></div>";
14919  };
14920
14921  Share.prototype.inject_facebook_sdk = function() {
14922    var fb_root, script;
14923    if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
14924      script = document.createElement("script");
14925      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')";
14926      fb_root = document.createElement("div");
14927      fb_root.id = "fb-root";
14928      this.el.body.appendChild(fb_root);
14929      return this.el.body.appendChild(script);
14930    }
14931  };
14932
14933  Share.prototype.hook = function(type, network, instance) {
14934    var fn, opts;
14935    fn = this.config.networks[network][type];
14936    if (typeof fn === "function") {
14937      opts = fn.call(this.config.networks[network], instance);
14938      if (opts !== void 0) {
14939        opts = this.normalize_filter_config_updates(opts);
14940        this.extend(this.config.networks[network], opts, true);
14941        this.normalize_network_configuration();
14942      }
14943    }
14944  };
14945
14946  Share.prototype.default_title = function() {
14947    var content;
14948    if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
14949      return encodeURIComponent(content.getAttribute('content'));
14950    } else if (content = document.querySelector('title')) {
14951      return encodeURIComponent(content.innerText);
14952    }
14953  };
14954
14955  Share.prototype.default_image = function() {
14956    var content;
14957    if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
14958      return content.getAttribute('content');
14959    }
14960  };
14961
14962  Share.prototype.default_description = function() {
14963    var content;
14964    if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
14965      return encodeURIComponent(content.getAttribute('content'));
14966    } else {
14967      return '';
14968    }
14969  };
14970
14971  Share.prototype.set_global_configuration = function() {
14972    var display, network, option, options, _ref, _results;
14973    _ref = this.config.networks;
14974    _results = [];
14975    for (network in _ref) {
14976      options = _ref[network];
14977      for (option in options) {
14978        if (this.config.networks[network][option] == null) {
14979          this.config.networks[network][option] = this.config[option];
14980        }
14981      }
14982      if (this.config.networks[network].enabled) {
14983        display = 'block';
14984        this.config.enabled_networks += 1;
14985      } else {
14986        display = 'none';
14987      }
14988      _results.push(this.config.networks[network].display = display);
14989    }
14990    return _results;
14991  };
14992
14993  Share.prototype.normalize_network_configuration = function() {
14994    if (!this.config.networks.facebook.app_id) {
14995      this.config.networks.facebook.load_sdk = false;
14996    }
14997    if (!this.is_encoded(this.config.networks.twitter.description)) {
14998      this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
14999    }
15000    if (typeof this.config.networks.facebook.app_id === 'number') {
15001      return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
15002    }
15003  };
15004
15005  Share.prototype.normalize_filter_config_updates = function(opts) {
15006    if (this.config.networks.facebook.app_id !== opts.app_id) {
15007      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.");
15008      delete opts.app_id;
15009    }
15010    if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
15011      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.");
15012      delete opts.app_id;
15013    }
15014    return opts;
15015  };
15016
15017  return Share;
15018
15019})(ShareUtils);
15020 return Share;
15021});
15022
15023
15024// Generated by CoffeeScript 1.9.2
15025
15026// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
15027
15028(function() {
15029  var $, win;
15030
15031  $ = this.jQuery || window.jQuery;
15032
15033  win = $(window);
15034
15035  $.fn.stick_in_parent = function(opts) {
15036    var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
15037    if (opts == null) {
15038      opts = {};
15039    }
15040    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;
15041    if (offset_top == null) {
15042      offset_top = 0;
15043    }
15044    if (parent_selector == null) {
15045      parent_selector = void 0;
15046    }
15047    if (inner_scrolling == null) {
15048      inner_scrolling = true;
15049    }
15050    if (sticky_class == null) {
15051      sticky_class = "is_stuck";
15052    }
15053    doc = $(document);
15054    if (enable_bottoming == null) {
15055      enable_bottoming = true;
15056    }
15057    outer_width = function(el) {
15058      var _el, computed, w;
15059      if (window.getComputedStyle) {
15060        _el = el[0];
15061        computed = window.getComputedStyle(el[0]);
15062        w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
15063        if (computed.getPropertyValue("box-sizing") !== "border-box") {
15064          w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
15065        }
15066        return w;
15067      } else {
15068        return el.outerWidth(true);
15069      }
15070    };
15071    fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
15072      var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
15073      if (elm.data("sticky_kit")) {
15074        return;
15075      }
15076      elm.data("sticky_kit", true);
15077      last_scroll_height = doc.height();
15078      parent = elm.parent();
15079      if (parent_selector != null) {
15080        parent = parent.closest(parent_selector);
15081      }
15082      if (!parent.length) {
15083        throw "failed to find stick parent";
15084      }
15085      fixed = false;
15086      bottomed = false;
15087      spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
15088      if (spacer) {
15089        spacer.css('position', elm.css('position'));
15090      }
15091      recalc = function() {
15092        var border_top, padding_top, restore;
15093        if (detached) {
15094          return;
15095        }
15096        last_scroll_height = doc.height();
15097        border_top = parseInt(parent.css("border-top-width"), 10);
15098        padding_top = parseInt(parent.css("padding-top"), 10);
15099        padding_bottom = parseInt(parent.css("padding-bottom"), 10);
15100        parent_top = parent.offset().top + border_top + padding_top;
15101        parent_height = parent.height();
15102        if (fixed) {
15103          fixed = false;
vendor: 6,069 bytes, lines 15104-15299
15104          bottomed = false;
15105          if (manual_spacer == null) {
15106            elm.insertAfter(spacer);
15107            spacer.detach();
15108          }
15109          elm.css({
15110            position: "",
15111            top: "",
15112            width: "",
15113            bottom: ""
15114          }).removeClass(sticky_class);
15115          restore = true;
15116        }
15117        top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
15118        height = elm.outerHeight(true);
15119        el_float = elm.css("float");
15120        if (spacer) {
15121          spacer.css({
15122            width: outer_width(elm),
15123            height: height,
15124            display: elm.css("display"),
15125            "vertical-align": elm.css("vertical-align"),
15126            "float": el_float
15127          });
15128        }
15129        if (restore) {
15130          return tick();
15131        }
15132      };
15133      recalc();
15134      if (height === parent_height) {
15135        return;
15136      }
15137      last_pos = void 0;
15138      offset = offset_top;
15139      recalc_counter = recalc_every;
15140      tick = function() {
15141        var css, delta, recalced, scroll, will_bottom, win_height;
15142        if (detached) {
15143          return;
15144        }
15145        recalced = false;
15146        if (recalc_counter != null) {
15147          recalc_counter -= 1;
15148          if (recalc_counter <= 0) {
15149            recalc_counter = recalc_every;
15150            recalc();
15151            recalced = true;
15152          }
15153        }
15154        if (!recalced && doc.height() !== last_scroll_height) {
15155          recalc();
15156          recalced = true;
15157        }
15158        scroll = win.scrollTop();
15159        if (last_pos != null) {
15160          delta = scroll - last_pos;
15161        }
15162        last_pos = scroll;
15163        if (fixed) {
15164          if (enable_bottoming) {
15165            will_bottom = scroll + height + offset > parent_height + parent_top;
15166            if (bottomed && !will_bottom) {
15167              bottomed = false;
15168              elm.css({
15169                position: "fixed",
15170                bottom: "",
15171                top: offset
15172              }).trigger("sticky_kit:unbottom");
15173            }
15174          }
15175          if (scroll < top) {
15176            fixed = false;
15177            offset = offset_top;
15178            if (manual_spacer == null) {
15179              if (el_float === "left" || el_float === "right") {
15180                elm.insertAfter(spacer);
15181              }
15182              spacer.detach();
15183            }
15184            css = {
15185              position: "",
15186              width: "",
15187              top: ""
15188            };
15189            elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
15190          }
15191          if (inner_scrolling) {
15192            win_height = win.height();
15193            if (height + offset_top > win_height) {
15194              if (!bottomed) {
15195                offset -= delta;
15196                offset = Math.max(win_height - height, offset);
15197                offset = Math.min(offset_top, offset);
15198                if (fixed) {
15199                  elm.css({
15200                    top: offset + "px"
15201                  });
15202                }
15203              }
15204            }
15205          }
15206        } else {
15207          if (scroll > top) {
15208            fixed = true;
15209            css = {
15210              position: "fixed",
15211              top: offset
15212            };
15213            css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
15214            elm.css(css).addClass(sticky_class);
15215            if (manual_spacer == null) {
15216              elm.after(spacer);
15217              if (el_float === "left" || el_float === "right") {
15218                spacer.append(elm);
15219              }
15220            }
15221            elm.trigger("sticky_kit:stick");
15222          }
15223        }
15224        if (fixed && enable_bottoming) {
15225          if (will_bottom == null) {
15226            will_bottom = scroll + height + offset > parent_height + parent_top;
15227          }
15228          if (!bottomed && will_bottom) {
15229            bottomed = true;
15230            if (parent.css("position") === "static") {
15231              parent.css({
15232                position: "relative"
15233              });
15234            }
15235            return elm.css({
15236              position: "absolute",
15237              bottom: padding_bottom,
15238              top: "auto"
15239            }).trigger("sticky_kit:bottom");
15240          }
15241        }
15242      };
15243      recalc_and_tick = function() {
15244        recalc();
15245        return tick();
15246      };
15247      detach = function() {
15248        detached = true;
15249        win.off("touchmove", tick);
15250        win.off("scroll", tick);
15251        win.off("resize", recalc_and_tick);
15252        $(document.body).off("sticky_kit:recalc", recalc_and_tick);
15253        elm.off("sticky_kit:detach", detach);
15254        elm.removeData("sticky_kit");
15255        elm.css({
15256          position: "",
15257          bottom: "",
15258          top: "",
15259          width: ""
15260        });
15261        parent.position("position", "");
15262        if (fixed) {
15263          if (manual_spacer == null) {
15264            if (el_float === "left" || el_float === "right") {
15265              elm.insertAfter(spacer);
15266            }
15267            spacer.remove();
15268          }
15269          return elm.removeClass(sticky_class);
15270        }
15271      };
15272      win.on("touchmove", tick);
15273      win.on("scroll", tick);
15274      win.on("resize", recalc_and_tick);
15275      $(document.body).on("sticky_kit:recalc", recalc_and_tick);
15276      elm.on("sticky_kit:detach", detach);
15277      return setTimeout(tick, 0);
15278    };
15279    for (i = 0, len = this.length; i < len; i++) {
15280      elm = this[i];
15281      fn($(elm));
15282    }
15283    return this;
15284  };
15285
15286}).call(this);
15287
15288/* ==========================================================================
15289 * bootstrap-tab-history.js
15290 * Author: Michael Narayan <[email protected]>
15291 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
15292 * ==========================================================================
15293 * Licensed under the Apache License, Version 2.0 (the "License"); you may
15294 * not use this file except in compliance with the License. You may obtain a
15295 * copy of the License at
15296 *
15297 * http://www.apache.org/licenses/LICENSE-2.0
15298 *
15299 * Unless required by applicable law or agreed to in writing, softw
15299are
15300 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15301 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15302 * License for the specific language governing permissions and limitations
15303 * under the License.
15304 * ========================================================================== */
15305
15306/* ========================================================================== */
15307/* JSHint directives                                                          */
15308/*                                                                            */
15309/* global BootstrapTabHistory: true                                           */
15310/*                                                                            */
15311/* global document                                                            */
15312/* global jQuery                                                              */
15313/* global history                                                             */
15314/* global window                                                              */
15315/* ========================================================================== */
15316
15317/**
15318 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
15319 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
15320 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
15321 *
15322 * See the README for additional information.
15323 *
15324 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
15325 */
15326
15327BootstrapTabHistory = {
15328  options: {
15329    /**
15330     * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
15331     * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
15332     *
15333     * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
15334     *
15335     * @public
15336     * @type {?number}
15337     */
15338    defaultAnchorYOffset: 0,
15339    /**
15340     * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
15341     *
15342     * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
15343     *
15344     * @public
15345     * @type {string}
15346     */
15347    defaultChanger: 'replace',
15348    /**
15349     * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
15350     * `null` is passed as the third parameter to these calls.
15351     *
15352     * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
15353     *
15354     * @public
15355     * @type {boolean}
15356     */
15357    defaultUpdateURL: false,
15358    /**
15359     * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
15360     * load.
15361     *
15362     * @public
15363     * @type {boolean}
15364     */
15365    showTabsBasedOnAnchor: true
15366  }
15367};
15368
15369(function () {
15370  'use strict';
15371
15372  jQuery(function () {
15373    if(history && history.pushState && history.replaceState) {
15374      var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
15375
15376      if(bootstrapTabHistory) {
15377        showTabsBasedOnState(bootstrapTabHistory);
15378      } else {
15379        showTabsBasedOnAnchor();
15380      }
15381
15382      backfillHistoryState();
15383
15384      jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
15385      jQuery(window).on('popstate', onPopState);
15386    } else {
15387      showTabsBasedOnAnchor();
15388    }
15389  });
15390
15391  /**
15392   * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
15393   *
15394   * @type {boolean}
15395   */
15396  var showingTabsBasedOnState = false;
15397
15398  /**
15399   * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
15400   * `history.back` handling when `data-tab-history-update-url` is true.
15401   */
15402  function backfillHistoryState() {
15403    var newState = null;
15404
15405    jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
15406      var $activeTabElement = jQuery(this);
15407      var selector = getTabSelector($activeTabElement);
15408
15409      if(selector) {
15410        var tabGroup = getTabGroup($activeTabElement);
15411
15412        if(tabGroup) {
15413          newState = createNewHistoryState(newState || history.state, tabGroup, selector);
15414        }
15415      }
15416    });
15417
15418    if(newState) {
15419      history.replaceState(newState, '', null);
15420    }
15421  }
15422
15423  /**
15424   * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
15425   * said bootstrapTabHistory attribute.
15426   *
15427   * @param {?object} existingState
15428   * @param {!string} tabGroup
15429   * @param {!string} selector
15430   * @returns {!object}
15431   */
15432  function createNewHistoryState(existingState, tabGroup, selector) {
15433    // Clone history.state and ensure it has a bootstrapTabHistory entry.
15434    var newState = jQuery.extend(true, {}, existingState, {
15435      bootstrapTabHistory: {}
15436    });
15437
15438    newState.bootstrapTabHistory[tabGroup] = selector;
15439
15440    return newState;
15441  }
15442
15443  /**
15444   * @param {jQuery} $tab
15445   * @returns {?string}
15446   */
15447  function getTabGroup($tab) {
15448    return parseTruthyAttributeValue($tab.data('tab-history'));
15449  }
15450
15451  /**
15452   * @param {jQuery} $tab
15453   * @returns {?string}
15454   */
15455  function getTabSelector($tab) {
15456    return $tab.data('target') || $tab.attr('href');
15457  }
15458
15459  /**
15460   * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
15461   *
15462   * @param {jQuery.Event} shownEvt
15463   */
15464  function onShownTab(shownEvt) {
15465    if(!showingTabsBasedOnState) {
15466      var $activatedTab = jQuery(shownEvt.target);
15467      if ( $activatedTab.hasClass('panel-collapse') )
15468        $activatedTab = $activatedTab.closest('.panel').find('a');
15469      var selector = getTabSelector($activatedTab);
15470
15471      if(selector) {
15472        var tabGroup = getTabGroup($activatedTab);
15473
15474        if(tabGroup) {
15475          var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
15476          var newState = createNewHistoryState(history.state, tabGroup, selector);
15477          var updateURL = (function ($activatedTab) {
15478            if(selector[0] === '#') {
15479              var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
15480
15481              if(elementUpdateURLOption === undefined) {
15482                return BootstrapTabHistory.options.defaultUpdateURL;
15483              } else {
15484                return elementUpdateURLOption;
15485              }
15486            } else {
15487              return false;
15488            }
15489          })($activatedTab);
15490
15491          switch(historyChanger) {
15492            case 'push':
15493              history.pushState(newState, '', updateURL ? selector : null);
15494              break;
15495            case 'replace':
15496              history.replaceState(newState, '', updateURL ? selector : null);
15497              break;
15498            default:
15499              throw new Error('Unknown tab-history-changer: ' + historyChanger);
15500          }
15501        }
15502      }
15503    }
15504  }
15505
15506  /**
15507   * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
15508   */
15509  function onPopState() {
15510    var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
15511
15512    if(bootstrapTabHistory) {
15513      showTabsBasedOnState(bootstrapTabHistory);
15514    }
15515  }
15516
15517  /**
15518   * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
15519   *
15520   * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
15521   *
15522   * @param {*} value
15523   * @returns {*}
15524   */
15525  function parseTruthyAttributeValue(value) {
15526    if(value) {
15527      return value;
15528    } else if(value === '') {
15529      return true;
15530    } else {
15531      return value;
15532    }
15533  }
15534
15535  /**
15536   * Show tabs based upon the anchor component of `window.location`.
15537   */
15538  function showTabsBasedOnAnchor() {
15539    if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
15540      var anchor = window.location && window.location.hash;
15541
15542      if(anchor) {
15543        var $tabElement = showTabForSelector(anchor);
15544
15545        if($tabElement && window.addEventListener && window.removeEventListener) {
15546          var anchorYOffset = (function ($tabElement) {
15547            var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
15548
15549            if(elementSetting === undefined) {
15550              return BootstrapTabHistory.options.defaultAnchorYOffset;
15551            } else {
15552              return elementSetting;
15553            }
15554          })($tabElement);
15555
15556          // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
15557          //   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
15558          //   `history.state` object should have been used (unless the browser did not support the modern History API).
15559          if(anchorYOffset || anchorYOffset === 0) {
15560            var scrollListener = function resetAnchorScroll () {
15561              window.removeEventListener('scroll', scrollListener);
15562              window.scrollTo(0, anchorYOffset);
15563            };
15564
15565            window.addEventListener('scroll', scrollListener);
15566          }
15567        }
15568      }
15569    }
15570  }
15571
15572  /**
15573   * Show a tab which corresponds to the provided selector.
15574   *
15575   * @param {string} selector - A CSS selector.
15576   * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
15577   */
15578  function showTabForSelector(selector) {
15579    var $tabElement = (function (selector) {
15580      var $ret = null;
15581
15582      jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
15583        var $potentialTab = jQuery(this);
15584
15585        if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
15586          $ret = $potentialTab;
15587          return false;
vendor: 4,523 bytes, lines 15588-15738
15588        } else {
15589         return null;
15590        }
15591      });
15592
15593      return $ret;
15594    })(selector);
15595
15596    if($tabElement) {
15597      $tabElement.trigger('click');
15598      //$tabElement.tab('show');
15599    }
15600
15601    return $tabElement;
15602  }
15603
15604  /**
15605   * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
15606   *
15607   * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
15608   */
15609  function showTabsBasedOnState(bootstrapTabHistory) {
15610    showingTabsBasedOnState = true;
15611
15612    try {
15613      for(var k in bootstrapTabHistory) {
15614        if(bootstrapTabHistory.hasOwnProperty(k)) {
15615          showTabForSelector(bootstrapTabHistory[k]);
15616        }
15617      }
15618    } finally {
15619      showingTabsBasedOnState = false;
15620    }
15621  }
15622})();
15623
15624
15625/*!
15626 * Justified Gallery - v3.6.3
15627 * http://miromannino.github.io/Justified-Gallery/
15628 * Copyright (c) 2016 Miro Mannino
15629 * Licensed under the MIT license.
15630 */
15631(function($) {
15632
15633  function hasScrollBar() {
15634    return $("body").height() > $(window).height();
15635  }
15636  /**
15637   * Justified Gallery controller constructor
15638   *
15639   * @param $gallery the gallery to build
15640   * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults)
15641   * @constructor
15642   */
15643  var JustifiedGallery = function ($gallery, settings) {
15644    
15645    this.settings = settings;
15646    this.checkSettings();
15647
15648    this.imgAnalyzerTimeout = null;
15649    this.entries = null;
15650    this.buildingRow = {
15651      entriesBuff : [],
15652      width : 0,
15653      height : 0,
15654      aspectRatio : 0
15655    };
15656    this.lastFetchedEntry = null;
15657    this.lastAnalyzedIndex = -1;
15658    this.yield = {
15659      every : 2, // do a flush every n flushes (must be greater than 1)
15660      flushed : 0 // flushed rows without a yield
15661    };
15662    this.border = settings.border >= 0 ? settings.border : settings.margins;
15663    this.maxRowHeight = this.retrieveMaxRowHeight();
15664    this.suffixRanges = this.retrieveSuffixRanges();
15665    this.offY = this.border;
15666    this.rows = 0;
15667    this.spinner = {
15668      phase : 0,
15669      timeSlot : 150,
15670      $el : $('<div class="spinner"><span></span><span></span><span></span></div>'),
15671      intervalId : null
15672    };
15673    this.checkWidthIntervalId = null;
15674    this.galleryWidth = $gallery.width();
15675    this.$gallery = $gallery;
15676
15677  };
15678
15679  /** @returns {String} the best suffix given the width and the height */
15680  JustifiedGallery.prototype.getSuffix = function (width, height) {
15681    var longestSide, i;
15682    longestSide = (width > height) ? width : height;
15683    for (i = 0; i < this.suffixRanges.length; i++) {
15684      if (longestSide <= this.suffixRanges[i]) {
15685        return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
15686      }
15687    }
15688    return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
15689  };
15690
15691  /**
15692   * Remove the suffix from the string
15693   *
15694   * @returns {string} a new string without the suffix
15695   */
15696  JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
15697    return str.substring(0, str.length - suffix.length);
15698  };
15699
15700  /**
15701   * @returns {boolean} a boolean to say if the suffix is contained in the str or not
15702   */
15703  JustifiedGallery.prototype.endsWith = function (str, suffix) {
15704    return str.indexOf(suffix, str.length - suffix.length) !== -1;
15705  };
15706
15707  /**
15708   * Get the used suffix of a particular url
15709   *
15710   * @param str
15711   * @returns {String} return the used suffix
15712   */
15713  JustifiedGallery.prototype.getUsedSuffix = function (str) {
15714    for (var si in this.settings.sizeRangeSuffixes) {
15715      if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
15716        if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
15717        if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
15718      }
15719    }
15720    return '';
15721  };
15722
15723  /**
15724   * Given an image src, with the width and the height, returns the new image src with the
15725   * best suffix to show the best quality thumbnail.
15726   *
15727   * @returns {String} the suffix to use
15728   */
15729  JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
15730    var newImageSrc;
15731
15732    if (this.settings.thumbnailPath) {
15733      newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
15734    } else {
15735      var matchRes = imageSrc.match(this.settings.extension);
15736      var ext = (matchRes !== null) ? matchRes[0] : '';
15737      newImageSrc = imageSrc.replace(this.settings.extension, '');
15738      newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
15739      newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
15740    }
15741
15742    return newImageSrc;
15743  };
15744
15745  /**
15746   * Shows the images that is in the given entry
15747   *
15748   * @param $entry the entry
15749   * @param callback the callback that is called when the show animation is finished
15750   */
15751  JustifiedGallery.prototype.showImg = function ($entry, callback) {
15752    if (this.settings.cssAnimation) {
15753      $entry.addClass('entry-visible');
15754      if (callback) callback();
15755    } else {
15756      $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
15757      $entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
15758    }
15759  };
15760
15761  /**
15762   * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
15763   * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
15764   *
15765   * @param $image the image to analyze
15766   * @returns {String} the extracted src
15767   */
15768  JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
15769    var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src');
15770    $image.data('jg.originalSrc', imageSrc);
15771    return imageSrc;
15772  };
15773
15774  /** @returns {jQuery} the image in the given entry */
15775  JustifiedGallery.prototype.imgFromEntry = function ($entry) {
15776    var $img = $entry.find('> img');
15777    if ($img.length === 0) $img = $entry.find('> a > img');
15778    if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
15779    return $img.length === 0 ? null : $img;
15780  };
15781
15782  /** @returns {jQuery} the caption in the given entry */
15783  JustifiedGallery.prototype.captionFromEntry = function ($entry) {
15784    var $caption = $entry.find('> .caption');
15785    return $caption.length === 0 ? null : $caption;
15786  };
15787
15788  /**
15789   * Display the entry
15790   *
15791   * @param {jQuery} $entry the entry to display
15792   * @param {int} x the x position where the entry must be positioned
15793   * @param y the y position where the entry must be positioned
15794   * @param imgWidth the image width
15795   * @param imgHeight the image height
15796   * @param rowHeight the row height of the row that owns the entry
15797   */
15798  JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
15799    $entry.width(imgWidth);
15800    $entry.height(Math.floor(rowHeight));//hacked by Uncode
15801    $entry.css('top', Math.floor(y));//hacked by Uncode
15802    $entry.css('left', x);
15803
15804    var $image = this.imgFromEntry($entry);
15805    if ($image !== null) {
15806      $image.css('width', imgWidth);
15807      $image.css('height', imgHeight);
15808      $image.css('margin-left', - imgWidth / 2);
15809      $image.css('margin-top', - imgHeight / 2);
15810
15811      // Image reloading for an high quality of thumbnails
15812      var imageSrc = $image.attr('src');
15813      var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
15814
15815      $image.one('error', function () {
15816        $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it.
15817      });
15818
15819      var loadNewImage = function () {
15820        if (imageSrc !== newImageSrc) { //load the new image after the fadeIn
15821          $image.attr('src', newImageSrc);
15822        }
15823      };
15824
15825      if ($entry.data('jg.loaded') === 'skipped') {
15826        this.onImageEvent(imageSrc, $.proxy(function() {
15827          this.showImg($entry, loadNewImage);
15828          $entry.data('jg.loaded', true);
15829        }, this));
15830      } else {
15831        this.showImg($entry, loadNewImage);
15832      }
15833
15834    } else {
15835      this.showImg($entry);
15836    }
15837
15838    this.displayEntryCaption($entry);
15839  };
15840
15841  /**
15842   * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
15843   * or the 'title' attributes.
15844   *
15845   * @param {jQuery} $entry the entry to process
15846   */
15847  JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
15848    var $image = this.imgFromEntry($entry);
15849    if ($image !== null && this.settings.captions) {
15850      var $imgCaption = this.captionFromEntry($entry);
15851
15852      // Create it if it doesn't exists
15853      if ($imgCaption === null) {
15854        var caption = $image.attr('alt');
15855        if (!this.isValidCaption(caption)) caption = $entry.attr('title');
15856        if (this.isValidCaption(caption)) { // Create only we found something
15857          $imgCaption = $('<div class="caption">' + caption + '</div>');
15858          $entry.append($imgCaption);
15859          $entry.data('jg.createdCaption', true);
15860        }
15861      }
15862
15863      // Create events (we check again the $imgCaption because it can be still inexistent)
15864      if ($imgCaption !== null) {
15865        if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
15866        this.addCaptionEventsHandlers($entry);
15867      }
15868    } else {
15869      this.removeCaptionEventsHandlers($entry);
15870    }
15871  };
15872
15873  /**
15874   * Validates the caption
15875   *
15876   * @param caption The caption that should be validated
15877   * @return {boolean} Validation result
15878   */
15879  JustifiedGallery.prototype.isValidCaption = function (caption) {
15880    return (typeof caption !== 'undefined' && caption.length > 0);
15881  };
15882
15883  /**
15884   * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
15885   * It shows the caption using jQuery (or using CSS if it is configured so)
15886   *
15887   * @param {Event} eventObject the event object
15888   */
15889  JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
15890    var $caption = this.captionFromEntry($(eventObject.currentTarget));
15891    if (this.settings.cssAnimation) {
15892      $caption.addClass('caption-visible').removeClass('caption-hidden');
15893    } else {
15894      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
15895          this.settings.captionSettings.visibleOpacity);
15896    }
15897  };
15898
15899  /**
15900   * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
15901   * It hides the caption using jQuery (or using CSS if it is configured so)
15902   *
15903   * @param {Event} eventObject the event object
15904   */
15905  JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
15906    var $caption = this.captionFromEntry($(eventObject.currentTarget));
15907    if (this.settings.cssAnimation) {
15908      $caption.removeClass('caption-visible').removeClass('caption-hidden');
15909    } else {
15910      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
15911          this.settings.captionSettings.nonVisibleOpacity);
15912    }
15913  };
15914
15915  /**
15916   * Add the handlers of the entry for the caption
15917   *
15918   * @param $entry the entry to modify
15919   */
15920  JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
15921    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
15922    if (typeof captionMouseEvents === 'undefined') {
15923      captionMouseEvents = {
15924        mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
15925        mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
15926      };
15927      $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
15928      $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
15929      $entry.data('jg.captionMouseEvents', captionMouseEvents);
15930    }
15931  };
15932
15933  /**
15934   * Remove the handlers of the entry for the caption
15935   *
15936   * @param $entry the entry to modify
15937   */
15938  JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
15939    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
15940    if (typeof captionMouseEvents !== 'undefined') {
15941      $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
15942      $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
15943      $entry.removeData('jg.captionMouseEvents');
15944    }
15945  };
15946
15947  /**
15948   * Justify the building row, preparing it to
15949   *
15950   * @param isLastRow
15951   * @returns a boolean to know if the row has been justified or not
15952   */
15953  JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) {
15954    var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
15955    var minHeight = 0;
15956    var availableWidth = this.galleryWidth - 2 * this.border - (
15957        (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
15958    var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
15959    var defaultRowHeight = this.settings.rowHeight;
15960    var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
15961
15962    //Skip the last row if we can't justify it and the lastRow == 'hide'
15963    if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) {
15964      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
15965        $entry = this.buildingRow.entriesBuff[i];
15966        if (this.settings.cssAnimation)
15967          $entry.removeClass('entry-visible');
15968        else {
15969          $entry.stop().fadeTo(0, 0.1);
15970          $entry.find('> img, > a > img').fadeTo(0, 0);
15971        }
15972      }
15973      return -1;
15974    }
15975
15976    // With lastRow = nojustify, justify if is justificable (the images will not become too big)
15977    if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
15978      justify = false;
15979
15980      if (this.rows > 0) {
15981        defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
15982        justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
15983      }
15984    }
15985
15986    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
15987      $entry = this.buildingRow.entriesBuff[i];
15988      imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
15989
15990      if (justify) {
15991        newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
15992        newImgH = rowHeight;
15993      } else {
15994        newImgW = defaultRowHeight * imgAspectRatio;
15995        newImgH = defaultRowHeight;
15996      }
15997
15998      availableWidth -= Math.round(newImgW);
15999      $entry.data('jg.jwidth', Math.round(newImgW));
16000      $entry.data('jg.jheight', Math.ceil(newImgH));
16001      if (i === 0 || minHeight > newImgH) minHeight = newImgH;
16002    }
16003
16004    this.buildingRow.height = minHeight;
16005    return justify;
16006  };
16007
16008  /**
16009   * Clear the building row data to be used for a new row
16010   */
16011  JustifiedGallery.prototype.clearBuildingRow = function () {
16012    this.buildingRow.entriesBuff = [];
16013    this.buildingRow.aspectRatio = 0;
16014    this.buildingRow.width = 0;
16015  };
16016
16017  /**
16018   * Flush a row: justify it, modify the gallery height accordingly to the row height
16019   *
16020   * @param isLastRow
16021   */
16022  JustifiedGallery.prototype.flushRow = function (isLastRow) {
16023    var settings = this.settings;
16024    var $entry, buildingRowRes, offX = this.border, i;
16025
16026    buildingRowRes = this.prepareBuildingRow(isLastRow);
16027    if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) {
16028      this.clearBuildingRow();
16029      return;
16030    }
16031
16032    if (this.maxRowHeight) {
16033      if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) {
16034        this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight;
16035      } else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) {
16036        this.buildingRow.height = this.maxRowHeight.value;
16037      }
16038    }
16039
16040    //Align last (unjustified) row
16041    if (settings.lastRow === 'center' || settings.lastRow === 'right') {
16042      var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
16043
16044      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
16045        $entry = this.buildingRow.entriesBuff[i];
16046        availableWidth -= $entry.data('jg.jwidth');
16047      }
16048
16049      if (settings.lastRow === 'center')
16050        offX += availableWidth / 2;
16051      else if (settings.lastRow === 'right')
16052        offX += availableWidth;
16053    }
16054
16055    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
16056      $entry = this.buildingRow.entriesBuff[i];
16057      this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
16058      offX += $entry.data('jg.jwidth') + settings.margins;
16059    }
16060
16061    //Gallery Height
16062    this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
16063    this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight());
16064
16065    if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
16066      //Ready for a new row
16067      this.offY += this.buildingRow.height + settings.margins;
16068      this.rows += 1;
16069      this.clearBuildingRow();
16070      this.$gallery.trigger('jg.rowflush');
16071    }
16072  };
16073
16074  /**
16075   * Checks the width of the gallery container, to know if a new justification is needed
16076   */
16077  var scrollBarOn = false;
16078  JustifiedGallery.prototype.checkWidth = function () {
16079    this.checkWidthIntervalId = setInterval($.proxy(function () {
16080      var galleryWidth = parseFloat(this.$gallery.width());
16081      if (hasScrollBar() === scrollBarOn) {
16082        if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
16083          this.galleryWidth = galleryWidth;
16084          this.rewind();
16085
16086          // Restart to analyze
16087          this.startImgAnalyzer(true);
16088        }
16089      } else {
16090        scrollBarOn = hasScrollBar();
16091        this.galleryWidth = galleryWidth;
16092      }
16093    }, this), this.settings.refreshTime);
16094  };
16095
16096  /**
16097   * @returns {boolean} a boolean saying if the spinner is active or not
16098   */
16099  JustifiedGallery.prototype.isSpinnerActive = function () {
16100    return this.spinner.intervalId !== null;
16101  };
16102
16103  /**
16104   * @returns {int} the spinner height
16105   */
16106  JustifiedGallery.prototype.getSpinnerHeight = function () {
16107    return this.spinner.$el.innerHeight();
16108  };
16109
16110  /**
16111   * Stops the spinner animation and modify the gallery height to exclude the spinner
16112   */
16113  JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
16114    clearInterval(this.spinner.intervalId);
16115    this.spinner.intervalId = null;
16116    this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight());
16117    this.spinner.$el.detach();
16118  };
16119
16120  /**
16121   * Starts the spinner animation
16122   */
16123  JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
16124    var spinnerContext = this.spinner;
16125    var $spinnerPoints = spinnerContext.$el.find('span');
16126    clearInterval(spinnerContext.intervalId);
16127    this.$gallery.append(spinnerContext.$el);
16128    this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight());
16129    spinnerContext.intervalId = setInterval(function () {
16130      if (spinnerContext.phase < $spinnerPoints.length) {
16131        $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
16132      } else {
vendor: 4,333 bytes, lines 16133-16277
16133        $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
16134      }
16135      spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
16136    }, spinnerContext.timeSlot);
16137  };
16138
16139  /**
16140   * Rewind the image analysis to start from the first entry.
16141   */
16142  JustifiedGallery.prototype.rewind = function () {
16143    this.lastFetchedEntry = null;
16144    this.lastAnalyzedIndex = -1;
16145    this.offY = this.border;
16146    this.rows = 0;
16147    this.clearBuildingRow();
16148  };
16149
16150  /**
16151   * Update the entries searching it from the justified gallery HTML element
16152   *
16153   * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
16154   * @returns {boolean} true if some entries has been founded
16155   */
16156  JustifiedGallery.prototype.updateEntries = function (norewind) {
16157    var newEntries;
16158
16159    if (norewind && this.lastFetchedEntry != null) {
16160      newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray();
16161    } else {
16162      this.entries = [];
16163      newEntries = this.$gallery.children(this.settings.selector).toArray();
16164    }
16165
16166    if (newEntries.length > 0) {
16167
16168      // Sort or randomize
16169      if ($.isFunction(this.settings.sort)) {
16170        newEntries = this.sortArray(newEntries);
16171      } else if (this.settings.randomize) {
16172        newEntries = this.shuffleArray(newEntries);
16173      }
16174      this.lastFetchedEntry = newEntries[newEntries.length - 1];
16175
16176      // Filter
16177      if (this.settings.filter) {
16178        newEntries = this.filterArray(newEntries);
16179      } else {
16180        this.resetFilters(newEntries);
16181      }
16182
16183    }
16184
16185    this.entries = this.entries.concat(newEntries);
16186    return true;
16187  };
16188
16189  /**
16190   * Apply the entries order to the DOM, iterating the entries and appending the images
16191   *
16192   * @param entries the entries that has been modified and that must be re-ordered in the DOM
16193   */
16194  JustifiedGallery.prototype.insertToGallery = function (entries) {
16195    var that = this;
16196    $.each(entries, function () {
16197      $(this).appendTo(that.$gallery);
16198    });
16199  };
16200
16201  /**
16202   * Shuffle the array using the Fisher-Yates shuffle algorithm
16203   *
16204   * @param a the array to shuffle
16205   * @return the shuffled array
16206   */
16207  JustifiedGallery.prototype.shuffleArray = function (a) {
16208    var i, j, temp;
16209    for (i = a.length - 1; i > 0; i--) {
16210      j = Math.floor(Math.random() * (i + 1));
16211      temp = a[i];
16212      a[i] = a[j];
16213      a[j] = temp;
16214    }
16215    this.insertToGallery(a);
16216    return a;
16217  };
16218
16219  /**
16220   * Sort the array using settings.comparator as comparator
16221   *
16222   * @param a the array to sort (it is sorted)
16223   * @return the sorted array
16224   */
16225  JustifiedGallery.prototype.sortArray = function (a) {
16226    a.sort(this.settings.sort);
16227    this.insertToGallery(a);
16228    return a;
16229  };
16230
16231  /**
16232   * Reset the filters removing the 'jg-filtered' class from all the entries
16233   *
16234   * @param a the array to reset
16235   */
16236  JustifiedGallery.prototype.resetFilters = function (a) {
16237    for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
16238  };
16239
16240  /**
16241   * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
16242   *
16243   * @param a the array to filter
16244   * @return the filtered array
16245   */
16246  JustifiedGallery.prototype.filterArray = function (a) {
16247    var settings = this.settings;
16248    if ($.type(settings.filter) === 'string') {
16249      // Filter only keeping the entries passed in the string
16250      return a.filter(function (el) {
16251        var $el = $(el);
16252        if ($el.is(settings.filter)) {
16253          $el.removeClass('jg-filtered');
16254          return true;
16255        } else {
16256          $el.addClass('jg-filtered').removeClass('jg-visible');
16257          return false;
16258        }
16259      });
16260    } else if ($.isFunction(settings.filter)) {
16261      // Filter using the passed function
16262      var filteredArr = a.filter(settings.filter);
16263      for (var i = 0; i < a.length; i++) {
16264        if (filteredArr.indexOf(a[i]) == -1) {
16265          $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
16266        } else {
16267          $(a[i]).removeClass('jg-filtered');
16268        }
16269      }
16270      return filteredArr;
16271    }
16272  };
16273
16274  /**
16275   * Destroy the Justified Gallery instance.
16276   *
16277   * It clears all the css properties added in the style attributes. We doesn't backup the original
16278   * values for those css attributes, because it costs (performance) and because in general one
16279   * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
16280   * classes). Creating a backup is also difficult because JG could be called multiple times and
16281   * with different style attributes.
16282   */
16283  JustifiedGallery.prototype.destroy = function () {
16284    clearInterval(this.checkWidthIntervalId);
16285
16286    $.each(this.entries, $.proxy(function(_, entry) {
16287      var $entry = $(entry);
16288
16289      // Reset entry style
16290      $entry.css('width', '');
16291      $entry.css('height', '');
16292      $entry.css('top', '');
16293      $entry.css('left', '');
16294      $entry.data('jg.loaded', undefined);
16295      $entry.removeClass('jg-entry');
16296
16297      // Reset image style
16298      var $img = this.imgFromEntry($entry);
16299      $img.css('width', '');
16300      $img.css('height', '');
16301      $img.css('margin-left', '');
16302      $img.css('margin-top', '');
16303      $img.attr('src', $img.data('jg.originalSrc'));
16304      $img.data('jg.originalSrc', undefined);
16305
16306      // Remove caption
16307      this.removeCaptionEventsHandlers($entry);
16308      var $caption = this.captionFromEntry($entry);
16309      if ($entry.data('jg.createdCaption')) {
16310        // remove also the caption element (if created by jg)
16311        $entry.data('jg.createdCaption', undefined);
16312        if ($caption !== null) $caption.remove();
16313      } else {
16314        if ($caption !== null) $caption.fadeTo(0, 1);
16315      }
16316
16317    }, this));
16318
16319    this.$gallery.css('height', '');
16320    this.$gallery.removeClass('justified-gallery');
16321    this.$gallery.data('jg.controller', undefined);
16322  };
16323
16324  /**
16325   * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
16326   *
16327   * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
16328   */
16329  JustifiedGallery.prototype.analyzeImages = function (isForResize) {
16330    for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
16331      var $entry = $(this.entries[i]);
16332      if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
16333        var availableWidth = this.galleryWidth - 2 * this.border - (
16334            (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
16335        var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
16336        if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
16337          this.flushRow(false);
16338          if(++this.yield.flushed >= this.yield.every) {
16339            this.startImgAnalyzer(isForResize);
16340            return;
16341          }
16342        }
16343
16344        this.buildingRow.entriesBuff.push($entry);
16345        this.buildingRow.aspectRatio += imgAspectRatio;
16346        this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
16347        this.lastAnalyzedIndex = i;
16348
16349      } else if ($entry.data('jg.loaded') !== 'error') {
16350        return;
16351      }
16352    }
16353
16354    // Last row flush (the row is not full)
16355    if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true);
16356
16357    if (this.isSpinnerActive()) {
16358      this.stopLoadingSpinnerAnimation();
16359    }
16360
16361    /* Stop, if there is, the timeout to start the analyzeImages.
16362     This is because an image can be set loaded, and the timeout can be set,
16363     but this image can be analyzed yet.
16364     */
16365    this.stopImgAnalyzerStarter();
16366
16367    //On complete callback
16368    this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete');
16369    this.$gallery.height(this.galleryHeightToSet);
16370  };
16371
16372  /**
16373   * Stops any ImgAnalyzer starter (that has an assigned timeout)
16374   */
16375  JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
16376    this.yield.flushed = 0;
16377    if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout);
16378  };
16379
16380  /**
16381   * Starts the image analyzer. It is not immediately called to let the browser to update the view
16382   *
16383   * @param isForResize specifies if the image analyzer must be called for resizing or not
16384   */
16385  JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
16386    var that = this;
16387    this.stopImgAnalyzerStarter();
16388    this.imgAnalyzerTimeout = setTimeout(function () {
16389      that.analyzeImages(isForResize);
16390    }, 0.001); // we can't start it immediately due to a IE different behaviour
16391  };
16392
16393  /**
16394   * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
16395   * because some browsers, with a 404 set complete = true.
16396   *
16397   * @param imageSrc the image src to load
16398   * @param onLoad callback that is called when the image has been loaded
vendor: 13,320 bytes, lines 16399-16749
16399   * @param onError callback that is called in case of an error
16400   */
16401  JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
16402    if (!onLoad && !onError) return;
16403
16404    var memImage = new Image();
16405    var $memImage = $(memImage);
16406    if (onLoad) {
16407      $memImage.one('load', function () {
16408        $memImage.off('load error');
16409        onLoad(memImage);
16410      });
16411    }
16412    if (onError) {
16413      $memImage.one('error', function() {
16414        $memImage.off('load error');
16415        onError(memImage);
16416      });
16417    }
16418    memImage.src = imageSrc;
16419  };
16420
16421  /**
16422   * Init of Justified Gallery controlled
16423   * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
16424   */
16425  JustifiedGallery.prototype.init = function () {
16426    var imagesToLoad = false, skippedImages = false, that = this;
16427    $.each(this.entries, function (index, entry) {
16428      var $entry = $(entry);
16429      var $image = that.imgFromEntry($entry);
16430
16431      $entry.addClass('jg-entry');
16432
16433      if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
16434
16435        // Link Rel global overwrite
16436        if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
16437
16438        // Link Target global overwrite
16439        if (that.settings.target !== null) $entry.attr('target', that.settings.target);
16440
16441        if ($image !== null) {
16442
16443          // Image src
16444          var imageSrc = that.extractImgSrcFromImage($image);
16445          $image.attr('src', imageSrc);
16446
16447          /* If we have the height and the width, we don't wait that the image is loaded, but we start directly
16448           * with the justification */
16449          if (that.settings.waitThumbnailsLoad === false) {
16450            var width = parseFloat($image.attr('width'));
16451            var height = parseFloat($image.attr('height'));
16452            if (!isNaN(width) && !isNaN(height)) {
16453              $entry.data('jg.width', width);
16454              $entry.data('jg.height', height);
16455              $entry.data('jg.loaded', 'skipped');
16456              skippedImages = true;
16457              that.startImgAnalyzer(false);
16458              return true; // continue
16459            }
16460          }
16461
16462          $entry.data('jg.loaded', false);
16463          imagesToLoad = true;
16464
16465          // Spinner start
16466          if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
16467
16468          that.onImageEvent(imageSrc, function (loadImg) { // image loaded
16469            $entry.data('jg.width', loadImg.width);
16470            $entry.data('jg.height', loadImg.height);
16471            $entry.data('jg.loaded', true);
16472            that.startImgAnalyzer(false);
16473          }, function () { // image load error
16474            $entry.data('jg.loaded', 'error');
16475            that.startImgAnalyzer(false);
16476          });
16477
16478        } else {
16479          $entry.data('jg.loaded', true);
16480          $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
16481          $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
16482        }
16483
16484      }
16485
16486    });
16487
16488    if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
16489    this.checkWidth();
16490  };
16491
16492  /**
16493   * Checks that it is a valid number. If a string is passed it is converted to a number
16494   *
16495   * @param settingContainer the object that contains the setting (to allow the conversion)
16496   * @param settingName the setting name
16497   */
16498  JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
16499    if ($.type(settingContainer[settingName]) === 'string') {
16500      settingContainer[settingName] = parseFloat(settingContainer[settingName]);
16501    }
16502
16503    if ($.type(settingContainer[settingName]) === 'number') {
16504      if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
16505    } else {
16506      throw settingName + ' must be a number';
16507    }
16508  };
16509
16510  /**
16511   * Checks the sizeRangeSuffixes and, if necessary, converts
16512   * its keys from string (e.g. old settings with 'lt100') to int.
16513   */
16514  JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
16515    if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
16516      throw 'sizeRangeSuffixes must be defined and must be an object';
16517    }
16518
16519    var suffixRanges = [];
16520    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
16521      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
16522    }
16523
16524    var newSizeRngSuffixes = {0: ''};
16525    for (var i = 0; i < suffixRanges.length; i++) {
16526      if ($.type(suffixRanges[i]) === 'string') {
16527        try {
16528          var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
16529          newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
16530        } catch (e) {
16531          throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
16532        }
16533      } else {
16534        newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
16535      }
16536    }
16537
16538    this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
16539  };
16540
16541  /**
16542   * check and convert the maxRowHeight setting
16543   */
16544  JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
16545    var newMaxRowHeight = { };
16546
16547    if ($.type(this.settings.maxRowHeight) === 'string') {
16548      if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
16549        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
16550        newMaxRowHeight.isPercentage = false;
16551      } else {
16552        newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight);
16553        newMaxRowHeight.isPercentage = true;
16554      }
16555    } else if ($.type(this.settings.maxRowHeight) === 'number') {
16556      newMaxRowHeight.value = this.settings.maxRowHeight;
16557      newMaxRowHeight.isPercentage = false;
16558    } else if (this.settings.maxRowHeight === false ||
16559        this.settings.maxRowHeight === null ||
16560        typeof this.settings.maxRowHeight == 'undefined') {
16561      return null;
16562    } else {
16563      throw 'maxRowHeight must be a number or a percentage';
16564    }
16565
16566    // check if the converted value is not a number
16567    if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight';
16568
16569    // check values
16570    if (newMaxRowHeight.isPercentage) {
16571      if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100;
16572    }
16573
16574    return newMaxRowHeight;
16575  };
16576
16577  /**
16578   * Checks the settings
16579   */
16580  JustifiedGallery.prototype.checkSettings = function () {
16581    this.checkSizeRangesSuffixes();
16582
16583    this.checkOrConvertNumber(this.settings, 'rowHeight');
16584    this.checkOrConvertNumber(this.settings, 'margins');
16585    this.checkOrConvertNumber(this.settings, 'border');
16586
16587    var lastRowModes = [
16588      'justify',
16589      'nojustify',
16590      'left',
16591      'center',
16592      'right',
16593      'hide'
16594    ];
16595    if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
16596      throw 'lastRow must be one of: ' + lastRowModes.join(', ');
16597    }
16598
16599    this.checkOrConvertNumber(this.settings, 'justifyThreshold');
16600    if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
16601      throw 'justifyThreshold must be in the interval [0,1]';
16602    }
16603    if ($.type(this.settings.cssAnimation) !== 'boolean') {
16604      throw 'cssAnimation must be a boolean';
16605    }
16606
16607    if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
16608    this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
16609
16610    this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
16611    if (this.settings.captionSettings.visibleOpacity < 0 ||
16612        this.settings.captionSettings.visibleOpacity > 1) {
16613      throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
16614    }
16615
16616    this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
16617    if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
16618        this.settings.captionSettings.nonVisibleOpacity > 1) {
16619      throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
16620    }
16621
16622    this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
16623    this.checkOrConvertNumber(this.settings, 'refreshTime');
16624    this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
16625    if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
16626    if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
16627
16628    if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
16629      throw 'sort must be false or a comparison function';
16630    }
16631
16632    if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
16633        $.type(this.settings.filter) !== 'string') {
16634      throw 'filter must be false, a string or a filter function';
16635    }
16636  };
16637
16638  /**
16639   * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
16640   * @returns {Array} sorted suffix ranges
16641   */
16642  JustifiedGallery.prototype.retrieveSuffixRanges = function () {
16643    var suffixRanges = [];
16644    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
16645      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
16646    }
16647    suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
16648    return suffixRanges;
16649  };
16650
16651  /**
16652   * Update the existing settings only changing some of them
16653   *
16654   * @param newSettings the new settings (or a subgroup of them)
16655   */
16656  JustifiedGallery.prototype.updateSettings = function (newSettings) {
16657    // In this case Justified Gallery has been called again changing only some options
16658    this.settings = $.extend({}, this.settings, newSettings);
16659    this.checkSettings();
16660
16661    // As reported in the settings: negative value = same as margins, 0 = disabled
16662    this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
16663
16664    this.maxRowHeight = this.retrieveMaxRowHeight();
16665    this.suffixRanges = this.retrieveSuffixRanges();
16666  };
16667
16668  /**
16669   * Justified Gallery plugin for jQuery
16670   *
16671   * Events
16672   *  - jg.complete : called when all the gallery has been created
16673   *  - jg.resize : called when the gallery has been resized
16674   *  - jg.rowflush : when a new row appears
16675   *
16676   * @param arg the action (or the settings) passed when the plugin is called
16677   * @returns {*} the object itself
16678   */
16679  $.fn.justifiedGallery = function (arg) {
16680    return this.each(function (index, gallery) {
16681
16682      var $gallery = $(gallery);
16683      $gallery.addClass('justified-gallery');
16684
16685      var controller = $gallery.data('jg.controller');
16686      if (typeof controller === 'undefined') {
16687        // Create controller and assign it to the object data
16688        if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
16689          if (arg === 'destroy') return; // Just a call to an unexisting object
16690          throw 'The argument must be an object';
16691        }
16692        controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg));
16693        $gallery.data('jg.controller', controller);
16694      } else if (arg === 'norewind') {
16695        // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
16696        // ... left to be more readable
16697      } else if (arg === 'destroy') {
16698        controller.destroy();
16699        return;
16700      } else {
16701        // In this case Justified Gallery has been called again changing only some options
16702        controller.updateSettings(arg);
16703        controller.rewind();
16704      }
16705
16706      // Update the entries list
16707      if (!controller.updateEntries(arg === 'norewind')) return;
16708
16709      // Init justified gallery
16710      controller.init();
16711
16712    });
16713  };
16714
16715  // Default options
16716  $.fn.justifiedGallery.defaults = {
16717    sizeRangeSuffixes: { }, /* e.g. Flickr configuration
16718        {
16719          100: '_t',  // used when longest is less than 100px
16720          240: '_m',  // used when longest is between 101px and 240px
16721          320: '_n',  // ...
16722          500: '',
16723          640: '_z',
16724          1024: '_b'  // used as else case because it is the last
16725        }
16726    */
16727    thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
16728    path relative to a specific thumbnail size. The function should accept respectively three arguments:
16729    current path, width and height */
16730    rowHeight: 120,
16731    maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
16732                         // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
16733                         // can't exceed 3 * rowHeight)
16734    margins: 1,
16735    border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
16736
16737    lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
16738
16739    justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
16740                             * (i.e. lastRow setting is not considered) */
16741    waitThumbnailsLoad: true,
16742    captions: true,
16743    cssAnimation: true,
16744    imagesAnimationDuration: 500, // ignored with css animations
16745    captionSettings: { // ignored with css animations
16746      animationDuration: 500,
16747      visibleOpacity: 0.7,
16748      nonVisibleOpacity: 0.0
16749    },
vendor: 5,760 bytes, lines 16750-16893
16750    rel: null, // rewrite the rel of each analyzed links
16751    target: null, // rewrite the target of all links
16752    extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
16753    refreshTime: 200, // time interval (in ms) to check if the page changes its width
16754    refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
16755    randomize: false,
16756    sort: false, /*
16757      - false: to do not sort
16758      - function: to sort them using the function as comparator (see Array.prototype.sort())
16759    */
16760    filter: false, /*
16761      - false, null or undefined: for a disabled filter
16762      - a string: an entry is kept if entry.is(filter string) returns true
16763                  see jQuery's .is() function for further information
16764      - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
16765                    It follows the specifications of the Array.prototype.filter() function of JavaScript.
16766    */
16767    selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery
16768  };
16769
16770}(jQuery));
16771
16772/*!
16773* Customized version of iScroll.js 0.0.1
16774* It fixes bugs affecting its integration with fullpage.js
16775*/
16776/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
16777(function (window, document, Math) {
16778var rAF = window.requestAnimationFrame  ||
16779    window.webkitRequestAnimationFrame  ||
16780    window.mozRequestAnimationFrame     ||
16781    window.oRequestAnimationFrame       ||
16782    window.msRequestAnimationFrame      ||
16783    function (callback) { window.setTimeout(callback, 1000 / 60); };
16784
16785var utils = (function () {
16786    var me = {};
16787
16788    var _elementStyle = document.createElement('div').style;
16789    var _vendor = (function () {
16790        var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
16791            transform,
16792            i = 0,
16793            l = vendors.length;
16794
16795        for ( ; i < l; i++ ) {
16796            transform = vendors[i] + 'ransform';
16797            if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
16798        }
16799
16800        return false;
16801    })();
16802
16803    function _prefixStyle (style) {
16804        if ( _vendor === false ) return false;
16805        if ( _vendor === '' ) return style;
16806        return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
16807    }
16808
16809    me.getTime = Date.now || function getTime () { return new Date().getTime(); };
16810
16811    me.extend = function (target, obj) {
16812        for ( var i in obj ) {
16813            target[i] = obj[i];
16814        }
16815    };
16816
16817    me.addEvent = function (el, type, fn, capture) {
16818        el.addEventListener(type, fn, !!capture);
16819    };
16820
16821    me.removeEvent = function (el, type, fn, capture) {
16822        el.removeEventListener(type, fn, !!capture);
16823    };
16824
16825    me.prefixPointerEvent = function (pointerEvent) {
16826        return window.MSPointerEvent ?
16827            'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
16828            pointerEvent;
16829    };
16830
16831    me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
16832        var distance = current - start,
16833            speed = Math.abs(distance) / time,
16834            destination,
16835            duration;
16836
16837        deceleration = deceleration === undefined ? 0.0006 : deceleration;
16838
16839        destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
16840        duration = speed / deceleration;
16841
16842        if ( destination < lowerMargin ) {
16843            destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
16844            distance = Math.abs(destination - current);
16845            duration = distance / speed;
16846        } else if ( destination > 0 ) {
16847            destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
16848            distance = Math.abs(current) + destination;
16849            duration = distance / speed;
16850        }
16851
16852        return {
16853            destination: Math.round(destination),
16854            duration: duration
16855        };
16856    };
16857
16858    var _transform = _prefixStyle('transform');
16859
16860    me.extend(me, {
16861        hasTransform: _transform !== false,
16862        hasPerspective: _prefixStyle('perspective') in _elementStyle,
16863        hasTouch: 'ontouchstart' in window,
16864        hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
16865        hasTransition: _prefixStyle('transition') in _elementStyle
16866    });
16867
16868    /*
16869    This should find all Android browsers lower than build 535.19 (both stock browser and webview)
16870    - galaxy S2 is ok
16871    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
16872    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16873   - galaxy S3 is badAndroid (stock brower, webview)
16874     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16875   - galaxy S4 is badAndroid (stock brower, webview)
16876     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16877   - galaxy S5 is OK
16878     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
16879   - galaxy S6 is OK
16880     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
16881  */
16882    me.isBadAndroid = (function() {
16883        var appVersion = window.navigator.appVersion;
16884        // Android browser is not a chrome browser.
16885        if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
16886            var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
16887            if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
16888                return parseFloat(safariVersion[1]) < 535.19;
16889            } else {
16890                return true;
16891            }
16892        } else {
16893            return false;
vendor: 5,536 bytes, lines 16894-17086
16894        }
16895    })();
16896
16897    me.extend(me.style = {}, {
16898        transform: _transform,
16899        transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
16900        transitionDuration: _prefixStyle('transitionDuration'),
16901        transitionDelay: _prefixStyle('transitionDelay'),
16902        transformOrigin: _prefixStyle('transformOrigin')
16903    });
16904
16905    me.hasClass = function (e, c) {
16906        var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
16907        return re.test(e.className);
16908    };
16909
16910    me.addClass = function (e, c) {
16911        if ( me.hasClass(e, c) ) {
16912            return;
16913        }
16914
16915        var newclass = e.className.split(' ');
16916        newclass.push(c);
16917        e.className = newclass.join(' ');
16918    };
16919
16920    me.removeClass = function (e, c) {
16921        if ( !me.hasClass(e, c) ) {
16922            return;
16923        }
16924
16925        var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
16926        e.className = e.className.replace(re, ' ');
16927    };
16928
16929    me.offset = function (el) {
16930        var left = -el.offsetLeft,
16931            top = -el.offsetTop;
16932
16933        // jshint -W084
16934        while (el = el.offsetParent) {
16935            left -= el.offsetLeft;
16936            top -= el.offsetTop;
16937        }
16938        // jshint +W084
16939
16940        return {
16941            left: left,
16942            top: top
16943        };
16944    };
16945
16946    me.preventDefaultException = function (el, exceptions) {
16947        for ( var i in exceptions ) {
16948            if ( exceptions[i].test(el[i]) ) {
16949                return true;
16950            }
16951        }
16952
16953        return false;
16954    };
16955
16956    me.extend(me.eventType = {}, {
16957        touchstart: 1,
16958        touchmove: 1,
16959        touchend: 1,
16960
16961        mousedown: 2,
16962        mousemove: 2,
16963        mouseup: 2,
16964
16965        pointerdown: 3,
16966        pointermove: 3,
16967        pointerup: 3,
16968
16969        MSPointerDown: 3,
16970        MSPointerMove: 3,
16971        MSPointerUp: 3
16972    });
16973
16974    me.extend(me.ease = {}, {
16975        quadratic: {
16976            style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
16977            fn: function (k) {
16978                return k * ( 2 - k );
16979            }
16980        },
16981        circular: {
16982            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)
16983            fn: function (k) {
16984                return Math.sqrt( 1 - ( --k * k ) );
16985            }
16986        },
16987        back: {
16988            style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
16989            fn: function (k) {
16990                var b = 4;
16991                return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
16992            }
16993        },
16994        bounce: {
16995            style: '',
16996            fn: function (k) {
16997                if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
16998                    return 7.5625 * k * k;
16999                } else if ( k < ( 2 / 2.75 ) ) {
17000                    return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
17001                } else if ( k < ( 2.5 / 2.75 ) ) {
17002                    return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
17003                } else {
17004                    return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
17005                }
17006            }
17007        },
17008        elastic: {
17009            style: '',
17010            fn: function (k) {
17011                var f = 0.22,
17012                    e = 0.4;
17013
17014                if ( k === 0 ) { return 0; }
17015                if ( k == 1 ) { return 1; }
17016
17017                return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
17018            }
17019        }
17020    });
17021
17022    me.tap = function (e, eventName) {
17023        var ev = document.createEvent('Event');
17024        ev.initEvent(eventName, true, true);
17025        ev.pageX = e.pageX;
17026        ev.pageY = e.pageY;
17027        e.target.dispatchEvent(ev);
17028    };
17029
17030    me.click = function (e) {
17031        var target = e.target,
17032            ev;
17033
17034        if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
17035            // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
17036            // initMouseEvent is deprecated.
17037            ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
17038            ev.initEvent('click', true, true);
17039            ev.view = e.view || window;
17040            ev.detail = 1;
17041            ev.screenX = target.screenX || 0;
17042            ev.screenY = target.screenY || 0;
17043            ev.clientX = target.clientX || 0;
17044            ev.clientY = target.clientY || 0;
17045            ev.ctrlKey = !!e.ctrlKey;
17046            ev.altKey = !!e.altKey;
17047            ev.shiftKey = !!e.shiftKey;
17048            ev.metaKey = !!e.metaKey;
17049            ev.button = 0;
17050            ev.relatedTarget = null;
17051            ev._constructed = true;
17052            target.dispatchEvent(ev);
17053        }
17054    };
17055
17056    return me;
17057})();
17058function IScroll (el, options) {
17059    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
17060    this.scroller = this.wrapper.children[0];
17061    this.scrollerStyle = this.scroller.style;       // cache style for better performance
17062
17063    this.options = {
17064
17065        resizeScrollbars: true,
17066
17067        mouseWheelSpeed: 20,
17068
17069        snapThreshold: 0.334,
17070
17071// INSERT POINT: OPTIONS
17072        disablePointer : !utils.hasPointer,
17073        disableTouch : utils.hasPointer || !utils.hasTouch,
17074        disableMouse : utils.hasPointer || utils.hasTouch,
17075        startX: 0,
17076        startY: 0,
17077        scrollY: true,
17078        directionLockThreshold: 5,
17079        momentum: true,
17080
17081        bounce: true,
17082        bounceTime: 600,
17083        bounceEasing: '',
17084
17085        preventDefault: true,
17086        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
vendor: 4,420 bytes, lines 17086-17230
17086SELECT|LABEL)$/ },
17087
17088        HWCompositing: true,
17089        useTransition: true,
17090        useTransform: true,
17091        bindToWrapper: typeof window.onmousedown === "undefined"
17092    };
17093
17094    for ( var i in options ) {
17095        this.options[i] = options[i];
17096    }
17097
17098    // Normalize options
17099    this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
17100
17101    this.options.useTransition = utils.hasTransition && this.options.useTransition;
17102    this.options.useTransform = utils.hasTransform && this.options.useTransform;
17103
17104    this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
17105    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
17106
17107    // If you want eventPassthrough I have to lock one of the axes
17108    this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
17109    this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
17110
17111    // With eventPassthrough we also need lockDirection mechanism
17112    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
17113    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
17114
17115    this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
17116
17117    this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
17118
17119    if ( this.options.tap === true ) {
17120        this.options.tap = 'tap';
17121    }
17122
17123    // https://github.com/cubiq/iscroll/issues/1029
17124    if (!this.options.useTransition && !this.options.useTransform) {
17125        if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
17126            this.scrollerStyle.position = "relative";
17127        }
17128    }
17129
17130    if ( this.options.shrinkScrollbars == 'scale' ) {
17131        this.options.useTransition = false;
17132    }
17133
17134    this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
17135
17136// INSERT POINT: NORMALIZATION
17137
17138    // Some defaults
17139    this.x = 0;
17140    this.y = 0;
17141    this.directionX = 0;
17142    this.directionY = 0;
17143    this._events = {};
17144
17145// INSERT POINT: DEFAULTS
17146
17147    this._init();
17148    this.refresh();
17149
17150    this.scrollTo(this.options.startX, this.options.startY);
17151    this.enable();
17152}
17153
17154IScroll.prototype = {
17155    version: '5.2.0',
17156
17157    _init: function () {
17158        this._initEvents();
17159
17160        if ( this.options.scrollbars || this.options.indicators ) {
17161            this._initIndicators();
17162        }
17163
17164        if ( this.options.mouseWheel ) {
17165            this._initWheel();
17166        }
17167
17168        if ( this.options.snap ) {
17169            this._initSnap();
17170        }
17171
17172        if ( this.options.keyBindings ) {
17173            this._initKeys();
17174        }
17175
17176// INSERT POINT: _init
17177
17178    },
17179
17180    destroy: function () {
17181        this._initEvents(true);
17182        clearTimeout(this.resizeTimeout);
17183        this.resizeTimeout = null;
17184        this._execEvent('destroy');
17185    },
17186
17187    _transitionEnd: function (e) {
17188        if ( e.target != this.scroller || !this.isInTransition ) {
17189            return;
17190        }
17191
17192        this._transitionTime();
17193        if ( !this.resetPosition(this.options.bounceTime) ) {
17194            this.isInTransition = false;
17195            this._execEvent('scrollEnd');
17196        }
17197    },
17198
17199    _start: function (e) {
17200        // React to left mouse button only
17201        if ( utils.eventType[e.type] != 1 ) {
17202          // for button property
17203          // http://unixpapa.com/js/mouse.html
17204          var button;
17205        if (!e.which) {
17206          /* IE case */
17207          button = (e.button < 2) ? 0 :
17208                   ((e.button == 4) ? 1 : 2);
17209        } else {
17210          /* All others */
17211          button = e.button;
17212        }
17213            if ( button !== 0 ) {
17214                return;
17215            }
17216        }
17217
17218        if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
17219            return;
17220        }
17221
17222        if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
17223            e.preventDefault();
17224        }
17225
17226        var point = e.touches ? e.touches[0] : e,
17227            pos;
17228
17229        this.initiated  = utils.eventType[e.type];
17230        this.moved      = false;
vendor: 5,928 bytes, lines 17231-17409
17231        this.distX      = 0;
17232        this.distY      = 0;
17233        this.directionX = 0;
17234        this.directionY = 0;
17235        this.directionLocked = 0;
17236
17237        this.startTime = utils.getTime();
17238
17239        if ( this.options.useTransition && this.isInTransition ) {
17240            this._transitionTime();
17241            this.isInTransition = false;
17242            pos = this.getComputedPosition();
17243            this._translate(Math.round(pos.x), Math.round(pos.y));
17244            this._execEvent('scrollEnd');
17245        } else if ( !this.options.useTransition && this.isAnimating ) {
17246            this.isAnimating = false;
17247            this._execEvent('scrollEnd');
17248        }
17249
17250        this.startX    = this.x;
17251        this.startY    = this.y;
17252        this.absStartX = this.x;
17253        this.absStartY = this.y;
17254        this.pointX    = point.pageX;
17255        this.pointY    = point.pageY;
17256
17257        this._execEvent('beforeScrollStart');
17258    },
17259
17260    _move: function (e) {
17261        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
17262            return;
17263        }
17264
17265        if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
17266            e.preventDefault();
17267        }
17268
17269        var point       = e.touches ? e.touches[0] : e,
17270            deltaX      = point.pageX - this.pointX,
17271            deltaY      = point.pageY - this.pointY,
17272            timestamp   = utils.getTime(),
17273            newX, newY,
17274            absDistX, absDistY;
17275
17276        this.pointX     = point.pageX;
17277        this.pointY     = point.pageY;
17278
17279        this.distX      += deltaX;
17280        this.distY      += deltaY;
17281        absDistX        = Math.abs(this.distX);
17282        absDistY        = Math.abs(this.distY);
17283
17284        // We need to move at least 10 pixels for the scrolling to initiate
17285        if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
17286            return;
17287        }
17288
17289        // If you are scrolling in one direction lock the other
17290        if ( !this.directionLocked && !this.options.freeScroll ) {
17291            if ( absDistX > absDistY + this.options.directionLockThreshold ) {
17292                this.directionLocked = 'h';     // lock horizontally
17293            } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
17294                this.directionLocked = 'v';     // lock vertically
17295            } else {
17296                this.directionLocked = 'n';     // no lock
17297            }
17298        }
17299
17300        if ( this.directionLocked == 'h' ) {
17301            if ( this.options.eventPassthrough == 'vertical' ) {
17302                e.preventDefault();
17303            } else if ( this.options.eventPassthrough == 'horizontal' ) {
17304                this.initiated = false;
17305                return;
17306            }
17307
17308            deltaY = 0;
17309        } else if ( this.directionLocked == 'v' ) {
17310            if ( this.options.eventPassthrough == 'horizontal' ) {
17311                e.preventDefault();
17312            } else if ( this.options.eventPassthrough == 'vertical' ) {
17313                this.initiated = false;
17314                return;
17315            }
17316
17317            deltaX = 0;
17318        }
17319
17320        deltaX = this.hasHorizontalScroll ? deltaX : 0;
17321        deltaY = this.hasVerticalScroll ? deltaY : 0;
17322
17323        newX = this.x + deltaX;
17324        newY = this.y + deltaY;
17325
17326        // Slow down if outside of the boundaries
17327        if ( newX > 0 || newX < this.maxScrollX ) {
17328            newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
17329        }
17330        if ( newY > 0 || newY < this.maxScrollY ) {
17331            newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
17332        }
17333
17334        this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
17335        this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
17336
17337        if ( !this.moved ) {
17338            this._execEvent('scrollStart');
17339        }
17340
17341        this.moved = true;
17342
17343        this._translate(newX, newY);
17344
17345/* REPLACE START: _move */
17346
17347        if ( timestamp - this.startTime > 300 ) {
17348            this.startTime = timestamp;
17349            this.startX = this.x;
17350            this.startY = this.y;
17351        }
17352
17353/* REPLACE END: _move */
17354
17355    },
17356
17357    _end: function (e) {
17358        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
17359            return;
17360        }
17361
17362        if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
17363            e.preventDefault();
17364        }
17365
17366        var point = e.changedTouches ? e.changedTouches[0] : e,
17367            momentumX,
17368            momentumY,
17369            duration = utils.getTime() - this.startTime,
17370            newX = Math.round(this.x),
17371            newY = Math.round(this.y),
17372            distanceX = Math.abs(newX - this.startX),
17373            distanceY = Math.abs(newY - this.startY),
17374            time = 0,
17375            easing = '';
17376
17377        this.isInTransition = 0;
17378        this.initiated = 0;
17379        this.endTime = utils.getTime();
17380
17381        // reset if we are outside of the boundaries
17382        if ( this.resetPosition(this.options.bounceTime) ) {
17383            return;
17384        }
17385
17386        this.scrollTo(newX, newY);  // ensures that the last position is rounded
17387
17388        // we scrolled less than 10 pixels
17389        if ( !this.moved ) {
17390            if ( this.options.tap ) {
17391                utils.tap(e, this.options.tap);
17392            }
17393
17394            if ( this.options.click ) {
17395                utils.click(e);
17396            }
17397
17398            this._execEvent('scrollCancel');
17399            return;
17400        }
17401
17402        if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
17403            this._execEvent('flick');
17404            return;
17405        }
17406
17407        // start momentum animation if needed
17408        if ( this.options.momentum && duration < 300 ) {
17409            momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 7,740 bytes, lines 17409-17682
17409idth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
17410            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 };
17411            newX = momentumX.destination;
17412            newY = momentumY.destination;
17413            time = Math.max(momentumX.duration, momentumY.duration);
17414            this.isInTransition = 1;
17415        }
17416
17417
17418        if ( this.options.snap ) {
17419            var snap = this._nearestSnap(newX, newY);
17420            this.currentPage = snap;
17421            time = this.options.snapSpeed || Math.max(
17422                    Math.max(
17423                        Math.min(Math.abs(newX - snap.x), 1000),
17424                        Math.min(Math.abs(newY - snap.y), 1000)
17425                    ), 300);
17426            newX = snap.x;
17427            newY = snap.y;
17428
17429            this.directionX = 0;
17430            this.directionY = 0;
17431            easing = this.options.bounceEasing;
17432        }
17433
17434// INSERT POINT: _end
17435
17436        if ( newX != this.x || newY != this.y ) {
17437            // change easing function when scroller goes out of the boundaries
17438            if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
17439                easing = utils.ease.quadratic;
17440            }
17441
17442            this.scrollTo(newX, newY, time, easing);
17443            return;
17444        }
17445
17446        this._execEvent('scrollEnd');
17447    },
17448
17449    _resize: function () {
17450        var that = this;
17451
17452        clearTimeout(this.resizeTimeout);
17453
17454        this.resizeTimeout = setTimeout(function () {
17455            that.refresh();
17456        }, this.options.resizePolling);
17457    },
17458
17459    resetPosition: function (time) {
17460        var x = this.x,
17461            y = this.y;
17462
17463        time = time || 0;
17464
17465        if ( !this.hasHorizontalScroll || this.x > 0 ) {
17466            x = 0;
17467        } else if ( this.x < this.maxScrollX ) {
17468            x = this.maxScrollX;
17469        }
17470
17471        if ( !this.hasVerticalScroll || this.y > 0 ) {
17472            y = 0;
17473        } else if ( this.y < this.maxScrollY ) {
17474            y = this.maxScrollY;
17475        }
17476
17477        if ( x == this.x && y == this.y ) {
17478            return false;
17479        }
17480
17481        this.scrollTo(x, y, time, this.options.bounceEasing);
17482
17483        return true;
17484    },
17485
17486    disable: function () {
17487        this.enabled = false;
17488    },
17489
17490    enable: function () {
17491        this.enabled = true;
17492    },
17493
17494    refresh: function () {
17495        var rf = this.wrapper.offsetHeight;     // Force reflow
17496
17497        this.wrapperWidth   = this.wrapper.clientWidth;
17498        this.wrapperHeight  = this.wrapper.clientHeight;
17499
17500/* REPLACE START: refresh */
17501
17502        this.scrollerWidth  = this.scroller.offsetWidth;
17503        this.scrollerHeight = this.scroller.offsetHeight;
17504
17505        this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
17506        this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
17507
17508/* REPLACE END: refresh */
17509
17510        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
17511        this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
17512
17513        if ( !this.hasHorizontalScroll ) {
17514            this.maxScrollX = 0;
17515            this.scrollerWidth = this.wrapperWidth;
17516        }
17517
17518        if ( !this.hasVerticalScroll ) {
17519            this.maxScrollY = 0;
17520            this.scrollerHeight = this.wrapperHeight;
17521        }
17522
17523        this.endTime = 0;
17524        this.directionX = 0;
17525        this.directionY = 0;
17526
17527        this.wrapperOffset = utils.offset(this.wrapper);
17528
17529        this._execEvent('refresh');
17530
17531        this.resetPosition();
17532
17533// INSERT POINT: _refresh
17534
17535    },
17536
17537    on: function (type, fn) {
17538        if ( !this._events[type] ) {
17539            this._events[type] = [];
17540        }
17541
17542        this._events[type].push(fn);
17543    },
17544
17545    off: function (type, fn) {
17546        if ( !this._events[type] ) {
17547            return;
17548        }
17549
17550        var index = this._events[type].indexOf(fn);
17551
17552        if ( index > -1 ) {
17553            this._events[type].splice(index, 1);
17554        }
17555    },
17556
17557    _execEvent: function (type) {
17558        if ( !this._events[type] ) {
17559            return;
17560        }
17561
17562        var i = 0,
17563            l = this._events[type].length;
17564
17565        if ( !l ) {
17566            return;
17567        }
17568
17569        for ( ; i < l; i++ ) {
17570            this._events[type][i].apply(this, [].slice.call(arguments, 1));
17571        }
17572    },
17573
17574    scrollBy: function (x, y, time, easing) {
17575        x = this.x + x;
17576        y = this.y + y;
17577        time = time || 0;
17578
17579        this.scrollTo(x, y, time, easing);
17580    },
17581
17582    scrollTo: function (x, y, time, easing) {
17583        easing = easing || utils.ease.circular;
17584
17585        this.isInTransition = this.options.useTransition && time > 0;
17586        var transitionType = this.options.useTransition && easing.style;
17587        if ( !time || transitionType ) {
17588                if(transitionType) {
17589                    this._transitionTimingFunction(easing.style);
17590                    this._transitionTime(time);
17591                }
17592            this._translate(x, y);
17593        } else {
17594            this._animate(x, y, time, easing.fn);
17595        }
17596    },
17597
17598    scrollToElement: function (el, time, offsetX, offsetY, easing) {
17599        el = el.nodeType ? el : this.scroller.querySelector(el);
17600
17601        if ( !el ) {
17602            return;
17603        }
17604
17605        var pos = utils.offset(el);
17606
17607        pos.left -= this.wrapperOffset.left;
17608        pos.top  -= this.wrapperOffset.top;
17609
17610        // if offsetX/Y are true we center the element to the screen
17611        if ( offsetX === true ) {
17612            offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
17613        }
17614        if ( offsetY === true ) {
17615            offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
17616        }
17617
17618        pos.left -= offsetX || 0;
17619        pos.top  -= offsetY || 0;
17620
17621        pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
17622        pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
17623
17624        time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
17625
17626        this.scrollTo(pos.left, pos.top, time, easing);
17627    },
17628
17629    _transitionTime: function (time) {
17630        if (!this.options.useTransition) {
17631            return;
17632        }
17633        time = time || 0;
17634        var durationProp = utils.style.transitionDuration;
17635        if(!durationProp) {
17636            return;
17637        }
17638
17639        this.scrollerStyle[durationProp] = time + 'ms';
17640
17641        if ( !time && utils.isBadAndroid ) {
17642            this.scrollerStyle[durationProp] = '0.0001ms';
17643            // remove 0.0001ms
17644            var self = this;
17645            rAF(function() {
17646                if(self.scrollerStyle[durationProp] === '0.0001ms') {
17647                    self.scrollerStyle[durationProp] = '0s';
17648                }
17649            });
17650        }
17651
17652
17653        if ( this.indicators ) {
17654            for ( var i = this.indicators.length; i--; ) {
17655                this.indicators[i].transitionTime(time);
17656            }
17657        }
17658
17659
17660// INSERT POINT: _transitionTime
17661
17662    },
17663
17664    _transitionTimingFunction: function (easing) {
17665        this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
17666
17667
17668        if ( this.indicators ) {
17669            for ( var i = this.indicators.length; i--; ) {
17670                this.indicators[i].transitionTimingFunction(easing);
17671            }
17672        }
17673
17674
17675// INSERT POINT: _transitionTimingFunction
17676
17677    },
17678
17679    _translate: function (x, y) {
17680        //Uncode addition
17681        if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
17682            return false;
vendor: 9,946 bytes, lines 17683-17994
17683
17684        if ( this.options.useTransform ) {
17685
17686/* REPLACE START: _translate */
17687
17688            this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
17689
17690/* REPLACE END: _translate */
17691
17692        } else {
17693            x = Math.round(x);
17694            y = Math.round(y);
17695            this.scrollerStyle.left = x + 'px';
17696            this.scrollerStyle.top = y + 'px';
17697        }
17698
17699        this.x = x;
17700        this.y = y;
17701
17702
17703        if ( this.indicators ) {
17704            for ( var i = this.indicators.length; i--; ) {
17705                this.indicators[i].updatePosition();
17706            }
17707        }
17708
17709        //Uncode addition
17710        var uncodevent = new CustomEvent('fp-slide-scroll');
17711        window.dispatchEvent(uncodevent);       
17712
17713// INSERT POINT: _translate
17714
17715    },
17716
17717    _initEvents: function (remove) {
17718        var eventType = remove ? utils.removeEvent : utils.addEvent,
17719            target = this.options.bindToWrapper ? this.wrapper : window;
17720
17721        eventType(window, 'orientationchange', this);
17722        eventType(window, 'resize', this);
17723
17724        if ( this.options.click ) {
17725            eventType(this.wrapper, 'click', this, true);
17726        }
17727
17728        if ( !this.options.disableMouse ) {
17729            eventType(this.wrapper, 'mousedown', this);
17730            eventType(target, 'mousemove', this);
17731            eventType(target, 'mousecancel', this);
17732            eventType(target, 'mouseup', this);
17733        }
17734
17735        if ( utils.hasPointer && !this.options.disablePointer ) {
17736            eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
17737            eventType(target, utils.prefixPointerEvent('pointermove'), this);
17738            eventType(target, utils.prefixPointerEvent('pointercancel'), this);
17739            eventType(target, utils.prefixPointerEvent('pointerup'), this);
17740        }
17741
17742        if ( utils.hasTouch && !this.options.disableTouch ) {
17743            eventType(this.wrapper, 'touchstart', this);
17744            eventType(target, 'touchmove', this);
17745            eventType(target, 'touchcancel', this);
17746            eventType(target, 'touchend', this);
17747        }
17748
17749        eventType(this.scroller, 'transitionend', this);
17750        eventType(this.scroller, 'webkitTransitionEnd', this);
17751        eventType(this.scroller, 'oTransitionEnd', this);
17752        eventType(this.scroller, 'MSTransitionEnd', this);
17753    },
17754
17755    getComputedPosition: function () {
17756        var matrix = window.getComputedStyle(this.scroller, null),
17757            x, y;
17758
17759        if ( this.options.useTransform ) {
17760            matrix = matrix[utils.style.transform].split(')')[0].split(', ');
17761            x = +(matrix[12] || matrix[4]);
17762            y = +(matrix[13] || matrix[5]);
17763        } else {
17764            x = +matrix.left.replace(/[^-\d.]/g, '');
17765            y = +matrix.top.replace(/[^-\d.]/g, '');
17766        }
17767
17768        return { x: x, y: y };
17769    },
17770    _initIndicators: function () {
17771        var interactive = this.options.interactiveScrollbars,
17772            customStyle = typeof this.options.scrollbars != 'string',
17773            indicators = [],
17774            indicator;
17775
17776        var that = this;
17777
17778        this.indicators = [];
17779
17780        if ( this.options.scrollbars ) {
17781            // Vertical scrollbar
17782            if ( this.options.scrollY ) {
17783                indicator = {
17784                    el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
17785                    interactive: interactive,
17786                    defaultScrollbars: true,
17787                    customStyle: customStyle,
17788                    resize: this.options.resizeScrollbars,
17789                    shrink: this.options.shrinkScrollbars,
17790                    fade: this.options.fadeScrollbars,
17791                    listenX: false
17792                };
17793
17794                this.wrapper.appendChild(indicator.el);
17795                indicators.push(indicator);
17796            }
17797
17798            // Horizontal scrollbar
17799            if ( this.options.scrollX ) {
17800                indicator = {
17801                    el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
17802                    interactive: interactive,
17803                    defaultScrollbars: true,
17804                    customStyle: customStyle,
17805                    resize: this.options.resizeScrollbars,
17806                    shrink: this.options.shrinkScrollbars,
17807                    fade: this.options.fadeScrollbars,
17808                    listenY: false
17809                };
17810
17811                this.wrapper.appendChild(indicator.el);
17812                indicators.push(indicator);
17813            }
17814        }
17815
17816        if ( this.options.indicators ) {
17817            // TODO: check concat compatibility
17818            indicators = indicators.concat(this.options.indicators);
17819        }
17820
17821        for ( var i = indicators.length; i--; ) {
17822            this.indicators.push( new Indicator(this, indicators[i]) );
17823        }
17824
17825        // TODO: check if we can use array.map (wide compatibility and performance issues)
17826        function _indicatorsMap (fn) {
17827            if (that.indicators) {
17828                for ( var i = that.indicators.length; i--; ) {
17829                    fn.call(that.indicators[i]);
17830                }
17831            }
17832        }
17833
17834        if ( this.options.fadeScrollbars ) {
17835            this.on('scrollEnd', function () {
17836                _indicatorsMap(function () {
17837                    this.fade();
17838                });
17839            });
17840
17841            this.on('scrollCancel', function () {
17842                _indicatorsMap(function () {
17843                    this.fade();
17844                });
17845            });
17846
17847            this.on('scrollStart', function () {
17848                _indicatorsMap(function () {
17849                    this.fade(1);
17850                });
17851            });
17852
17853            this.on('beforeScrollStart', function () {
17854                _indicatorsMap(function () {
17855                    this.fade(1, true);
17856                });
17857            });
17858        }
17859
17860
17861        this.on('refresh', function () {
17862            _indicatorsMap(function () {
17863                this.refresh();
17864            });
17865        });
17866
17867        this.on('destroy', function () {
17868            _indicatorsMap(function () {
17869                this.destroy();
17870            });
17871
17872            delete this.indicators;
17873        });
17874    },
17875
17876    _initWheel: function () {
17877        utils.addEvent(this.wrapper, 'wheel', this);
17878        utils.addEvent(this.wrapper, 'mousewheel', this);
17879        utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
17880
17881        this.on('destroy', function () {
17882            clearTimeout(this.wheelTimeout);
17883            this.wheelTimeout = null;
17884            utils.removeEvent(this.wrapper, 'wheel', this);
17885            utils.removeEvent(this.wrapper, 'mousewheel', this);
17886            utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
17887        });
17888    },
17889
17890    _wheel: function (e) {
17891        if ( !this.enabled ) {
17892            return;
17893        }
17894
17895        var wheelDeltaX, wheelDeltaY,
17896            newX, newY,
17897            that = this;
17898
17899        if ( this.wheelTimeout === undefined ) {
17900            that._execEvent('scrollStart');
17901        }
17902
17903        // Execute the scrollEnd event after 400ms the wheel stopped scrolling
17904        clearTimeout(this.wheelTimeout);
17905        this.wheelTimeout = setTimeout(function () {
17906            if(!that.options.snap) {
17907                that._execEvent('scrollEnd');
17908            }
17909            that.wheelTimeout = undefined;
17910        }, 400);
17911
17912        if ( 'deltaX' in e ) {
17913            if (e.deltaMode === 1) {
17914                wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
17915                wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
17916            } else {
17917                wheelDeltaX = -e.deltaX;
17918                wheelDeltaY = -e.deltaY;
17919            }
17920        } else if ( 'wheelDeltaX' in e ) {
17921            wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
17922            wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
17923        } else if ( 'wheelDelta' in e ) {
17924            wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
17925        } else if ( 'detail' in e ) {
17926            wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
17927        } else {
17928            return;
17929        }
17930
17931        wheelDeltaX *= this.options.invertWheelDirection;
17932        wheelDeltaY *= this.options.invertWheelDirection;
17933
17934        if ( !this.hasVerticalScroll ) {
17935            wheelDeltaX = wheelDeltaY;
17936            wheelDeltaY = 0;
17937        }
17938
17939        if ( this.options.snap ) {
17940            newX = this.currentPage.pageX;
17941            newY = this.currentPage.pageY;
17942
17943            if ( wheelDeltaX > 0 ) {
17944                newX--;
17945            } else if ( wheelDeltaX < 0 ) {
17946                newX++;
17947            }
17948
17949            if ( wheelDeltaY > 0 ) {
17950                newY--;
17951            } else if ( wheelDeltaY < 0 ) {
17952                newY++;
17953            }
17954
17955            this.goToPage(newX, newY);
17956
17957            return;
17958        }
17959
17960        newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
17961        newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
17962
17963        this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
17964        this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
17965
17966        if ( newX > 0 ) {
17967            newX = 0;
17968        } else if ( newX < this.maxScrollX ) {
17969            newX = this.maxScrollX;
17970        }
17971
17972        if ( newY > 0 ) {
17973            newY = 0;
17974        } else if ( newY < this.maxScrollY ) {
17975            newY = this.maxScrollY;
17976        }
17977
17978        this.scrollTo(newX, newY, 0);
17979
17980// INSERT POINT: _wheel
17981    },
17982
17983    _initSnap: function () {
17984        this.currentPage = {};
17985
17986        if ( typeof this.options.snap == 'string' ) {
17987            this.options.snap = this.scroller.querySelectorAll(this.options.snap);
17988        }
17989
17990        this.on('refresh', function () {
17991            var i = 0, l,
17992                m = 0, n,
17993                cx, cy,
17994                x = 0, y,
vendor: 7,339 bytes, lines 17995-18248
17995                stepX = this.options.snapStepX || this.wrapperWidth,
17996                stepY = this.options.snapStepY || this.wrapperHeight,
17997                el;
17998
17999            this.pages = [];
18000
18001            if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
18002                return;
18003            }
18004
18005            if ( this.options.snap === true ) {
18006                cx = Math.round( stepX / 2 );
18007                cy = Math.round( stepY / 2 );
18008
18009                while ( x > -this.scrollerWidth ) {
18010                    this.pages[i] = [];
18011                    l = 0;
18012                    y = 0;
18013
18014                    while ( y > -this.scrollerHeight ) {
18015                        this.pages[i][l] = {
18016                            x: Math.max(x, this.maxScrollX),
18017                            y: Math.max(y, this.maxScrollY),
18018                            width: stepX,
18019                            height: stepY,
18020                            cx: x - cx,
18021                            cy: y - cy
18022                        };
18023
18024                        y -= stepY;
18025                        l++;
18026                    }
18027
18028                    x -= stepX;
18029                    i++;
18030                }
18031            } else {
18032                el = this.options.snap;
18033                l = el.length;
18034                n = -1;
18035
18036                for ( ; i < l; i++ ) {
18037                    if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
18038                        m = 0;
18039                        n++;
18040                    }
18041
18042                    if ( !this.pages[m] ) {
18043                        this.pages[m] = [];
18044                    }
18045
18046                    x = Math.max(-el[i].offsetLeft, this.maxScrollX);
18047                    y = Math.max(-el[i].offsetTop, this.maxScrollY);
18048                    cx = x - Math.round(el[i].offsetWidth / 2);
18049                    cy = y - Math.round(el[i].offsetHeight / 2);
18050
18051                    this.pages[m][n] = {
18052                        x: x,
18053                        y: y,
18054                        width: el[i].offsetWidth,
18055                        height: el[i].offsetHeight,
18056                        cx: cx,
18057                        cy: cy
18058                    };
18059
18060                    if ( x > this.maxScrollX ) {
18061                        m++;
18062                    }
18063                }
18064            }
18065
18066            this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
18067
18068            // Update snap threshold if needed
18069            if ( this.options.snapThreshold % 1 === 0 ) {
18070                this.snapThresholdX = this.options.snapThreshold;
18071                this.snapThresholdY = this.options.snapThreshold;
18072            } else {
18073                this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
18074                this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
18075            }
18076        });
18077
18078        this.on('flick', function () {
18079            var time = this.options.snapSpeed || Math.max(
18080                    Math.max(
18081                        Math.min(Math.abs(this.x - this.startX), 1000),
18082                        Math.min(Math.abs(this.y - this.startY), 1000)
18083                    ), 300);
18084
18085            this.goToPage(
18086                this.currentPage.pageX + this.directionX,
18087                this.currentPage.pageY + this.directionY,
18088                time
18089            );
18090        });
18091    },
18092
18093    _nearestSnap: function (x, y) {
18094        if ( !this.pages.length ) {
18095            return { x: 0, y: 0, pageX: 0, pageY: 0 };
18096        }
18097
18098        var i = 0,
18099            l = this.pages.length,
18100            m = 0;
18101
18102        // Check if we exceeded the snap threshold
18103        if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
18104            Math.abs(y - this.absStartY) < this.snapThresholdY ) {
18105            return this.currentPage;
18106        }
18107
18108        if ( x > 0 ) {
18109            x = 0;
18110        } else if ( x < this.maxScrollX ) {
18111            x = this.maxScrollX;
18112        }
18113
18114        if ( y > 0 ) {
18115            y = 0;
18116        } else if ( y < this.maxScrollY ) {
18117            y = this.maxScrollY;
18118        }
18119
18120        for ( ; i < l; i++ ) {
18121            if ( x >= this.pages[i][0].cx ) {
18122                x = this.pages[i][0].x;
18123                break;
18124            }
18125        }
18126
18127        l = this.pages[i].length;
18128
18129        for ( ; m < l; m++ ) {
18130            if ( y >= this.pages[0][m].cy ) {
18131                y = this.pages[0][m].y;
18132                break;
18133            }
18134        }
18135
18136        if ( i == this.currentPage.pageX ) {
18137            i += this.directionX;
18138
18139            if ( i < 0 ) {
18140                i = 0;
18141            } else if ( i >= this.pages.length ) {
18142                i = this.pages.length - 1;
18143            }
18144
18145            x = this.pages[i][0].x;
18146        }
18147
18148        if ( m == this.currentPage.pageY ) {
18149            m += this.directionY;
18150
18151            if ( m < 0 ) {
18152                m = 0;
18153            } else if ( m >= this.pages[0].length ) {
18154                m = this.pages[0].length - 1;
18155            }
18156
18157            y = this.pages[0][m].y;
18158        }
18159
18160        return {
18161            x: x,
18162            y: y,
18163            pageX: i,
18164            pageY: m
18165        };
18166    },
18167
18168    goToPage: function (x, y, time, easing) {
18169        easing = easing || this.options.bounceEasing;
18170
18171        if ( x >= this.pages.length ) {
18172            x = this.pages.length - 1;
18173        } else if ( x < 0 ) {
18174            x = 0;
18175        }
18176
18177        if ( y >= this.pages[x].length ) {
18178            y = this.pages[x].length - 1;
18179        } else if ( y < 0 ) {
18180            y = 0;
18181        }
18182
18183        var posX = this.pages[x][y].x,
18184            posY = this.pages[x][y].y;
18185
18186        time = time === undefined ? this.options.snapSpeed || Math.max(
18187            Math.max(
18188                Math.min(Math.abs(posX - this.x), 1000),
18189                Math.min(Math.abs(posY - this.y), 1000)
18190            ), 300) : time;
18191
18192        this.currentPage = {
18193            x: posX,
18194            y: posY,
18195            pageX: x,
18196            pageY: y
18197        };
18198
18199        this.scrollTo(posX, posY, time, easing);
18200    },
18201
18202    next: function (time, easing) {
18203        var x = this.currentPage.pageX,
18204            y = this.currentPage.pageY;
18205
18206        x++;
18207
18208        if ( x >= this.pages.length && this.hasVerticalScroll ) {
18209            x = 0;
18210            y++;
18211        }
18212
18213        this.goToPage(x, y, time, easing);
18214    },
18215
18216    prev: function (time, easing) {
18217        var x = this.currentPage.pageX,
18218            y = this.currentPage.pageY;
18219
18220        x--;
18221
18222        if ( x < 0 && this.hasVerticalScroll ) {
18223            x = 0;
18224            y--;
18225        }
18226
18227        this.goToPage(x, y, time, easing);
18228    },
18229
18230    _initKeys: function (e) {
18231        // default key bindings
18232        var keys = {
18233            pageUp: 33,
18234            pageDown: 34,
18235            end: 35,
18236            home: 36,
18237            left: 37,
18238            up: 38,
18239            right: 39,
18240            down: 40
18241        };
18242        var i;
18243
18244        // if you give me characters I give you keycode
18245        if ( typeof this.options.keyBindings == 'object' ) {
18246            for ( i in this.options.keyBindings ) {
18247                if ( typeof this.options.keyBindings[i] == 'string' ) {
18248                    this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 18248-18601
18248deAt(0);
18249                }
18250            }
18251        } else {
18252            this.options.keyBindings = {};
18253        }
18254
18255        for ( i in keys ) {
18256            this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
18257        }
18258
18259        utils.addEvent(window, 'keydown', this);
18260
18261        this.on('destroy', function () {
18262            utils.removeEvent(window, 'keydown', this);
18263        });
18264    },
18265
18266    _key: function (e) {
18267        if ( !this.enabled ) {
18268            return;
18269        }
18270
18271        var snap = this.options.snap,   // we are using this alot, better to cache it
18272            newX = snap ? this.currentPage.pageX : this.x,
18273            newY = snap ? this.currentPage.pageY : this.y,
18274            now = utils.getTime(),
18275            prevTime = this.keyTime || 0,
18276            acceleration = 0.250,
18277            pos;
18278
18279        if ( this.options.useTransition && this.isInTransition ) {
18280            pos = this.getComputedPosition();
18281
18282            this._translate(Math.round(pos.x), Math.round(pos.y));
18283            this.isInTransition = false;
18284        }
18285
18286        this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
18287
18288        switch ( e.keyCode ) {
18289            case this.options.keyBindings.pageUp:
18290                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
18291                    newX += snap ? 1 : this.wrapperWidth;
18292                } else {
18293                    newY += snap ? 1 : this.wrapperHeight;
18294                }
18295                break;
18296            case this.options.keyBindings.pageDown:
18297                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
18298                    newX -= snap ? 1 : this.wrapperWidth;
18299                } else {
18300                    newY -= snap ? 1 : this.wrapperHeight;
18301                }
18302                break;
18303            case this.options.keyBindings.end:
18304                newX = snap ? this.pages.length-1 : this.maxScrollX;
18305                newY = snap ? this.pages[0].length-1 : this.maxScrollY;
18306                break;
18307            case this.options.keyBindings.home:
18308                newX = 0;
18309                newY = 0;
18310                break;
18311            case this.options.keyBindings.left:
18312                newX += snap ? -1 : 5 + this.keyAcceleration>>0;
18313                break;
18314            case this.options.keyBindings.up:
18315                newY += snap ? 1 : 5 + this.keyAcceleration>>0;
18316                break;
18317            case this.options.keyBindings.right:
18318                newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
18319                break;
18320            case this.options.keyBindings.down:
18321                newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
18322                break;
18323            default:
18324                return;
18325        }
18326
18327        if ( snap ) {
18328            this.goToPage(newX, newY);
18329            return;
18330        }
18331
18332        if ( newX > 0 ) {
18333            newX = 0;
18334            this.keyAcceleration = 0;
18335        } else if ( newX < this.maxScrollX ) {
18336            newX = this.maxScrollX;
18337            this.keyAcceleration = 0;
18338        }
18339
18340        if ( newY > 0 ) {
18341            newY = 0;
18342            this.keyAcceleration = 0;
18343        } else if ( newY < this.maxScrollY ) {
18344            newY = this.maxScrollY;
18345            this.keyAcceleration = 0;
18346        }
18347
18348        this.scrollTo(newX, newY, 0);
18349
18350        this.keyTime = now;
18351    },
18352
18353    _animate: function (destX, destY, duration, easingFn) {
18354        var that = this,
18355            startX = this.x,
18356            startY = this.y,
18357            startTime = utils.getTime(),
18358            destTime = startTime + duration;
18359
18360        function step () {
18361            var now = utils.getTime(),
18362                newX, newY,
18363                easing;
18364
18365            if ( now >= destTime ) {
18366                that.isAnimating = false;
18367                that._translate(destX, destY);
18368
18369                if ( !that.resetPosition(that.options.bounceTime) ) {
18370                    that._execEvent('scrollEnd');
18371                }
18372
18373                return;
18374            }
18375
18376            now = ( now - startTime ) / duration;
18377            easing = easingFn(now);
18378            newX = ( destX - startX ) * easing + startX;
18379            newY = ( destY - startY ) * easing + startY;
18380            that._translate(newX, newY);
18381
18382            if ( that.isAnimating ) {
18383                rAF(step);
18384            }
18385        }
18386
18387        this.isAnimating = true;
18388        step();
18389    },
18390    handleEvent: function (e) {
18391        switch ( e.type ) {
18392            case 'touchstart':
18393            case 'pointerdown':
18394            case 'MSPointerDown':
18395            case 'mousedown':
18396                this._start(e);
18397                break;
18398            case 'touchmove':
18399            case 'pointermove':
18400            case 'MSPointerMove':
18401            case 'mousemove':
18402                this._move(e);
18403                break;
18404            case 'touchend':
18405            case 'pointerup':
18406            case 'MSPointerUp':
18407            case 'mouseup':
18408            case 'touchcancel':
18409            case 'pointercancel':
18410            case 'MSPointerCancel':
18411            case 'mousecancel':
18412                this._end(e);
18413                break;
18414            case 'orientationchange':
18415            case 'resize':
18416                this._resize();
18417                break;
18418            case 'transitionend':
18419            case 'webkitTransitionEnd':
18420            case 'oTransitionEnd':
18421            case 'MSTransitionEnd':
18422                this._transitionEnd(e);
18423                break;
18424            case 'wheel':
18425            case 'DOMMouseScroll':
18426            case 'mousewheel':
18427                this._wheel(e);
18428                break;
18429            case 'keydown':
18430                this._key(e);
18431                break;
18432            case 'click':
18433                if ( this.enabled && !e._constructed ) {
18434                    e.preventDefault();
18435                    e.stopPropagation();
18436                }
18437                break;
18438        }
18439    }
18440};
18441function createDefaultScrollbar (direction, interactive, type) {
18442    var scrollbar = document.createElement('div'),
18443        indicator = document.createElement('div');
18444
18445    if ( type === true ) {
18446        scrollbar.style.cssText = 'position:absolute;z-index:9999';
18447        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';
18448    }
18449
18450    indicator.className = 'iScrollIndicator';
18451
18452    if ( direction == 'h' ) {
18453        if ( type === true ) {
18454            scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
18455            indicator.style.height = '100%';
18456        }
18457        scrollbar.className = 'iScrollHorizontalScrollbar';
18458    } else {
18459        if ( type === true ) {
18460            scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
18461            indicator.style.width = '100%';
18462        }
18463        scrollbar.className = 'iScrollVerticalScrollbar';
18464    }
18465
18466    scrollbar.style.cssText += ';overflow:hidden';
18467
18468    if ( !interactive ) {
18469        scrollbar.style.pointerEvents = 'none';
18470    }
18471
18472    scrollbar.appendChild(indicator);
18473
18474    return scrollbar;
18475}
18476
18477function Indicator (scroller, options) {
18478    this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
18479    this.wrapperStyle = this.wrapper.style;
18480    this.indicator = this.wrapper.children[0];
18481    this.indicatorStyle = this.indicator.style;
18482    this.scroller = scroller;
18483
18484    this.options = {
18485        listenX: true,
18486        listenY: true,
18487        interactive: false,
18488        resize: true,
18489        defaultScrollbars: false,
18490        shrink: false,
18491        fade: false,
18492        speedRatioX: 0,
18493        speedRatioY: 0
18494    };
18495
18496    for ( var i in options ) {
18497        this.options[i] = options[i];
18498    }
18499
18500    this.sizeRatioX = 1;
18501    this.sizeRatioY = 1;
18502    this.maxPosX = 0;
18503    this.maxPosY = 0;
18504
18505    if ( this.options.interactive ) {
18506        if ( !this.options.disableTouch ) {
18507            utils.addEvent(this.indicator, 'touchstart', this);
18508            utils.addEvent(window, 'touchend', this);
18509        }
18510        if ( !this.options.disablePointer ) {
18511            utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
18512            utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
18513        }
18514        if ( !this.options.disableMouse ) {
18515            utils.addEvent(this.indicator, 'mousedown', this);
18516            utils.addEvent(window, 'mouseup', this);
18517        }
18518    }
18519
18520    if ( this.options.fade ) {
18521        this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
18522        var durationProp = utils.style.transitionDuration;
18523        if(!durationProp) {
18524            return;
18525        }
18526        this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
18527        // remove 0.0001ms
18528        var self = this;
18529        if(utils.isBadAndroid) {
18530            rAF(function() {
18531                if(self.wrapperStyle[durationProp] === '0.0001ms') {
18532                    self.wrapperStyle[durationProp] = '0s';
18533                }
18534            });
18535        }
18536        this.wrapperStyle.opacity = '0';
18537    }
18538}
18539
18540Indicator.prototype = {
18541    handleEvent: function (e) {
18542        switch ( e.type ) {
18543            case 'touchstart':
18544            case 'pointerdown':
18545            case 'MSPointerDown':
18546            case 'mousedown':
18547                this._start(e);
18548                break;
18549            case 'touchmove':
18550            case 'pointermove':
18551            case 'MSPointerMove':
18552            case 'mousemove':
18553                this._move(e);
18554                break;
18555            case 'touchend':
18556            case 'pointerup':
18557            case 'MSPointerUp':
18558            case 'mouseup':
18559            case 'touchcancel':
18560            case 'pointercancel':
18561            case 'MSPointerCancel':
18562            case 'mousecancel':
18563                this._end(e);
18564                break;
18565        }
18566    },
18567
18568    destroy: function () {
18569        if ( this.options.fadeScrollbars ) {
18570            clearTimeout(this.fadeTimeout);
18571            this.fadeTimeout = null;
18572        }
18573        if ( this.options.interactive ) {
18574            utils.removeEvent(this.indicator, 'touchstart', this);
18575            utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
18576            utils.removeEvent(this.indicator, 'mousedown', this);
18577
18578            utils.removeEvent(window, 'touchmove', this);
18579            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
18580            utils.removeEvent(window, 'mousemove', this);
18581
18582            utils.removeEvent(window, 'touchend', this);
18583            utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
18584            utils.removeEvent(window, 'mouseup', this);
18585        }
18586
18587        if ( this.options.defaultScrollbars ) {
18588            this.wrapper.parentNode.removeChild(this.wrapper);
18589        }
18590    },
18591
18592    _start: function (e) {
18593        var point = e.touches ? e.touches[0] : e;
18594
18595        e.preventDefault();
18596        e.stopPropagation();
18597
18598        this.transitionTime();
18599
18600        this.initiated = true;
18601        this.moved = false;
vendor: 9,615 bytes, lines 18602-18860
18602        this.lastPointX = point.pageX;
18603        this.lastPointY = point.pageY;
18604
18605        this.startTime  = utils.getTime();
18606
18607        if ( !this.options.disableTouch ) {
18608            utils.addEvent(window, 'touchmove', this);
18609        }
18610        if ( !this.options.disablePointer ) {
18611            utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
18612        }
18613        if ( !this.options.disableMouse ) {
18614            utils.addEvent(window, 'mousemove', this);
18615        }
18616
18617        this.scroller._execEvent('beforeScrollStart');
18618    },
18619
18620    _move: function (e) {
18621        var point = e.touches ? e.touches[0] : e,
18622            deltaX, deltaY,
18623            newX, newY,
18624            timestamp = utils.getTime();
18625
18626        if ( !this.moved ) {
18627            this.scroller._execEvent('scrollStart');
18628        }
18629
18630        this.moved = true;
18631
18632        deltaX = point.pageX - this.lastPointX;
18633        this.lastPointX = point.pageX;
18634
18635        deltaY = point.pageY - this.lastPointY;
18636        this.lastPointY = point.pageY;
18637
18638        newX = this.x + deltaX;
18639        newY = this.y + deltaY;
18640
18641        this._pos(newX, newY);
18642
18643// INSERT POINT: indicator._move
18644
18645        e.preventDefault();
18646        e.stopPropagation();
18647    },
18648
18649    _end: function (e) {
18650        if ( !this.initiated ) {
18651            return;
18652        }
18653
18654        this.initiated = false;
18655
18656        e.preventDefault();
18657        e.stopPropagation();
18658
18659        utils.removeEvent(window, 'touchmove', this);
18660        utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
18661        utils.removeEvent(window, 'mousemove', this);
18662
18663        if ( this.scroller.options.snap ) {
18664            var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
18665
18666            var time = this.options.snapSpeed || Math.max(
18667                    Math.max(
18668                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
18669                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
18670                    ), 300);
18671
18672            if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
18673                this.scroller.directionX = 0;
18674                this.scroller.directionY = 0;
18675                this.scroller.currentPage = snap;
18676                this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
18677            }
18678        }
18679
18680        if ( this.moved ) {
18681            this.scroller._execEvent('scrollEnd');
18682        }
18683    },
18684
18685    transitionTime: function (time) {
18686        time = time || 0;
18687        var durationProp = utils.style.transitionDuration;
18688        if(!durationProp) {
18689            return;
18690        }
18691
18692        this.indicatorStyle[durationProp] = time + 'ms';
18693
18694        if ( !time && utils.isBadAndroid ) {
18695            this.indicatorStyle[durationProp] = '0.0001ms';
18696            // remove 0.0001ms
18697            var self = this;
18698            rAF(function() {
18699                if(self.indicatorStyle[durationProp] === '0.0001ms') {
18700                    self.indicatorStyle[durationProp] = '0s';
18701                }
18702            });
18703        }
18704    },
18705
18706    transitionTimingFunction: function (easing) {
18707        this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
18708    },
18709
18710    refresh: function () {
18711        this.transitionTime();
18712
18713        if ( this.options.listenX && !this.options.listenY ) {
18714            this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
18715        } else if ( this.options.listenY && !this.options.listenX ) {
18716            this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
18717        } else {
18718            this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
18719        }
18720
18721        if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
18722            utils.addClass(this.wrapper, 'iScrollBothScrollbars');
18723            utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
18724
18725            if ( this.options.defaultScrollbars && this.options.customStyle ) {
18726                if ( this.options.listenX ) {
18727                    this.wrapper.style.right = '8px';
18728                } else {
18729                    this.wrapper.style.bottom = '8px';
18730                }
18731            }
18732        } else {
18733            utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
18734            utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
18735
18736            if ( this.options.defaultScrollbars && this.options.customStyle ) {
18737                if ( this.options.listenX ) {
18738                    this.wrapper.style.right = '2px';
18739                } else {
18740                    this.wrapper.style.bottom = '2px';
18741                }
18742            }
18743        }
18744
18745        var r = this.wrapper.offsetHeight;  // force refresh
18746
18747        if ( this.options.listenX ) {
18748            this.wrapperWidth = this.wrapper.clientWidth;
18749            if ( this.options.resize ) {
18750                this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
18751                this.indicatorStyle.width = this.indicatorWidth + 'px';
18752            } else {
18753                this.indicatorWidth = this.indicator.clientWidth;
18754            }
18755
18756            this.maxPosX = this.wrapperWidth - this.indicatorWidth;
18757
18758            if ( this.options.shrink == 'clip' ) {
18759                this.minBoundaryX = -this.indicatorWidth + 8;
18760                this.maxBoundaryX = this.wrapperWidth - 8;
18761            } else {
18762                this.minBoundaryX = 0;
18763                this.maxBoundaryX = this.maxPosX;
18764            }
18765
18766            this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
18767        }
18768
18769        if ( this.options.listenY ) {
18770            this.wrapperHeight = this.wrapper.clientHeight;
18771            if ( this.options.resize ) {
18772                this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
18773                this.indicatorStyle.height = this.indicatorHeight + 'px';
18774            } else {
18775                this.indicatorHeight = this.indicator.clientHeight;
18776            }
18777
18778            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
18779
18780            if ( this.options.shrink == 'clip' ) {
18781                this.minBoundaryY = -this.indicatorHeight + 8;
18782                this.maxBoundaryY = this.wrapperHeight - 8;
18783            } else {
18784                this.minBoundaryY = 0;
18785                this.maxBoundaryY = this.maxPosY;
18786            }
18787
18788            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
18789            this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
18790        }
18791
18792        this.updatePosition();
18793    },
18794
18795    updatePosition: function () {
18796        var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
18797            y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
18798
18799        if ( !this.options.ignoreBoundaries ) {
18800            if ( x < this.minBoundaryX ) {
18801                if ( this.options.shrink == 'scale' ) {
18802                    this.width = Math.max(this.indicatorWidth + x, 8);
18803                    this.indicatorStyle.width = this.width + 'px';
18804                }
18805                x = this.minBoundaryX;
18806            } else if ( x > this.maxBoundaryX ) {
18807                if ( this.options.shrink == 'scale' ) {
18808                    this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
18809                    this.indicatorStyle.width = this.width + 'px';
18810                    x = this.maxPosX + this.indicatorWidth - this.width;
18811                } else {
18812                    x = this.maxBoundaryX;
18813                }
18814            } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
18815                this.width = this.indicatorWidth;
18816                this.indicatorStyle.width = this.width + 'px';
18817            }
18818
18819            if ( y < this.minBoundaryY ) {
18820                if ( this.options.shrink == 'scale' ) {
18821                    this.height = Math.max(this.indicatorHeight + y * 3, 8);
18822                    this.indicatorStyle.height = this.height + 'px';
18823                }
18824                y = this.minBoundaryY;
18825            } else if ( y > this.maxBoundaryY ) {
18826                if ( this.options.shrink == 'scale' ) {
18827                    this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
18828                    this.indicatorStyle.height = this.height + 'px';
18829                    y = this.maxPosY + this.indicatorHeight - this.height;
18830                } else {
18831                    y = this.maxBoundaryY;
18832                }
18833            } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
18834                this.height = this.indicatorHeight;
18835                this.indicatorStyle.height = this.height + 'px';
18836            }
18837        }
18838
18839        this.x = x;
18840        this.y = y;
18841
18842        if ( this.scroller.options.useTransform ) {
18843            this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
18844        } else {
18845            this.indicatorStyle.left = x + 'px';
18846            this.indicatorStyle.top = y + 'px';
18847        }
18848    },
18849
18850    _pos: function (x, y) {
18851        if ( x < 0 ) {
18852            x = 0;
18853        } else if ( x > this.maxPosX ) {
18854            x = this.maxPosX;
18855        }
18856
18857        if ( y < 0 ) {
18858            y = 0;
18859        } else if ( y > this.maxPosY ) {
18860            y = this.maxPosY;
18861        }
18862
18863        x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
18864        y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
18865
18866        this.scroller.scrollTo(x, y);
18867    },
18868
18869    fade: function (val, hold) {
18870        if ( hold && !this.visible ) {
18871            return;
18872        }
18873
18874        clearTimeout(this.fadeTimeout);
18875        this.fadeTimeout = null;
18876
18877        var time = val ? 250 : 500,
18878            delay = val ? 0 : 300;
18879
18880        val = val ? '1' : '0';
18881
18882        this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
18883
18884        this.fadeTimeout = setTimeout((function (val) {
18885            this.wrapperStyle.opacity = val;
18886            this.visible = +val;
18887        }).bind(this, val), delay);
18888    }
18889};
18890
18891IScroll.utils = utils;
18892
18893if ( typeof module != 'undefined' && module.exports ) {
18894    module.exports = IScroll;
18895} else if ( typeof define == 'function' && define.amd ) {
18896        define( function () { return IScroll; } );
18897} else {
18898    window.IScroll = IScroll;
18899}
18900
18901})(window, document, Math);
18902/*!
18903 * fullPage 2.9.4
18904 * https://github.com/alvarotrigo/fullPage.js
18905 * @license MIT licensed
18906 *
18907 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
18908 */
18909(function(global, factory) {
18910    'use strict';
18911    if (typeof define === 'function' && define.amd) {
18912        define(['jquery'], function($) {
18913          return factory($, global, global.document, global.Math);
18914        });
18915    } else if (typeof exports === "object" && exports) {
18916        module.exports = factory(require('jquery'), global, global.document, global.Math);
18917    } else {
18918        factory(jQuery, global, global.document, global.Math);
18919    }
18920})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
18921    'use strict';
18922
18923    // keeping central set of classnames and selectors
18924    var WRAPPER =               'fullpage-wrapper';
18925    var WRAPPER_SEL =           '.' + WRAPPER;
18926
18927    // slimscroll
18928    var SCROLLABLE =            'fp-scrollable';
18929    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
18930
18931    // util
18932    var RESPONSIVE =            'fp-responsive';
18933    var NO_TRANSITION =         'fp-notransition';
18934    var DESTROYED =             'fp-destroyed';
18935    var ENABLED =               'fp-enabled';
18936    var VIEWING_PREFIX =        'fp-viewing';
18937    var ACTIVE =                'active';
18938    var ACTIVE_SEL =            '.' + ACTIVE;
18939    var COMPLETELY =            'fp-completely';
18940    var COMPLETELY_SEL =        '.' + COMPLETELY;
18941
18942    // section
18943    var SECTION_DEFAULT_SEL =   '.section';
18944    var SECTION =               'fp-section';
18945    var SECTION_SEL =           '.' + SECTION;
18946    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
18947    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
18948    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
18949    var TABLE_CELL =            'fp-tableCell';
18950    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
18951    var AUTO_HEIGHT =           'fp-auto-height';
18952    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
18953    var NORMAL_SCROLL =         'fp-normal-scroll';
18954    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
18955
18956    // section nav
18957    var SECTION_NAV =           'fp-nav';
18958    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
18959    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
18960    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
18961    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
18962
18963    // slide
18964    var SLIDE_DEFAULT_SEL =     '.slide';
18965    var SLIDE =                 'fp-slide';
18966    var SLIDE_SEL =             '.' + SLIDE;
18967    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
18968    var SLIDES_WRAPPER =        'fp-slides';
18969    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
18970    var SLIDES_CONTAINER =      'fp-slidesContainer';
18971    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
18972    var TABLE =                 'fp-table';
18973
18974    // slide nav
18975    var SLIDES_NAV =            'fp-slidesNav';
18976    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
18977    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
18978    var SLIDES_ARROW =          'fp-controlArrow';
18979    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
18980    var SLIDES_PREV =           'fp-prev';
18981    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
18982    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
18983    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
18984    var SLIDES_NEXT =           'fp-next';
18985    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
18986    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
18987    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
18988
18989    var $window = $(window);
18990    var $document = $(document);
18991
18992    // Default options for iScroll.js used when using scrollOverflow
18993    var iscrollOptions = {
18994        scrollbars: true,
18995        mouseWheel: true,
18996        hideScrollbars: false,
18997        fadeScrollbars: false,
18998        disableMouse: true,
18999        interactiveScrollbars: true,
19000        bounce: false,
19001    };
19002
19003    $.fn.fullpage = function(options) {
19004        //only once my friend!
19005        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
19006
19007        // common jQuery objects
19008        var $htmlBody = $('html, body');
19009        var $body = $('body');
19010
19011        var FP = $.fn.fullpage;
19012
19013        // Creating some defaults, extending them with any options that were provided
19014        options = $.extend({
19015            //navigation
19016            menu: false,
19017            anchors:[],
19018            lockAnchors: false,
19019            navigation: false,
19020            navigationPosition: 'right',
19021            navigationTooltips: [],
19022            showActiveTooltip: false,
19023            slidesNavigation: false,
19024            slidesNavPosition: 'bottom',
19025            scrollBar: false,
19026            hybrid: false,
19027
19028            //scrolling
19029            css3: true,
19030            scrollingSpeed: 700,
19031            autoScrolling: true,
19032            fitToSection: true,
19033            fitToSectionDelay: 1000,
19034            easing: 'easeInOutCubic',
19035            easingcss3: 'ease',
19036            loopBottom: false,
19037            loopTop: false,
19038            loopHorizontal: true,
19039            continuousVertical: false,
19040            continuousHorizontal: false,
19041            scrollHorizontally: false,
19042            interlockedSlides: false,
19043            dragAndMove: false,
19044            offsetSections: false,
19045            resetSliders: false,
19046            fadingEffect: false,
19047            normalScrollElements: null,
19048            scrollOverflow: false,
19049            scrollOverflowReset: false,
19050            scrollOverflowHandler: iscrollHandler,
19051            scrollOverflowOptions: null,
19052            touchSensitivity: 5,
19053            normalScrollElementTouchThreshold: 5,
19054            bigSectionsDestination: null,
19055
19056            //Accessibility
19057            keyboardScrolling: true,
19058            animateAnchor: true,
19059            recordHistory: true,
19060
19061            //design
19062            controlArrows: true,
19063            controlArrowColor: '#fff',
19064            verticalCentered: true,
19065            sectionsColor : [],
19066            paddingTop: 0,
19067            paddingBottom: 0,
19068            fixedElements: null,
19069            responsive: 0, //backwards compabitility with responsiveWiddth
19070            responsiveWidth: 0,
19071            responsiveHeight: 0,
19072            responsiveSlides: false,
19073            parallax: false,
19074            parallaxOptions: {
19075                type: 'reveal',
19076                percentage: 62,
19077                property: 'translate'
19078            },
19079
19080            //Custom selectors
19081            sectionSelector: SECTION_DEFAULT_SEL,
19082            slideSelector: SLIDE_DEFAULT_SEL,
19083
19084            //events
19085            afterLoad: null,
19086            onLeave: null,
19087            afterRender: null,
19088            afterResize: null,
19089            afterReBuild: null,
19090            afterSlideLoad: null,
19091            onSlideLeave: null,
19092            afterResponsive: null,
19093
19094            lazyLoading: true
19095        }, options);
19096
19097        //flag to avoid very fast sliding for landscape sliders
19098        var slideMoving = false;
19099
19100        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
19101        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
19102        var container = $(this);
19103        var windowsHeight = $window.height();
19104        var isResizing = false;
19105        var isWindowFocused = true;
19106        var lastScrolledDestiny;
19107        var lastScrolledSlide;
19108        var canScroll = true;
19109        var scrollings = [];
19110        var controlPressed;
19111        var startingSection;
19112        var isScrollAllowed = {};
19113        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
19114        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
19115        var MSPointer = getMSPointer();
19116        var events = {
19117            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
19118            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
19119        };
19120
19121        //timeouts
19122        var resizeId;
19123        var afterSectionLoadsId;
19124        var afterSlideLoadsId;
19125        var scrollId;
19126        var scrollId2;
19127        var keydownId;
19128        var originals = $.extend(true, {}, options); //deep copy
19129
19130        //Uncode addition
19131        var $masthead = $('#masthead');
19132        var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
19133        var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
19134        var bodyBorder = UNCODE.bodyBorder;
19135        var adminBarHeight = UNCODE.adminBarHeight;
19136
19137        displayWarnings();
19138
19139        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
19140        iscrollOptions.click = isTouch; // see #2035
19141
19142        //extending iScroll options with the user custom ones
19143        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
19144
19145        //easeInOutCubic animation included in the plugin
19146        $.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;}});
19147
19148        /**
19149        * Sets the autoScroll option.
19150        * It changes the scroll bar visibility and the history of the site as a result.
19151        */
19152        function setAutoScrolling(value, type){
19153            //removing the transformation
19154            if(!value){
19155                silentScroll(0);
19156            }
19157
19158            setVariableState('autoScrolling', value, type);
19159
19160            var element = $(SECTION_ACTIVE_SEL);
19161
19162            if(options.autoScrolling && !options.scrollBar){
19163                $htmlBody.css({
19164                    'overflow' : 'hidden !important',
19165                    'height' : '100%'
19166                });
19167
19168                //Uncode addition
19169                //setRecordHistory(originals.recordHistory, 'internal');
19170
19171                //for IE touch devices
19172                container.css({
19173                    '-ms-touch-action': 'none',
19174                    'touch-action': 'none'
19175                });
19176
19177                if(element.length){
19178                    //moving the container up
19179                    silentScroll(element.position().top);
19180                }
19181
19182            }else{
19183                $htmlBody.css({
19184                    'overflow' : 'visible !important',
19185                    'height' : 'initial'
19186                });
19187
19188                //Uncode addition
19189                //setRecordHistory(false, 'internal');
19190
19191                //for IE touch devices
19192                container.css({
19193                    '-ms-touch-action': '',
19194                    'touch-action': ''
19195                });
19196
19197                //scrolling the page to the section with no animation
19198                if (element.length) {
19199                    $htmlBody.scrollTop(element.position().top);
19200                }
19201            }
19202        }
19203
19204        /**
19205        * Defines wheter to record the history for each hash change in the URL.
19206        */
19207        function setRecordHistory(value, type){
19208            setVariableState('recordHistory', value, type);
19209        }
19210
19211        /**
19212        * Defines the scrolling speed
19213        */
19214        function setScrollingSpeed(value, type){
19215            setVariableState('scrollingSpeed', value, type);
19216        }
19217
19218        /**
19219        * Sets fitToSection
19220        */
19221        function setFitToSection(value, type){
19222            setVariableState('fitToSection', value, type);
19223        }
19224
19225        /**
19226        * Sets lockAnchors
19227        */
19228        function setLockAnchors(value){
19229            options.lockAnchors = value;
19230        }
19231
19232        /**
19233        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
19234        */
19235        function setMouseWheelScrolling(value){
19236            if(value){
19237                addMouseWheelHandler();
19238                addMiddleWheelHandler();
19239            }else{
19240                removeMouseWheelHandler();
19241                removeMiddleWheelHandler();
19242            }
19243        }
19244
19245        /**
19246        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
19247        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
19248        *
19249        * @param directions string containing the direction or directions separated by comma.
19250        */
19251        function setAllowScrolling(value, directions){
19252            if(typeof directions !== 'undefined'){
19253                directions = directions.replace(/ /g,'').split(',');
19254
19255                $.each(directions, function (index, direction){
19256                    setIsScrollAllowed(value, direction, 'm');
19257                });
19258            }
19259            else if(value){
19260                setMouseWheelScrolling(true);
19261                addTouchHandler();
19262            }else{
19263                setMouseWheelScrolling(false);
19264                removeTouchHandler();
19265            }
19266        }
19267
19268        /**
19269        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
19270        */
19271        function setKeyboardScrolling(value, directions){
19272            if(typeof directions !== 'undefined'){
19273                directions = directions.replace(/ /g,'').split(',');
19274
19275                $.each(directions, function (index, direction){
19276                    setIsScrollAllowed(value, direction, 'k');
19277                });
19278            }else{
19279                options.keyboardScrolling = value;
19280            }
19281        }
19282
19283        /**
19284        * Moves the page up one section.
19285        */
19286        function moveSectionUp(){
19287            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
19288
19289            //looping to the bottom if there's no more sections above
19290            if (!prev.length && (options.loopTop || options.continuousVertical)) {
19291                prev = $(SECTION_SEL).last();
19292            }
19293
19294            if (prev.length) {
19295                scrollPage(prev, null, true);
19296            }
19297        }
19298
19299        /**
19300        * Moves the page down one section.
19301        */
19302        function moveSectionDown(){
19303            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
19304
19305            //looping to the top if there's no more sections below
19306            if(!next.length &&
19307                (options.loopBottom || options.continuousVertical)){
19308                next = $(SECTION_SEL).first();
19309            }
19310
19311            if(next.length){
19312                scrollPage(next, null, false);
19313            }
19314        }
19315
19316        /**
19317        * Moves the page to the given section and slide with no animation.
19318        * Anchors or index positions can be used as params.
19319        */
19320        function silentMoveTo(sectionAnchor, slideAnchor){
19321            setScrollingSpeed (0, 'internal');
19322            moveTo(sectionAnchor, slideAnchor);
19323            setScrollingSpeed (originals.scrollingSpeed, 'internal');
19324        }
19325
19326        /**
19327        * Moves the page to the given section and slide.
19328        * Anchors or index positions can be used as params.
19329        */
19330        function moveTo(sectionAnchor, slideAnchor){
19331            var destiny = getSectionByAnchor(sectionAnchor);
19332
19333            if (typeof slideAnchor !== 'undefined'){
19334                scrollPageAndSlide(sectionAnchor, slideAnchor);
19335            }else if(destiny.length > 0){
19336                scrollPage(destiny);
19337            }
19338        }
19339
19340        /**
19341        * Slides right the slider of the active section.
19342        * Optional `section` param.
19343        */
19344        function moveSlideRight(section){
19345            moveSlide('right', section);
19346        }
19347
19348        /**
19349        * Slides left the slider of the active section.
19350        * Optional `section` param.
19351        */
19352        function moveSlideLeft(section){
19353            moveSlide('left', section);
19354        }
19355
19356        /**
19357         * When resizing is finished, we adjust the slides sizes and positions
19358         */
19359        function reBuild(resizing){
19360            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
19361
19362            isResizing = true;
19363
19364            windowsHeight = $window.height();  //updating global var
19365
19366            $(SECTION_SEL).each(function(){
19367                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
19368                var slides = $(this).find(SLIDE_SEL);
19369
19370                //adjusting the height of the table-cell for IE and Firefox
19371                if(options.verticalCentered){
19372                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
19373                }
19374
19375                $(this).css('height', windowsHeight + 'px');
19376
19377                //resizing the scrolling divs
19378                if(options.scrollOverflow){
19379                    if(slides.length){
19380                        slides.each(function(){
19381                            createScrollBar($(this));
19382                        });
19383                    }else{
19384                        createScrollBar($(this));
19385                    }
19386                }
19387
19388                //adjusting the position fo the FULL WIDTH slides...
19389                if (slides.length > 1) {
19390                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
19391                }
19392            });
19393
19394            var activeSection = $(SECTION_ACTIVE_SEL);
19395            var sectionIndex = activeSection.index(SECTION_SEL);
19396
19397            //isn't it the first section?
19398            if(sectionIndex){
19399                //adjusting the position for the current section
19400                silentMoveTo(sectionIndex + 1);
19401            }
19402
19403            isResizing = false;
19404            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
19405            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
19406        }
19407
19408        /**
19409        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
19410        * are smaller than the set limit values.
19411        */
19412        function setResponsive(active){
19413            var isResponsive = $body.hasClass(RESPONSIVE);
19414
19415            if(active){
19416                if(!isResponsive){
19417                    setAutoScrolling(false, 'internal');
19418                    setFitToSection(false, 'internal');
19419                    $(SECTION_NAV_SEL).hide();
19420                    $body.addClass(RESPONSIVE);
19421                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
19422                }
19423            }
19424            else if(isResponsive){
19425                setAutoScrolling(originals.autoScrolling, 'internal');
19426                setFitToSection(originals.autoScrolling, 'internal');
19427                $(SECTION_NAV_SEL).show();
19428                $body.removeClass(RESPONSIVE);
19429                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
19430            }
19431        }
19432
19433        if($(this).length){
19434            //public functions
19435            FP.setAutoScrolling = setAutoScrolling;
19436            FP.setRecordHistory = setRecordHistory;
19437            FP.setScrollingSpeed = setScrollingSpeed;
19438            FP.setFitToSection = setFitToSection;
19439            FP.setLockAnchors = setLockAnchors;
19440            FP.setMouseWheelScrolling = setMouseWheelScrolling;
19441            FP.setAllowScrolling = setAllowScrolling;
19442            FP.setKeyboardScrolling = setKeyboardScrolling;
19443            FP.moveSectionUp = moveSectionUp;
19444            FP.moveSectionDown = moveSectionDown;
19445            FP.silentMoveTo = silentMoveTo;
19446            FP.moveTo = moveTo;
19447            FP.moveSlideRight = moveSlideRight;
19448            FP.moveSlideLeft = moveSlideLeft;
19449            FP.fitToSection = fitToSection;
19450            FP.reBuild = reBuild;
19451            FP.setResponsive = setResponsive;
19452            FP.destroy = destroy;
19453
19454            init();
19455
19456            bindEvents();
19457        }
19458
19459        function init(){
19460            //if css3 is not supported, it will use jQuery animations
19461            if(options.css3){
19462                options.css3 = support3d();
19463            }
19464
19465            options.scrollBar = options.scrollBar || options.hybrid;
19466
19467            setOptionsFromDOM();
19468            prepareDom();
19469            setAllowScrolling(true);
19470            setAutoScrolling(options.autoScrolling, 'internal');
19471            responsive();
19472
19473            //setting the class for the body element
19474            setBodyClass();
19475
19476            //Uncode addition
19477            // if(document.readyState === 'complete'){
19478            //     scrollToAnchor();
19479            // }
19480            // $window.on('load', scrollToAnchor);
19481        }
19482
19483        function bindEvents(){
19484            $window
19485                //when scrolling...
19486                //.on('scroll', scrollHandler)
19487
19488                //detecting any change on the URL to scroll to the given anchor link
19489                //(a way to detect back history button as we play with the hashes on the URL)
19490                .on('hashchange', hashChangeHandler)
19491
19492                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
19493                .blur(blurHandler)
19494
19495                //when resizing the site, we adjust the heights of the sections, slimScroll...
19496                .resize(resizeHandler);
19497
19498            $document
19499                //Sliding with arrow keys, both, vertical and horizontal
19500                .keydown(keydownHandler)
19501
19502                //to prevent scrolling while zooming
19503                .keyup(keyUpHandler)
19504
19505                //Scrolls to the section when clicking the navigation bullet
19506                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
19507
19508                //Scrolls the slider to the given slide destination for the given section
19509                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
19510
19511                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
19512
19513            //Scrolling horizontally when clicking on the slider controls.
19514            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
19515
19516            /**
19517            * Applying normalScroll elements.
19518            * Ignoring the scrolls over the specified selectors.
19519            */
19520            if(options.normalScrollElements){
19521                $document.on('mouseenter', options.normalScrollElements, function () {
19522                    setMouseWheelScrolling(false);
19523                });
19524
19525                $document.on('mouseleave', options.normalScrollElements, function(){
19526                    setMouseWheelScrolling(true);
19527                });
19528            }
19529        }
19530
19531        /**
19532        * Setting options from DOM elements if they are not provided.
19533        */
19534        function setOptionsFromDOM(){
19535            var sections = container.find(options.sectionSelector);
19536
19537            //no anchors option? Checking for them in the DOM attributes
19538            if(!options.anchors.length){
19539                options.anchors = sections.filter('[data-anchor]').map(function(){
19540                    return $(this).data('anchor').toString();
19541                }).get();
19542            }
19543
19544            //no tooltips option? Checking for them in the DOM attributes
19545            if(!options.navigationTooltips.length){
19546                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
19547                    return $(this).data('tooltip').toString();
19548                }).get();
19549            }
19550        }
19551
19552        /**
19553        * Works over the DOM structure to set it up for the current fullpage options.
19554        */
19555        function prepareDom(){
19556            container.css({
19557                'height': '100%',
19558                'position': 'relative'
19559            });
19560
19561            //adding a class to recognize the container internally in the code
19562            container.addClass(WRAPPER);
19563            $('html').addClass(ENABLED);
19564
19565            windowsHeight = $window.height();
19566
19567            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
19568
19569            addInternalSelectors();
19570
19571             //styling the sections / slides / menu
19572            $(SECTION_SEL).each(function(index){
19573                var section = $(this);
19574                var slides = section.find(SLIDE_SEL);
19575                var numSlides = slides.length;
19576
19577                styleSection(section, index);
19578                styleMenu(section, index);
19579
19580                // if there's any slide
19581                if (numSlides > 0) {
19582                    styleSlides(section, slides, numSlides);
19583                }else{
19584                    if(options.verticalCentered){
19585                        addTableClass(section);
19586                    }
19587                }
19588            });
19589
19590            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
19591            if(options.fixedElements && options.css3){
19592                $(options.fixedElements).appendTo($body);
19593            }
19594
19595            //vertical centered of the navigation + active bullet
19596            if(options.navigation){
19597                addVerticalNavigation();
19598            }
19599
19600            enableYoutubeAPI();
19601
19602            if(options.scrollOverflow){
19603                if(document.readyState === 'complete'){
19604                    createScrollBarHandler();
19605                }
19606                //after DOM and images are loaded
19607                $window.on('load', createScrollBarHandler);
19608            }else{
19609                afterRenderActions();
19610            }
19611        }
19612
19613        /**
19614        * Styles the horizontal slides for a section.
19615        */
19616        function styleSlides(section, slides, numSlides){
19617            var sliderWidth = numSlides * 100;
19618            var slideWidth = 100 / numSlides;
19619
19620            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
19621            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
19622
19623            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
19624
19625            if(numSlides > 1){
19626                if(options.controlArrows){
19627                    createSlideArrows(section);
19628                }
19629
19630                if(options.slidesNavigation){
19631                    addSlidesNavigation(section, numSlides);
19632                }
19633            }
19634
19635            slides.each(function(index) {
19636                $(this).css('width', slideWidth + '%');
19637
19638                if(options.verticalCentered){
19639                    addTableClass($(this));
19640                }
19641            });
19642
19643            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
19644
19645            //if the slide won't be an starting point, the default will be the first one
19646            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
19646ide by default.
19647            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
19648                silentLandscapeScroll(startingSlide, 'internal');
19649            }else{
19650                slides.eq(0).addClass(ACTIVE);
19651            }
19652        }
19653
19654        /**
19655        * Styling vertical sections
19656        */
19657        function styleSection(section, index){
19658            //if no active section is defined, the 1st one will be the default one
19659            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
19660                section.addClass(ACTIVE);
19661            }
19662            startingSection = $(SECTION_ACTIVE_SEL);
19663
19664            section.css('height', windowsHeight + 'px');
19665
19666            if(options.paddingTop){
19667                section.css('padding-top', options.paddingTop);
19668            }
19669
19670            if(options.paddingBottom){
19671                section.css('padding-bottom', options.paddingBottom);
19672            }
19673
19674            if (typeof options.sectionsColor[index] !==  'undefined') {
19675                section.css('background-color', options.sectionsColor[index]);
19676            }
19677
19678            if (typeof options.anchors[index] !== 'undefined') {
19679                section.attr('data-anchor', options.anchors[index]);
19680            }
19681        }
19682
19683        /**
19684        * Sets the data-anchor attributes to the menu elements and activates the current one.
19685        */
19686        function styleMenu(section, index){
19687            if (typeof options.anchors[index] !== 'undefined') {
19688                //activating the menu / nav element on load
19689                if(section.hasClass(ACTIVE)){
19690                    activateMenuAndNav(options.anchors[index], index);
19691                }
19692            }
19693
19694            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
19695            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
19696                $(options.menu).appendTo($body);
19697            }
19698        }
19699
19700        /**
19701        * Adds internal classes to be able to provide customizable selectors
19702        * keeping the link with the style sheet.
19703        */
19704        function addInternalSelectors(){
19705            container.find(options.sectionSelector).addClass(SECTION);
19706            container.find(options.slideSelector).addClass(SLIDE);
19707        }
19708
19709        /**
19710        * Creates the control arrows for the given section
19711        */
19712        function createSlideArrows(section){
19713            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
19714
19715            if(options.controlArrowColor!='#fff'){
19716                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
19717                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
19718            }
19719
19720            if(!options.loopHorizontal){
19721                section.find(SLIDES_ARROW_PREV_SEL).hide();
19722            }
19723        }
19724
19725        /**
19726        * Creates a vertical navigation bar.
19727        */
19728        function addVerticalNavigation(){
19729            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
19730            var nav = $(SECTION_NAV_SEL);
19731
19732            nav.addClass(function() {
19733                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
19734            });
19735
19736            for (var i = 0; i < $(SECTION_SEL).length; i++) {
19737                var link = '';
19738                if (options.anchors.length) {
19739                    link = options.anchors[i];
19740                }
19741
19742                var li = '<li><a href="#' + link + '"><span></span></a>';
19743
19744                // Only add tooltip if needed (defined by user)
19745                var tooltip = options.navigationTooltips[i];
19746
19747                if (typeof tooltip !== 'undefined' && tooltip !== '') {
19748                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
19749                }
19750
19751                li += '</li>';
19752
19753                nav.find('ul').append(li);
19754            }
19755
19756            //centering it vertically
19757            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
19758
19759            //activating the current active section
19760            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
19761        }
19762
19763        /**
19764        * Creates the slim scroll scrollbar for the sections and slides inside them.
19765        */
19766        function createScrollBarHandler(){
19767            $(SECTION_SEL).each(function(){
19768                var slides = $(this).find(SLIDE_SEL);
19769
19770                if(slides.length){
19771                    slides.each(function(){
19772                        createScrollBar($(this));
19773                    });
19774                }else{
19775                    createScrollBar($(this));
19776                }
19777
19778            });
19779            afterRenderActions();
19780        }
19781
19782        /*
19783        * Enables the Youtube videos API so we can control their flow if necessary.
19784        */
19785        function enableYoutubeAPI(){
19786            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
19787                addURLParam($(this), 'enablejsapi=1');
19788            });
19789        }
19790
19791        /**
19792        * Adds a new parameter and its value to the `src` of a given element
19793        */
19794        function addURLParam(element, newParam){
19795            var originalSrc = element.attr('src');
19796            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
19797        }
19798
19799        /*
19800        * Returns the prefix sign to use for a new parameter in an existen URL.
19801        *
19802        * @return {String}  ? | &
19803        */
19804        function getUrlParamSign(url){
19805            return ( !/\?/.test( url ) ) ? '?' : '&';
19806        }
19807
19808        /**
19809        * Actions and callbacks to fire afterRender
19810        */
19811        function afterRenderActions(){
19812            var section = $(SECTION_ACTIVE_SEL);
19813
19814            section.addClass(COMPLETELY);
19815
19816            if(options.scrollOverflowHandler.afterRender){
19817                options.scrollOverflowHandler.afterRender(section);
19818            }
19819            lazyLoad(section);
19820            playMedia(section);
19821            options.scrollOverflowHandler.afterLoad();
19822            
19823            if(isDestinyTheStartingSection()){
19824                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
19825            }
19826
19827            $.isFunction( options.afterRender ) && options.afterRender.call(container);
19828        }
19829
19830        /**
19831        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
19832        */
19833        function isDestinyTheStartingSection(){
19834            var anchors =  window.location.hash.replace('#', '').split('/');
19835            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
19836    
19837            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
19838        }
19839
19840
19841        var isScrolling = false;
19842        var lastScroll = 0;
19843
19844        //when scrolling...
19845        function scrollHandler(){
19846            var currentSection;
19847
19848            if(!options.autoScrolling || options.scrollBar){
19849                var currentScroll = $window.scrollTop();
19850                var scrollDirection = getScrollDirection(currentScroll);
19851                var visibleSectionIndex = 0;
19852                var screen_mid = currentScroll + ($window.height() / 2.0);
19853                var isAtBottom = $body.height() - $window.height() === currentScroll;
19854                var sections =  document.querySelectorAll(SECTION_SEL);
19855
19856                //when using `auto-height` for a small last section it won't be centered in the viewport
19857                if(isAtBottom){
19858                    visibleSectionIndex = sections.length - 1;
19859                }
19860                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
19861                else if(!currentScroll){
19862                    visibleSectionIndex = 0;
19863                }
19864
19865                //taking the section which is showing more content in the viewport
19866                else{
19867                    for (var i = 0; i < sections.length; ++i) {
19868                        var section = sections[i];
19869
19870                        // Pick the the last section which passes the middle line of the screen.
19871                        if (section.offsetTop <= screen_mid)
19872                        {
19873                            visibleSectionIndex = i;
19874                        }
19875                    }
19876                }
19877
19878                if(isCompletelyInViewPort(scrollDirection)){
19879                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
19880                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
19881                    }
19882                }
19883
19884                //geting the last one, the current one on the screen
19885                currentSection = $(sections).eq(visibleSectionIndex);
19886
19887                //setting the visible section as active when manually scrolling
19888                //executing only once the first time we reach the section
19889                if(!currentSection.hasClass(ACTIVE)){
19890                    isScrolling = true;
19891                    var leavingSection = $(SECTION_ACTIVE_SEL);
19892                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
19893                    var yMovement = getYmovement(currentSection);
19894                    var anchorLink  = currentSection.data('anchor');
19895                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
19896                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
19897                    var slideIndex;
19898                    var slideAnchorLink;
19899
19900                    if(activeSlide.length){
19901                        slideAnchorLink = activeSlide.data('anchor');
19902                        slideIndex = activeSlide.index();
19903                    }
19904
19905                    if(canScroll){
19906                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
19907
19908                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
19909                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
19910
19911                        stopMedia(leavingSection);
19912                        lazyLoad(currentSection);
19913                        playMedia(currentSection);
19914
19915                        activateMenuAndNav(anchorLink, sectionIndex - 1);
19916
19917                        if(options.anchors.length){
19918                            //needed to enter in hashChange event when using the menu with anchor links
19919                            lastScrolledDestiny = anchorLink;
19920                        }
19921                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
19922                    }
19923
19924                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
19925                    clearTimeout(scrollId);
19926                    scrollId = setTimeout(function(){
19927                        isScrolling = false;
19928                    }, 100);
19929                }
19930
19931                if(options.fitToSection){
19932                    //for the auto adjust of the viewport to fit a whole section
19933                    clearTimeout(scrollId2);
19934
19935                    scrollId2 = setTimeout(function(){
19936                        //checking it again in case it changed during the delay
19937                        if(options.fitToSection){
19938                            fitToSection();
19939                        }
19940                    }, options.fitToSectionDelay);
19941                }
19942            }
19943        }
19944
19945        /**
19946        * Fits the site to the nearest active section
19947        */
19948        function fitToSection(){
19949            //checking fitToSection again in case it was set to false before the timeout delay
19950            if(canScroll){
19951                //allows to scroll to an active section and
19952                //if the section is already active, we prevent firing callbacks
19953                isResizing = true;
19954
19955                scrollPage($(SECTION_ACTIVE_SEL));
19956                isResizing = false;
19957            }
19958        }
19959
19960        /**
19961        * Determines whether the active section has seen in its whole or not.
19962        */
19963        function isCompletelyInViewPort(movement){
19964            var top = $(SECTION_ACTIVE_SEL).position().top;
19965            var bottom = top + $window.height();
19966
19967            if(movement == 'up'){
19968                return bottom >= ($window.scrollTop() + $window.height());
19969            }
19970            return top <= $window.scrollTop();
19971        }
19972
19973        /**
19974        * Gets the directon of the the scrolling fired by the scroll event.
19975        */
19976        function getScrollDirection(currentScroll){
19977            var direction = currentScroll > lastScroll ? 'down' : 'up';
19978
19979            lastScroll = currentScroll;
19980
19981            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
19982            previousDestTop = currentScroll;
19983
19984            return direction;
19985        }
19986
19987        /**
19988        * Determines the way of scrolling up or down:
19989        * by 'automatically' scrolling a section or by using the default and normal scrolling.
19990        */
19991        function scrolling(type, scrollable){
19992            if (!isScrollAllowed.m[type]){
19993                return;
19994            }
19995            var check = (type === 'down') ? 'bottom' : 'top';
19996            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
19997
19998            if(scrollable.length > 0 ){
19999                //is the scrollbar at the start/end of the scroll?
20000                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
20001                    scrollSection();
20002                }else{
20003                    return true;
20004                }
20005            }else{
20006                // moved up/down
20007                scrollSection();
20008            }
20009        }
20010
20011        /*
20012        * Preventing bouncing in iOS #2285
20013        */
20014        function preventBouncing(event){
20015            var e = event.originalEvent;
20016            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e)){
20017                //preventing the easing on iOS devices
20018                event.preventDefault();
20019            }
20020        }
20021
20022        var touchStartY = 0;
20023        var touchStartX = 0;
20024        var touchEndY = 0;
20025        var touchEndX = 0;
20026
20027        /* Detecting touch events
20028
20029        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
20030        * This way, the touchstart and the touch moves shows an small difference between them which is the
20031        * used one to determine the direction.
20032        */
20033        function touchMoveHandler(event){
20034            var e = event.originalEvent;
20035            var activeSection = $(e.target).closest(SECTION_SEL);
20036
20037            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
20038            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
20039
20040                if(options.autoScrolling){
20041                    //preventing the easing on iOS devices
20042                    event.preventDefault();
20043                }
20044
20045                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
20046                var touchEvents = getEventsPage(e);
20047
20048                touchEndY = touchEvents.y;
20049                touchEndX = touchEvents.x;
20050
20051                //if movement in the X axys is greater than in the Y and the currect section has slides...
20052                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
20053
20054                    //is the movement greater than the minimum resistance to scroll?
20055                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
20056                        if (touchStartX > touchEndX) {
20057                            if(isScrollAllowed.m.right){
20058                                moveSlideRight(activeSection); //next
20059                            }
20060                        } else {
20061                            if(isScrollAllowed.m.left){
20062                                moveSlideLeft(activeSection); //prev
20063                            }
20064                        }
20065                    }
20066                }
20067
20068                //vertical scrolling (only when autoScrolling is enabled)
20069                else if(options.autoScrolling && canScroll){
20070
20071                    //is the movement greater than the minimum resistance to scroll?
20072                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
20073                        if (touchStartY > touchEndY) {
20074                            scrolling('down', scrollable);
20075                        } else if (touchEndY > touchStartY) {
20076                            scrolling('up', scrollable);
20077                        }
20078                    }
20079                }
20080            }
20081        }
20082
20083        /**
20084         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
20085         * Currently works well for iOS - Android might need some testing
20086         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
20087         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
20088         * @return {boolean} true if there is a match to options.normalScrollElements
20089         */
20090        function checkParentForNormalScrollElement (el, hop) {
20091            hop = hop || 0;
20092            var parent = $(el).parent();
20093
20094            if (hop < options.normalScrollElementTouchThreshold &&
20095                parent.is(options.normalScrollElements) ) {
20096                return true;
20097            } else if (hop == options.normalScrollElementTouchThreshold) {
20098                return false;
20099            } else {
20100                return checkParentForNormalScrollElement(parent, ++hop);
20101            }
20102        }
20103
20104        /**
20105        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
20106        * this way we make sure that is really a touch event what IE is detecting.
20107        */
20108        function isReallyTouch(e){
20109            //if is not IE   ||  IE is detecting `touch` or `pen`
20110            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
20111        }
20112
20113        /**
20114        * Handler for the touch start event.
20115        */
20116        function touchStartHandler(event){
20117            var e = event.originalEvent;
20118
20119            //stopping the auto scroll to adjust to a section
20120            if(options.fitToSection){
20121                $htmlBody.stop();
20122            }
20123
20124            if(isReallyTouch(e)){
20125                var touchEvents = getEventsPage(e);
20126                touchStartY = touchEvents.y;
20127                touchStartX = touchEvents.x;
20128            }
20129        }
20130
20131        /**
20132        * Gets the average of the last `number` elements of the given array.
20133        */
20134        function getAverage(elements, number){
20135            var sum = 0;
20136
20137            //taking `number` elements from the end to make the average, if there are not enought, 1
20138            var lastElements = elements.slice(Math.max(elements.length - number, 1));
20139
20140            for(var i = 0; i < lastElements.length; i++){
20141                sum = sum + lastElements[i];
20142            }
20143
20144            return Math.ceil(sum/number);
20145        }
20146
20147        /**
20148         * Detecting mousewheel scrolling
20149         *
20150         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
20151         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
20152         */
20153        var prevTime = new Date().getTime();
20154
20155        function MouseWheelHandler(e) {
20156            var curTime = new Date().getTime();
20157            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
20158
20159            //autoscrolling and not zooming?
20160            if(options.autoScrolling && !controlPressed && !isNormalScroll){
20161                // cross-browser wheel delta
20162                e = e || window.event;
20163                var value = e.wheelDelta || -e.deltaY || -e.detail;
20164                var delta = Math.max(-1, Math.min(1, value));
20165
20166                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
20167                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
20168
20169                //Limiting the array to 150 (lets not waste memory!)
20170                if(scrollings.length > 149){
20171                    scrollings.shift();
20172                }
20173
20174                //keeping record of the previous scrollings
20175                scrollings.push(Math.abs(value));
20176
20177                //preventing to scroll the site on mouse wheel when scrollbar is present
20178                if(options.scrollBar){
20179                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
20180                }
20181
20182                var activeSection = $(SECTION_ACTIVE_SEL);
20183                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
20184
20185                //time difference between the last scroll and the current one
20186                var timeDiff = curTime-prevTime;
20187                prevTime = curTime;
20188
20189                //haven't they scrolled in a while?
20190                //(enough to be consider a different scrolling action to scroll another section)
20191                if(timeDiff > 200){
20192                    //emptying the array, we dont care about old scrollings for our averages
20193                    scrollings = [];
20194                }
20195
20196                if(canScroll){
20197                    var averageEnd = getAverage(scrollings, 10);
20198                    var averageMiddle = getAverage(scrollings, 70);
20199                    var isAccelerating = averageEnd >= averageMiddle;
20200
20201                    //to avoid double swipes...
20202                    if(isAccelerating && isScrollingVertically){
20203                        //scrolling down?
20204                        if (delta < 0) {
20205                            scrolling('down', scrollable);
20206
20207                        //scrolling up?
20208                        }else {
20209                            scrolling('up', scrollable);
20210                        }
20211                    }
20212                }
20213
20214                return false;
20215            }
20216
20217            if(options.fitToSection){
20218                //stopping the auto scroll to adjust to a section
20219                $htmlBody.stop();
20220            }
20221        }
20222
20223        /**
20224        * Slides a slider to the given direction.
20225        * Optional `section` param.
20226        */
20227        function moveSlide(direction, section){
20228            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
20229            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
20230            var numSlides = slides.find(SLIDE_SEL).length;
20231
20232            // more than one slide needed and nothing should be sliding
20233            if (!slides.length || slideMoving || numSlides < 2) {
20234                return;
20235            }
20236
20237            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
20238            var destiny = null;
20239
20240            if(direction === 'left'){
20241                destiny = currentSlide.prev(SLIDE_SEL);
20242            }else{
20243                destiny = currentSlide.next(SLIDE_SEL);
20244            }
20245
20246            //isn't there a next slide in the secuence?
20247            if(!destiny.length){
20248                //respect loopHorizontal settin
20249                if (!options.loopHorizontal) return;
20250
20251                if(direction === 'left'){
20252                    destiny = currentSlide.siblings(':last');
20253                }else{
20254                    destiny = currentSlide.siblings(':first');
20255                }
20256            }
20257
20258            slideMoving = true;
20259
20260            landscapeScroll(slides, destiny, direction);
20261        }
20262
20263        /**
20264        * Maintains the active slides in the viewport
20265        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
20266        */
20267        function keepSlidesPosition(){
20268            $(SLIDE_ACTIVE_SEL).each(function(){
20269                silentLandscapeScroll($(this), 'internal');
20270            });
20271        }
20272
20273        var previousDestTop = 0;
20274        /**
20275        * Returns the destination Y position based on the scrolling direction and
20276        * the height of the section.
20277        */
20278        function getDestinationPosition(element){
20279            var elemPosition = element.position();
20280
20281            //top of the desination will be at the top of the viewport
20282            var position = elemPosition.top;
20283            var isScrollingDown =  elemPosition.top > previousDestTop;
20284            var sectionBottom = position - windowsHeight + element.outerHeight();
20285            var bigSectionsDestination = options.bigSectionsDestination;
20286
20287            //Uncode addition
20288            var containerH = container.outerHeight();
20289            var containerPosition = container.offset();
20290
20291            //########### Commented by Uncode - START ###########
20292            //is the destination element bigger than the viewport?
20293            // if(element.outerHeight() > windowsHeight){
20294            //     //scrolling up?
20295            //     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
20296            //         position = sectionBottom;
20297            //     }
20298            // }
20299
20300            // //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
20301            // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
20302            //     //The bottom of the destination will be at the bottom of the viewport
20303            //     position = sectionBottom;
20304            // }
20305            //########### Commented by Uncode - END ###########
20306
20307            //Uncode addition
20308            if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
20309                position += 18;
20310            if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
20311                position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
20312            }
20313            
20314            /*
20315            Keeping record of the last scrolled position to determine the scrolling direction.
20316            No conventional methods can be used as the scroll bar might not be present
20317            AND the section might not be active if it is auto-height and didnt reach the middle
20318            of the viewport.
20319            */
20320            previousDestTop = position;
20321            return position;
20322        }
20323
20324        /**
20325        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
20326        */
20327        function scrollPage(element, callback, isMovementUp){
20328            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
20329
20330            var dtop = getDestinationPosition(element);
20331            var slideAnchorLink;
20332            var slideIndex;
20333
20334            //local variables
20335            var v = {
20336                element: element,
20337                callback: callback,
20338                isMovementUp: isMovementUp,
20339                dtop: dtop,
20340                yMovement: getYmovement(element),
20341                anchorLink: element.data('anchor'),
20342                sectionIndex: element.index(SECTION_SEL),
20343                activeSlide: element.find(SLIDE_ACTIVE_SEL),
20344                activeSection: $(SECTION_ACTIVE_SEL),
20345                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
20346
20347                //caching the value of isResizing at the momment the function is called
20348                //because it will be checked later inside a setTimeout and the value might change
20349                localIsResizing: isResizing
20350            };
20351
20352            //quiting when destination scroll is the same as the current one
20353            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
20354
20355            if(v.activeSlide.length){
20356                slideAnchorLink = v.activeSlide.data('anchor');
20357                slideIndex = v.activeSlide.index();
20358            }
20359
20360            // If continuousVertical && we need to wrap around
20361            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
20362                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
20363                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
20364
20365                v = createInfiniteSections(v);
20366            }
20367
20368            //callback (onLeave) if the site is not just resizing and readjusting the slides
20369            if($.isFunction(options.onLeave) && !v.localIsResizing){
20370                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
20371                    return;
20372                }
20373            }
20374
20375            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
20376            if(!v.localIsResizing){
20377                stopMedia(v.activeSection);
20378            }
20379
20380            options.scrollOverflowHandler.beforeLeave();
20381            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
20382            lazyLoad(element);
20383            options.scrollOverflowHandler.onLeave();
20384
20385
20386            //preventing from activating the MouseWheelHandler event
20387            //more than once if the page is scrolling
20388            canScroll = false;
20389
20390            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
20391
20392            performMovement(v);
20393
20394            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
20395            lastScrolledDestiny = v.anchorLink;
20396
20397            //avoid firing it twice (as it does also on scroll)
20398            activateMenuAndNav(v.anchorLink, v.sectionIndex);
20399        }
20400
20401        /**
20402        * Performs the vertical movement (by CSS3 or by jQuery)
20403        */
20404        function performMovement(v){
20405            // using CSS3 translate functionality
20406            if (options.css3 && options.autoScrolling && !options.scrollBar) {
20407
20408                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
20409                // that's why we round it to 0.
20410                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
20411                transformContainer(translate3d, true);
20412
20413                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
20414                //scrollingSpeed to change in case of using silentMoveTo();
20415                if(options.scrollingSpeed){
20416                    clearTimeout(afterSectionLoadsId);
20417                    afterSectionLoadsId = setTimeout(function () {
20418                        afterSectionLoads(v);
20419                    }, options.scrollingSpeed);
20420                }else{
20421                    afterSectionLoads(v);
20422                }
20423            }
20424
20425            // using jQuery animate
20426            else{
20427                var scrollSettings = getScrollSettings(v);
20428
20429                $(scrollSettings.element).animate(
20430                    scrollSettings.options,
20431                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
20432                    if(options.scrollBar){
20433
20434                        /* Hack!
20435                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
20436                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
20437
20438                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
20439                        */
20440                        setTimeout(function(){
20441                            afterSectionLoads(v);
20442                        },30);
20443                    }else{
20444                        afterSectionLoads(v);
20445                    }
20446                });
20447            }
20448        }
20449
20450        /**
20451        * Gets the scrolling settings depending on the plugin autoScrolling option
20452        */
20453        function getScrollSettings(v){
20454            var scroll = {};
20455
20456            if(options.autoScrolling && !options.scrollBar){
20457                scroll.options = { 'top': -v.dtop};
20458                scroll.element = WRAPPER_SEL;
20459            }else{
20460                scroll.options = { 'scrollTop': v.dtop};
20461                scroll.element = 'html, body';
20462            }
20463
20464            return scroll;
20465        }
20466
20467        /**
20468        * Adds sections before or after the current one to create the infinite effect.
20469        */
20470        function createInfiniteSections(v){
20471            // Scrolling down
20472            if (!v.isMovementUp) {
20473                // Move all previous sections to after the active section
20474                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
20475            }
20476            else { // Scrolling up
20477                // Move all next sections to before the active section
20478                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
20479            }
20480
20481            // Maintain the displayed position (now that we changed the element order)
20482            silentScroll($(SECTION_ACTIVE_SEL).position().top);
20483
20484            // Maintain the active slides visible in the viewport
20485            keepSlidesPosition();
20486
20487            // save for later the elements that still need to be reordered
20488            v.wrapAroundElements = v.activeSection;
20489
20490            // Recalculate animation variables
20491            v.dtop = v.element.position().top;
20492            v.yMovement = getYmovement(v.element);
20493
20494            return v;
20495        }
20496
20497        /**
20498        * Fix section order after continuousVertical changes have been animated
20499        */
20500        function continuousVerticalFixSectionOrder (v) {
20501            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
20502            // finish moving the elements around so the direct navigation will function more simply
20503            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
20504                return;
20505            }
20506
20507            if (v.isMovementUp) {
20508                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
20509            }
20510            else {
20511                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
20512            }
20513
20514            silentScroll($(SECTION_ACTIVE_SEL).position().top);
20515
20516            // Maintain the active slides visible in the viewport
20517            keepSlidesPosition();
20518        }
20519
20520
20521        /**
20522        * Actions to do once the section is loaded.
20523        */
20524        function afterSectionLoads (v){
20525            continuousVerticalFixSectionOrder(v);
20526
20527            //callback (afterLoad) if the site is not just resizing and readjusting the slides
20528            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
20529            options.scrollOverflowHandler.afterLoad();
20530
20531            if(!v.localIsResizing){
20532                playMedia(v.element);
20533            }
20534
20535            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
20536
20537            canScroll = true;
20538
20539            $.isFunction(v.callback) && v.callback.call(this);
20540        }
20541
20542        /**
20543        * Sets the value for the given attribute from the `data-` attribute with the same suffix
20544        * ie: data-srcset ==> srcset  |  data-src ==> src
20545        */
20546        function setSrc(element, attribute){
20547            element
20548                .attr(attribute, element.data(attribute))
20549                .removeAttr('data-' + attribute);
20550        }
20551
20552        /**
20553        * Lazy loads image, video and audio elements.
20554        */
20555        function lazyLoad(destiny){
20556            if (!options.lazyLoading){
20557                return;
20558            }
20559
20560            var panel = getSlideOrSection(destiny);
20561            var element;
20562            
20563            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
20564                element = $(this);
20565
20566                $.each(['src', 'srcset'], function(index, type){
20567                    var attribute = element.attr('data-' + type);
20568                    if(typeof attribute !== 'undefined' && attribute){
20569                        setSrc(element, type);
20570                    }
20571                });
20572
20573                if(element.is('source')){
20574                    element.closest('video').get(0).load();
20575                }
20576            });
20577        }
20578
20579        /**
20580        * Plays video and audio elements.
20581        */
20582        function playMedia(destiny){
20583            var panel = getSlideOrSection(destiny);
20584
20585            //playing HTML5 media elements
20586            panel.find('video, audio').each(function(){
20587                var element = $(this).get(0);
20588
20589                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
20590                    element.play();
20591                }
20592            });
20593
20594            //youtube videos
20595            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
20596                var element = $(this).get(0);
20597
20598                if ( element.hasAttribute('data-autoplay') ){
20599                    playYoutube(element);
20600                }
20601
20602                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
20603                element.onload = function() {
20604                    if ( element.hasAttribute('data-autoplay') ){
20605                        playYoutube(element);
20606                    }
20607                };
20608            });
20609        }
20610
20611        /**
20612        * Plays a youtube video
20613        */
20614        function playYoutube(element){
20615            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
20616        }
20617
20618        /**
20619        * Stops video and audio elements.
20620        */
20621        function stopMedia(destiny){
20622            var panel = getSlideOrSection(destiny);
20623
20624            //stopping HTML5 media elements
20625            panel.find('video, audio').each(function(){
20626                var element = $(this).get(0);
20627
20628                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
20629                    element.pause();
20630                }
20631            });
20632
20633            //youtube videos
20634            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
20635                var element = $(this).get(0);
20636
20637                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
20638                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
20639                }
20640            });
20641        }
20642
20643        /**
20644        * Gets the active slide (or section) for the given section
20645        */
20646        function getSlideOrSection(destiny){
20647            var slide = destiny.find(SLIDE_ACTIVE_SEL);
20648            if( slide.length ) {
20649                destiny = $(slide);
20650            }
20651
20652            return destiny;
20653        }
20654
20655        /**
20656        * Scrolls to the anchor in the URL when loading the site
20657        */
20658        function scrollToAnchor(){
20659            //getting the anchor link in the URL and deleting the `#`
20660            var value =  window.location.hash.replace('#', '').split('/');
20661            var sectionAnchor = decodeURIComponent(value[0]);
20662            var slideAnchor = decodeURIComponent(value[1]);
20663
20664            if(sectionAnchor){  //if theres any #
20665                if(options.animateAnchor){
20666                    scrollPageAndSlide(sectionAnchor, slideAnchor);
20667                }else{
20668                    silentMoveTo(sectionAnchor, slideAnchor);
20669                }
20670            }
20671        }
20672
20673        /**
20674        * Detecting any change on the URL to scroll to the given anchor link
20675        * (a way to detect back history button as we play with the hashes on the URL)
20676        */
20677        function hashChangeHandler(){
20678            if(!isScrolling && !options.lockAnchors){
20679                var value =  window.location.hash.replace('#', '').split('/');
20680                var sectionAnchor = decodeURIComponent(value[0]);
20681                var slideAnchor = decodeURIComponent(value[1]);
20682
20683                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
20684                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
20685                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
20686
20687
20688                if(sectionAnchor.length){
20689                    /*in order to call scrollpage() only once for each destination at a time
20690                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
20691                    event is fired on every scroll too.*/
20692                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
20693                        scrollPageAndSlide(sectionAnchor, slideAnchor);
20694                    }
20695                }
20696            }
20697        }
20698
20699        //Sliding with arrow keys, both, vertical and horizontal
20700        function keydownHandler(e) {
20701
20702            clearTimeout(keydownId);
20703
20704            var activeElement = $(':focus');
20705
20706            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
20707                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
20708                options.keyboardScrolling && options.autoScrolling){
20709                var keyCode = e.which;
20710
20711                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
20712                var keyControls = [40, 38, 32, 33, 34];
20713                if($.inArray(keyCode, keyControls) > -1){
20714                    e.preventDefault();
20715                }
20716
20717                controlPressed = e.ctrlKey;
20718
20719                keydownId = setTimeout(function(){
20720                    onkeydown(e);
20721                },150);
20722            }
20723        }
20724
20725        function tooltipTextHandler(){
20726            $(this).prev().trigger('click');
20727        }
20728
20729        //to prevent scrolling while zooming
20730        function keyUpHandler(e){
20731            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
20732                controlPressed = e.ctrlKey;
20733            }
20734        }
20735
20736        //binding the mousemove when the mouse's middle button is released
20737        function mouseDownHandler(e){
20738            //middle button
20739            if (e.which == 2){
20740                oldPageY = e.pageY;
20741                container.on('mousemove', mouseMoveHandler);
20742            }
20743        }
20744
20745        //unbinding the mousemove when the mouse's middle button is released
20746        function mouseUpHandler(e){
20747            //middle button
20748            if (e.which == 2){
20749                container.off('mousemove');
20750            }
20751        }
20752
20753        //Scrolling horizontally when clicking on the slider controls.
20754        function slideArrowHandler(){
20755            var section = $(this).closest(SECTION_SEL);
20756
20757            if ($(this).hasClass(SLIDES_PREV)) {
20758                if(isScrollAllowed.m.left){
20759                    moveSlideLeft(section);
20760                }
20761            } else {
20762                if(isScrollAllowed.m.right){
20763                    moveSlideRight(section);
20764                }
20765            }
20766        }
20767
20768        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
20769        function blurHandler(){
20770            isWindowFocused = false;
20771            controlPressed = false;
20772        }
20773
20774        //Scrolls to the section when clicking the navigation bullet
20775        function sectionBulletHandler(e){
20776            e.preventDefault();
20777            var index = $(this).parent().index();
20778            scrollPage($(SECTION_SEL).eq(index));
20779        }
20780
20781        //Scrolls the slider to the given slide destination for the given section
20782        function slideBulletHandler(e){
20783            e.preventDefault();
20784            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
20785            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
20786
20787            landscapeScroll(slides, destiny);
20788        }
20789
20790        /**
20791        * Keydown event
20792        */
20793        function onkeydown(e){
20794            var shiftPressed = e.shiftKey;
20795
20796            //do nothing if we can not scroll or we are not using horizotnal key arrows.
20797            if(!canScroll && [37,39].indexOf(e.which) < 0){
20798                return;
20799            }
20800
20801            switch (e.which) {
20802                //up
20803                case 38:
20804                case 33:
20805                    if(isScrollAllowed.k.up){
20806                        moveSectionUp();
20807                    }
20808                    break;
20809
20810                //down
20811                case 32: //spacebar
20812                    if(shiftPressed && isScrollAllowed.k.up){
20813                        moveSectionUp();
20814                        break;
20815                    }
20816                /* falls through */
20817                case 40:
20818                case 34:
20819                    if(isScrollAllowed.k.down){
20820                        moveSectionDown();
20821                    }
20822                    break;
20823
20824                //Home
20825                case 36:
20826                    if(isScrollAllowed.k.up){
20827                        moveTo(1);
20828                    }
20829                    break;
20830
20831                //End
20832                case 35:
20833                     if(isScrollAllowed.k.down){
20834                        moveTo( $(SECTION_SEL).length );
20835                    }
20836                    break;
20837
20838                //left
20839                case 37:
20840                    if(isScrollAllowed.k.left){
20841                        moveSlideLeft();
20842                    }
20843                    break;
20844
20845                //right
20846                case 39:
20847                    if(isScrollAllowed.k.right){
20848                        moveSlideRight();
20849                    }
20850                    break;
20851
20852                default:
20853                    return; // exit this handler for other keys
20854            }
20855        }
20856
20857        /**
20858        * Detecting the direction of the mouse movement.
20859        * Used only for the middle button of the mouse.
20860        */
20861        var oldPageY = 0;
20862        function mouseMoveHandler(e){
20863            if(canScroll){
20864                // moving up
20865                if (e.pageY < oldPageY && isScrollAllowed.m.up){
20866                    moveSectionUp();
20867                }
20868
20869                // moving down
20870                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
20871                    moveSectionDown();
20872                }
20873            }
20874            oldPageY = e.pageY;
20875        }
20876
20877        /**
20878        * Scrolls horizontal sliders.
20879        */
20880        function landscapeScroll(slides, destiny, direction){
20881            var section = slides.closest(SECTION_SEL);
20882            var v = {
20883                slides: slides,
20884                destiny: destiny,
20885                direction: direction,
20886                destinyPos: destiny.position(),
20887                slideIndex: destiny.index(),
20888                section: section,
20889                sectionIndex: section.index(SECTION_SEL),
20890                anchorLink: section.data('anchor'),
20891                slidesNav: section.find(SLIDES_NAV_SEL),
20892                slideAnchor:  getAnchor(destiny),
20893                prevSlide: section.find(SLIDE_ACTIVE_SEL),
20894                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
20895
20896                //caching the value of isResizing at the momment the function is called
20897                //because it will be checked later inside a setTimeout and the value might change
20898                localIsResizing: isResizing
20899            };
20900            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
20901
20902            //important!! Only do it when not resizing
20903            if(!v.localIsResizing){
20904                //preventing from scrolling to the next/prev section when using scrollHorizontally
20905                canScroll = false;
20906            }
20907
20908            if(options.onSlideLeave){
20909
20910                //if the site is not just resizing and readjusting the slides
20911                if(!v.localIsResizing && v.xMovement!=='none'){
20912                    if($.isFunction( options.onSlideLeave )){
20913                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
20914                            slideMoving = false;
20915                            return;
20916                        }
20917                    }
20918                }
20919            }
20920
20921            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
20922
20923            if(!v.localIsResizing){
20924                stopMedia(v.prevSlide);
20925                lazyLoad(destiny);
20926            }
20927
20928            if(!options.loopHorizontal && options.controlArrows){
20929                //hidding it for the fist slide, showing for the rest
20930                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
20931
20932                //hidding it for the last slide, showing for the rest
20933                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
20934            }
20935
20936            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
20937            if(section.hasClass(ACTIVE) && !v.localIsResizing){
20938                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
20939            }
20940
20941            performHorizontalMove(slides, v, true);
20942        }
20943
20944
20945        function afterSlideLoads(v){
20946            activeSlidesNavigation(v.slidesNav, v.slideIndex);
20947
20948            //if the site is not just resizing and readjusting the slides
20949            if(!v.localIsResizing){
20950                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
20951
20952                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
20953                //and to prevent double scroll right after a windows resize
20954                canScroll = true;
20955
20956                playMedia(v.destiny);
20957            }
20958
20959            //letting them slide again
20960            slideMoving = false;
20961        }
20962
20963        /**
20964        * Performs the horizontal movement. (CSS3 or jQuery)
20965        *
20966        * @param fireCallback {Bool} - determines whether or not to fire the callback
20967        */
20968        function performHorizontalMove(slides, v, fireCallback){
20969            var destinyPos = v.destinyPos;
20970
20971            if(options.css3){
20972                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
20973
20974                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
20975
20976                afterSlideLoadsId = setTimeout(function(){
20977                    fireCallback && afterSlideLoads(v);
20978                }, options.scrollingSpeed, options.easing);
20979            }else{
20980                slides.animate({
20981                    scrollLeft : Math.round(destinyPos.left)
20982                }, options.scrollingSpeed, options.easing, function() {
20983
20984                    fireCallback && afterSlideLoads(v);
20985                });
20986            }
20987        }
20988
20989        /**
20990        * Sets the state for the horizontal bullet navigations.
20991        */
20992        function activeSlidesNavigation(slidesNav, slideIndex){
20993            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
20994            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
20995        }
20996
20997        var previousHeight = windowsHeight;
20998
20999        //when resizing the site, we adjust the heights of the sections, slimScroll...
21000        function resizeHandler(){
21001            //checking if it needs to get responsive
21002            responsive();
21003
21004            // rebuild immediately on touch devices
21005            if (isTouchDevice) {
21006                var activeElement = $(document.activeElement);
21007
21008                //if the keyboard is NOT visible
21009                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
21010                    var currentHeight = $window.height();
21011
21012                    //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)
21013                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
21014                        reBuild(true);
21015                        previousHeight = currentHeight;
21016                    }
21017                }
21018            }else{
21019                //in order to call the functions only when the resize is finished
21020                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
21021                clearTimeout(resizeId);
21022
21023                resizeId = setTimeout(function(){
21024                    reBuild(true);
21025                }, 350);
21026            }
21027        }
21028
21029        /**
21030        * Checks if the site needs to get responsive and disables autoScrolling if so.
21031        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
21032        */
21033        function responsive(){
21034            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
21035            var heightLimit = options.responsiveHeight;
21036
21037            //only calculating what we need. Remember its called on the resize event.
21038            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
21039            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
21040
21041            if(widthLimit && heightLimit){
21042                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
21043            }
21044            else if(widthLimit){
21045                setResponsive(isBreakingPointWidth);
21046            }
21047            else if(heightLimit){
21048                setResponsive(isBreakingPointHeight);
21049            }
21050        }
21051
21052        /**
21053        * Adds transition animations for the given element
21054        */
21055        function addAnimation(container, element){
21056            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
21057
21058            container.removeClass(NO_TRANSITION);
21059            return container.css({
21060                '-webkit-transition': transition,
21061                'transition': transition
21062            });
21063        }
21064
21065        /**
21066        * Remove transition animations for the given element
21067        */
21068        function removeAnimation(element){
21069            return element.addClass(NO_TRANSITION);
21070        }
21071
21072        /**
21073        * Activating the vertical navigation bullets according to the given slide name.
21074        */
21075        function activateNavDots(name, sectionIndex){
21076            if(options.navigation){
21077                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
21078                if(name){
21079                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
21080                }else{
21081                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
21082                }
21083            }
21084        }
21085
21086        /**
21087        * Activating the website main menu elements according to the given slide name.
21088        */
21089        function activateMenuElement(name){
21090            if(options.menu){
21091                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
21092                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
21093            }
21094        }
21095
21096        /**
21097        * Sets to active the current menu and vertical nav items.
21098        */
21099        function activateMenuAndNav(anchor, index){
21100            activateMenuElement(anchor);
21101            activateNavDots(anchor, index);
21102        }
21103
21104        /**
21105        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
21106        * from the current section.
21107        */
21108        function getYmovement(destiny){
21109            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
21110            var toIndex = destiny.index(SECTION_SEL);
21111            if( fromIndex == toIndex){
21112                return 'none';
21113            }
21114            if(fromIndex > toIndex){
21115                return 'up';
21116            }
21117            return 'down';
21118        }
21119
21120        /**
21121        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
21122        * from the current slide.
21123        */
21124        function getXmovement(fromIndex, toIndex){
21125            if( fromIndex == toIndex){
21126                return 'none';
21127            }
21128            if(fromIndex > toIndex){
21129                return 'left';
21130            }
21131            return 'right';
21132        }
21133
21134        /**
21135        * Checks if the element needs scrollbar and if the user wants to apply it.
21136        * If so it creates it.
21137        *
21138        * @param {Object} element   jQuery object of the section or slide
21139        */
21140        function createScrollBar(element){
21141            //User doesn't want scrollbar here? Sayonara baby!
21142            if(element.hasClass('fp-noscroll')) return;
21143
21144            //needed to make `scrollHeight` work under Opera 12
21145            element.css('overflow', 'hidden');
21146
21147            var scrollOverflowHandler = options.scrollOverflowHandler;
21148            var wrap = scrollOverflowHandler.wrapContent();
21149            //in case element is a slide
21150            var section = element.closest(SECTION_SEL);
21151            var scrollable = scrollOverflowHandler.scrollable(element);
21152            var contentHeight;
21153
21154            //if there was scroll, the contentHeight will be the one in the scrollable section
21155            if(scrollable.length){
21156                contentHeight = scrollOverflowHandler.scrollHeight(element);
21157            }else{
21158                contentHeight = element.get(0).scrollHeight;
21159                if(options.verticalCentered){
21160                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
21161                }
21162            }
21163
21164            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
21165            //Uncode addition
21166            scrollHeight -= UNCODE.bodyBorder*2 + UNCODE.adminBarHeight;
21167
21168            //needs scroll?
21169            if ( contentHeight > scrollHeight) {
21170                //did we already have an scrollbar ? Updating it
21171                if(scrollable.length){
21172                    scrollOverflowHandler.update(element, scrollHeight);
21173                }
21174                //creating the scrolling
21175                else{
21176                    if(options.verticalCentered){
21177                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
21178                    }else{
21179                        element.wrapInner(wrap);
21180                    }
21181                    scrollOverflowHandler.create(element, scrollHeight);
21182                }
21183            }
21184            //removing the scrolling when it is not necessary anymore
21185            else{
21186                scrollOverflowHandler.remove(element);
21187            }
21188
21189            //undo
21190            element.css('overflow', '');
21191        }
21192
21193        function addTableClass(element){
21194            //In case we are styling for the 2nd time as in with reponsiveSlides
21195            if(!element.hasClass(TABLE)){
21196                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
21197            }
21198        }
21199
21200        function getTableHeight(element){
21201            var sectionHeight = windowsHeight;
21202
21203            if(options.paddingTop || options.paddingBottom){
21204                var section = element;
21205                if(!section.hasClass(SECTION)){
21206                    section = element.closest(SECTION_SEL);
21207                }
21208
21209                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
21210                sectionHeight = (windowsHeight - paddings);
21211            }
21212
21213            return sectionHeight;
21214        }
21215
21216        /**
21217        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
21218        */
21219        function transformContainer(translate3d, animated){
21220            if(animated){
21221                addAnimation(container);
21222            }else{
21223                removeAnimation(container);
21224            }
21225
21226            container.css(getTransforms(translate3d));
21227
21228            //syncronously removing the class after the animation has been applied.
21229            setTimeout(function(){
21230                container.removeClass(NO_TRANSITION);
21231            },10);
21232        }
21233
21234        /**
21235        * Gets a section by its anchor / index
21236        */
21237        function getSectionByAnchor(sectionAnchor){
21238            if(!sectionAnchor) return [];
21239
21240            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
21241            if(!section.length){
21242                section = $(SECTION_SEL).eq( sectionAnchor -1);
21243            }
21244
21245            return section;
21246        }
21247
21248        /**
21249        * Gets a slide inside a given section by its anchor / index
21250        */
21251        function getSlideByAnchor(slideAnchor, section){
21252            var slides = section.find(SLIDES_WRAPPER_SEL);
21253            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
21254
21255            if(!slide.length){
21256                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
21257            }
21258
21259            return slide;
21260        }
21261
21262        /**
21263        * Scrolls to the given section and slide anchors
21264        */
21265        function scrollPageAndSlide(destiny, slide){
21266            var section = getSectionByAnchor(destiny);
21267
21268            //do nothing if there's no section with the given anchor name
21269            if(!section.length) return;
21270
21271            //default slide
21272            if (typeof slide === 'undefined') {
21273                slide = 0;
21274            }
21275
21276            //we need to scroll to the section and then to the slide
21277            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
21278                scrollPage(section, function(){
21279                    scrollSlider(section, slide);
21280                });
21281            }
21282            //if we were already in the section
21283            else{
21284                scrollSlider(section, slide);
21285            }
21286        }
21287
21288        /**
21289        * Scrolls the slider to the given slide destination for the given section
21290        */
21291        function scrollSlider(section, slideAnchor){
21292            if(typeof slideAnchor !== 'undefined'){
21293                var slides = section.find(SLIDES_WRAPPER_SEL);
21294                var destiny =  getSlideByAnchor(slideAnchor, section);
21295
21296                if(destiny.length){
21297                    landscapeScroll(slides, destiny);
21298                }
21299            }
21300        }
21301
21302        /**
21303        * Creates a landscape navigation bar with dots for horizontal sliders.
21304        */
21305        function addSlidesNavigation(section, numSlides){
21306            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
21307            var nav = section.find(SLIDES_NAV_SEL);
21308
21309            //top or bottom
21310            nav.addClass(options.slidesNavPosition);
21311
21312            for(var i=0; i< numSlides; i++){
21313                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
21314            }
21315
21316            //centering it
21317            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
21318
21319            nav.find('li').first().find('a').addClass(ACTIVE);
21320        }
21321
21322
21323        /**
21324        * Sets the state of the website depending on the active section/slide.
21325        * It changes the URL hash when needed and updates the body class.
21326        */
21327        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
21328            var sectionHash = '';
21329
21330            if(options.anchors.length && !options.lockAnchors){
21331
21332                //isn't it the first slide?
21333                if(slideIndex){
21334                    if(typeof anchorLink !== 'undefined'){
21335                        sectionHash = anchorLink;
21336                    }
21337
21338                    //slide without anchor link? We take the index instead.
21339                    if(typeof slideAnchor === 'undefined'){
21340                        slideAnchor = slideIndex;
21341                    }
21342
21343                    lastScrolledSlide = slideAnchor;
21344                    setUrlHash(sectionHash + '/' + slideAnchor);
21345
21346                //first slide won't have slide anchor, just the section one
21347                }else if(typeof slideIndex !== 'undefined'){
21348                    lastScrolledSlide = slideAnchor;
21349                    setUrlHash(anchorLink);
21350                }
21351
21352                //section without slides
21353                else{
21354                    setUrlHash(anchorLink);
21355                }
21356            }
21357
21358            setBodyClass();
21359        }
21360
21361        /**
21362        * Sets the URL hash.
21363        */
21364        function setUrlHash(url){
21365            //Uncode addition
21366            if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
21367                return false;
21368
21369            if(options.recordHistory){
21370                location.hash = url;
21371            }else{
21372                //Uncode addition
21373                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
21374                // if(isTouchDevice || isTouch){
21375                //     window.history.replaceState(undefined, undefined, '#' + url);
21376                // }else{
21377                //     var baseUrl = window.location.href.split('#')[0];
21378                //     window.location.replace( baseUrl + '#' + url );
21379                // }
21380                return false;
21381            }
21382        }
21383
21384        /**
21385        * Gets the anchor for the given slide / section. Its index will be used if there's none.
21386        */
21387        function getAnchor(element){
21388            var anchor = element.data('anchor');
21389            var index = element.index();
21390
21391            //Slide without anchor link? We take the index instead.
21392            if(typeof anchor === 'undefined'){
21393                anchor = index;
21394            }
21395
21396            return anchor;
21397        }
21398
21399        /**
21400        * Sets a class for the body of the page depending on the active section / slide
21401        */
21402        function setBodyClass(){
21403            var section = $(SECTION_ACTIVE_SEL);
21404            var slide = section.find(SLIDE_ACTIVE_SEL);
21405
21406            var sectionAnchor = getAnchor(section);
21407            var slideAnchor = getAnchor(slide);
21408
21409            var text = String(sectionAnchor);
21410
21411            if(slide.length){
21412                text = text + '-' + slideAnchor;
21413            }
21414
21415            //changing slash for dash to make it a valid CSS style
21416            text = text.replace('/', '-').replace('#','');
21417
21418            //removing previous anchor classes
21419            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
21420            $body[0].className = $body[0].className.replace(classRe, '');
21421
21422            //adding the current anchor
21423            $body.addClass(VIEWING_PREFIX + '-' + text);
21424        }
21425
21426        /**
21427        * Checks for translate3d support
21428        * @return boolean
21429        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
21430        */
21431        function support3d() {
21432            var el = document.createElement('p'),
21433                has3d,
21434                transforms = {
21435                    'webkitTransform':'-webkit-transform',
21436                    'OTransform':'-o-transform',
21437                    'msTransform':'-ms-transform',
21438                    'MozTransform':'-moz-transform',
21439                    'transform':'transform'
21440                };
21441
21442            // Add it to the body to get the computed style.
21443            document.body.insertBefore(el, null);
21444
21445            for (var t in transforms) {
21446                if (el.style[t] !== undefined) {
21447                    el.style[t] = 'translate3d(1px,1px,1px)';
21448                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
21449                }
21450            }
21451
21452            document.body.removeChild(el);
21453
21454            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
21455        }
21456
21457        /**
21458        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
21459        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
21460        */
21461        function removeMouseWheelHandler(){
21462            if (document.addEventListener) {
21463                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
21464                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
21465                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
21466            } else {
21467                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
21468            }
21469        }
21470
21471        /**
21472        * Adds the auto scrolling action for the mouse wheel and trackpad.
21473        * After this function is called, the mousewheel and trackpad movements will scroll through sections
21474        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
21475        */
21476        function addMouseWheelHandler(){
21477            var prefix = '';
21478            var _addEventListener;
21479
21480            if (window.addEventListener){
21481                _addEventListener = "addEventListener";
21482            }else{
21483                _addEventListener = "attachEvent";
21484                prefix = 'on';
21485            }
21486
21487             // detect available wheel event
21488            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
21489                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
21490                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
21491
21492
21493            if(support == 'DOMMouseScroll'){
21494                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false);
21495            }
21496
21497            //handle MozMousePixelScroll in older Firefox
21498            else{
21499                document[ _addEventListener ](prefix + support, MouseWheelHandler, false);
21500            }
21501        }
21502
21503        /**
21504        * Binding the mousemove when the mouse's middle button is pressed
21505        */
21506        function addMiddleWheelHandler(){
21507            container
21508                .on('mousedown', mouseDownHandler)
21509                .on('mouseup', mouseUpHandler);
21510        }
21511
21512        /**
21513        * Unbinding the mousemove when the mouse's middle button is released
21514        */
21515        function removeMiddleWheelHandler(){
21516            container
21517                .off('mousedown', mouseDownHandler)
21518                .off('mouseup', mouseUpHandler);
21519        }
21520
21521        /**
21522        * Adds the possibility to auto scroll through sections on touch devices.
21523        */
21524        function addTouchHandler(){
21525            if(isTouchDevice || isTouch){
21526                if(options.autoScrolling){
21527                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
21528                }
21529
21530                $(WRAPPER_SEL)
21531                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
21532                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
21533            }
21534        }
21535
21536        /**
21537        * Removes the auto scrolling for touch devices.
21538        */
21539        function removeTouchHandler(){
21540            if(isTouchDevice || isTouch){
21541                $(WRAPPER_SEL)
21542                    .off(events.touchstart)
21543                    .off(events.touchmove);
21544            }
21545        }
21546
21547        /*
21548        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
21549        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
21550        */
21551        function getMSPointer(){
21552            var pointer;
21553
21554            //IE >= 11 & rest of browsers
21555            if(window.PointerEvent){
21556                pointer = { down: 'pointerdown', move: 'pointermove'};
21557            }
21558
21559            //IE < 11
21560            else{
21561                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
21562            }
21563
21564            return pointer;
21565        }
21566
21567        /**
21568        * Gets the pageX and pageY properties depending on the browser.
21569        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
21570        */
21571        function getEventsPage(e){
21572            var events = [];
21573
21574            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
21575            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
21576
21577            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
21578            if(isTouch && isReallyTouch(e) && options.scrollBar){
21579                events.y = e.touches[0].pageY;
21580                events.x = e.touches[0].pageX;
21581            }
21582
21583            return events;
21584        }
21585
21586        /**
21587        * Slides silently (with no animation) the active slider to the given slide.
21588        * @param noCallback {bool} true or defined -> no callbacks
21589        */
21590        function silentLandscapeScroll(activeSlide, noCallbacks){
21591            setScrollingSpeed (0, 'internal');
21592
21593            if(typeof noCallbacks !== 'undefined'){
21594                //preventing firing callbacks afterSlideLoad etc.
21595                isResizing = true;
21596            }
21597
21598            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
21599
21600            if(typeof noCallbacks !== 'undefined'){
21601                isResizing = false;
21602            }
21603
21604            setScrollingSpeed(originals.scrollingSpeed, 'internal');
21605        }
21606
21607        /**
21608        * Scrolls silently (with no animation) the page to the given Y position.
21609        */
21610        function silentScroll(top){
21611            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
21612            // that's why we round it to 0.
21613            var roundedTop = Math.round(top);
21614
21615            if (options.css3 && options.autoScrolling && !options.scrollBar){
21616                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
21617                transformContainer(translate3d, false);
21618            }
21619            else if(options.autoScrolling && !options.scrollBar){
21620                container.css('top', -roundedTop);
21621            }
21622            else{
21623                $htmlBody.scrollTop(roundedTop);
21624            }
21625        }
21626
21627        /**
21628        * Returns the cross-browser transform string.
21629        */
21630        function getTransforms(translate3d){
21631            return {
21632                '-webkit-transform': translate3d,
21633                '-moz-transform': translate3d,
21634                '-ms-transform':translate3d,
21635                'transform': translate3d
21636            };
21637        }
21638
21639        /**
21640        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
21641        * @type  m (mouse) or k (keyboard)
21642        */
21643        function setIsScrollAllowed(value, direction, type){
21644            switch (direction){
21645                case 'up': isScrollAllowed[type].up = value; break;
21646                case 'down': isScrollAllowed[type].down = value; break;
21647                case 'left': isScrollAllowed[type].left = value; break;
21648                case 'right': isScrollAllowed[type].right = value; break;
21649                case 'all':
21650                    if(type == 'm'){
21651                        setAllowScrolling(value);
21652                    }else{
21653                        setKeyboardScrolling(value);
21654                    }
21655            }
21656        }
21657
21658        /*
21659        * Destroys fullpage.js plugin events and optinally its html markup and styles
21660        */
21661        function destroy(all){
21662            setAutoScrolling(false, 'internal');
21663            setAllowScrolling(false);
21664            setKeyboardScrolling(false);
21665            container.addClass(DESTROYED);
21666
21667            clearTimeout(afterSlideLoadsId);
21668            clearTimeout(afterSectionLoadsId);
21669            clearTimeout(resizeId);
21670            clearTimeout(scrollId);
21671            clearTimeout(scrollId2);
21672
21673            $window
21674                .off('scroll', scrollHandler)
21675                .off('hashchange', hashChangeHandler)
21676                .off('resize', resizeHandler);
21677
21678            $document
21679                .off('click touchstart', SECTION_NAV_SEL + ' a')
21680                .off('mouseenter', SECTION_NAV_SEL + ' li')
21681                .off('mouseleave', SECTION_NAV_SEL + ' li')
21682                .off('click touchstart', SLIDES_NAV_LINK_SEL)
21683                .off('mouseover', options.normalScrollElements)
21684                .off('mouseout', options.normalScrollElements);
21685
21686            $(SECTION_SEL)
21687                .off('click touchstart', SLIDES_ARROW_SEL);
21688
21689            clearTimeout(afterSlideLoadsId);
21690            clearTimeout(afterSectionLoadsId);
21691
21692            //lets make a mess!
21693            if(all){
21694                destroyStructure();
21695            }
21696        }
21697
21698        /*
21699        * Removes inline styles added by fullpage.js
21700        */
21701        function destroyStructure(){
21702            //reseting the `top` or `translate` properties to 0
21703            silentScroll(0);
21704
21705            //loading all the lazy load content
21706            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
21707                setSrc($(this), 'src');
21708            });
21709
21710            container.find('img[data-srcset]').each(function(){
21711                setSrc($(this), 'srcset');
21712            });
21713
21714            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
21715
21716            //removing inline styles
21717            $(SECTION_SEL).css( {
21718                'height': '',
21719                'background-color' : '',
21720                'padding': ''
21721            });
21722
21723            $(SLIDE_SEL).css( {
21724                'width': ''
21725            });
21726
21727            container.css({
21728                'height': '',
21729                'position': '',
21730                '-ms-touch-action': '',
21731                'touch-action': ''
21732            });
21733
21734            $htmlBody.css({
21735                'overflow': '',
21736                'height': ''
21737            });
21738
21739            // remove .fp-enabled class
21740            $('html').removeClass(ENABLED);
21741
21742            // remove .fp-responsive class
21743            $body.removeClass(RESPONSIVE);
21744
21745            // remove all of the .fp-viewing- classes
21746            $.each($body.get(0).className.split(/\s+/), function (index, className) {
21747                if (className.indexOf(VIEWING_PREFIX) === 0) {
21748                    $body.removeClass(className);
21749                }
21750            });
21751
21752            //removing added classes
21753            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
21754                options.scrollOverflowHandler.remove($(this));
21755                $(this).removeClass(TABLE + ' ' + ACTIVE);
21756            });
21757
21758            removeAnimation(container);
21759
21760            //Unwrapping content
21761            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
21762                //unwrap not being use in case there's no child element inside and its just text
21763                $(this).replaceWith(this.childNodes);
21764            });
21765
21766            //removing the applied transition from the fullpage wrapper
21767            container.css({
21768                '-webkit-transition': 'none',
21769                'transition': 'none'
21770            });
21771
21772            //scrolling the page to the top with no animation
21773            $htmlBody.scrollTop(0);
21774
21775            //removing selectors
21776            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
21777            $.each(usedSelectors, function(index, value){
21778                $('.' + value).removeClass(value);
21779            });
21780        }
21781
21782        /*
21783        * Sets the state for a variable with multiple states (original, and temporal)
21784        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
21785        * This function is used to keep track of both states, the original and the temporal one.
21786        * If type is not 'internal', then we assume the user is globally changing the variable.
21787        */
21788        function setVariableState(variable, value, type){
21789            options[variable] = value;
21790            if(type !== 'internal'){
21791                originals[variable] = value;
21792            }
21793        }
21794
21795        /**
21796        * Displays warnings
21797        */
21798        function displayWarnings(){
21799            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
21800            //UNCODE.addition
21801            // if($('html').hasClass(ENABLED)){
21802            //     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
21803            //     return;
21804            // }
21805
21806            // Disable mutually exclusive settings
21807            //UNCODE.addition
21808            // if (options.continuousVertical &&
21809            //     (options.loopTop || options.loopBottom)) {
21810            //     options.continuousVertical = false;
21811            //     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
21812            // }
21813
21814            // if(options.scrollBar && options.scrollOverflow){
21815            //     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
21816            // }
21817
21818            // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
21819            //     options.continuousVertical = false;
21820            //     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
21821            // }
21822
21823            //using extensions? Wrong file!
21824            $.each(extensions, function(index, extension){
21825                //is the option set to true?
21826                if(options[extension]){
21827                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
21828                }
21829            });
21830
21831            //anchors can not have the same value as any element ID or NAME
21832            $.each(options.anchors, function(index, name){
21833
21834                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
21835                var nameAttr = $document.find('[name]').filter(function() {
21836                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
21837                });
21838
21839                var idAttr = $document.find('[id]').filter(function() {
21840                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
21841                });
21842
21843                if(idAttr.length || nameAttr.length ){
21844                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
21845                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
21846                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
21847                }
21848            });
21849        }
21850
21851        /**
21852        * Shows a message in the console of the given type.
21853        */
21854        function showError(type, text){
21855            console && console[type] && console[type]('fullPage: ' + text);
21856        }
21857
21858    }; //end of $.fn.fullpage
21859
21860    if(typeof IScroll !== 'undefined'){
21861        /*
21862        * Turns iScroll `mousewheel` option off dynamically
21863        * https://github.com/cubiq/iscroll/issues/1036
21864        */
21865        IScroll.prototype.wheelOn = function () {
21866            this.wrapper.addEventListener('wheel', this);
21867            this.wrapper.addEventListener('mousewheel', this);
21868            this.wrapper.addEventListener('DOMMouseScroll', this);
21869        };
21870
21871        /*
21872        * Turns iScroll `mousewheel` option on dynamically
21873        * https://github.com/cubiq/iscroll/issues/1036
21874        */
21875        IScroll.prototype.wheelOff = function () {
21876            this.wrapper.removeEventListener('wheel', this);
21877            this.wrapper.removeEventListener('mousewheel', this);
21878            this.wrapper.removeEventListener('DOMMouseScroll', this);
21879        };
21880    }
21881
21882    /**
21883     * An object to handle overflow scrolling.
21884     * This uses jquery.slimScroll to accomplish overflow scrolling.
21885     * It is possible to pass in an alternate scrollOverflowHandler
21886     * to the fullpage.js option that implements the same functions
21887     * as this handler.
21888     *
21889     * @type {Object}
21890     */
21891    var iscrollHandler = {
21892        refreshId: null,
21893        iScrollInstances: [],
21894
21895        // Enables or disables the mouse wheel for the active section or all slides in it
21896        toggleWheel: function(value){
21897            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
21898            scrollable.each(function(){
21899                var iScrollInstance = $(this).data('iscrollInstance');
21900                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
21901                    if(value){
21902                        iScrollInstance.wheelOn();
21903                    }
21904                    else{
21905                        iScrollInstance.wheelOff();
21906                    }
21907                }
21908            });
21909        },
21910
21911        /**
21912        * Turns off iScroll for the destination section.
21913        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
21914        * scroll the destination section/slide before the sections animations ends.
21915        */
21916        onLeave: function(){
21917            iscrollHandler.toggleWheel(false);
21918        },
21919
21920        // Turns off iScroll for the leaving section
21921        beforeLeave: function(){
21922            iscrollHandler.onLeave()
21923        },
21924
21925        // Turns on iScroll on section load
21926        afterLoad: function(){
21927            iscrollHandler.toggleWheel(true);
21928        },
21929
21930        /**
21931         * Called when overflow scrolling is needed for a section.
21932         *
21933         * @param  {Object} element      jQuery object containing current section
21934         * @param  {Number} scrollHeight Current window height in pixels
21935         */
21936        create: function(element, scrollHeight) {
21937            var scrollable = element.find(SCROLLABLE_SEL);
21938
21939            scrollable.height(scrollHeight);
21940            scrollable.each(function() {
21941                var $this = $(this);
21942                var iScrollInstance = $this.data('iscrollInstance');
21943                if (iScrollInstance) {
21944                    $.each(iscrollHandler.iScrollInstances, function(){
21945                        $(this).destroy();
21946                    });
21947                }
21948
21949                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
21950                iscrollHandler.iScrollInstances.push(iScrollInstance);
21951
21952                //off by default until the section gets active
21953                iScrollInstance.wheelOff();
21954
21955                $this.data('iscrollInstance', iScrollInstance);
21956            });
21957        },
21958
21959        /**
21960         * Return a boolean depending on whether the scrollable element is a
21961         * the end or at the start of the scrolling depending on the given type.
21962         *
21963         * @param  {String}  type       Either 'top' or 'bottom'
21964         * @param  {Object}  scrollable jQuery object for the scrollable element
21965         * @return {Boolean}
21966         */
21967        isScrolled: function(type, scrollable) {
21968            var scroller = scrollable.data('iscrollInstance');
21969
21970            //no scroller?
21971            if (!scroller) {
21972                return true;
21973            }
21974
21975            if (type === 'top') {
21976                return scroller.y >= 0 && !scrollable.scrollTop();
21977            } else if (type === 'bottom') {
21978                return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
21979            }
21980        },
21981
21982        /**
21983         * Returns the scrollable element for the given section.
21984         * If there are landscape slides, will only return a scrollable element
21985         * if it is in the active slide.
21986         *
21987         * @param  {Object}  activeSection jQuery object containing current section
21988         * @return {Boolean}
21989         */
21990        scrollable: function(activeSection){
21991            // if there are landscape slides, we check if the scrolling bar is in the current one or not
21992            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
21993                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
21994            }
21995            return activeSection.find(SCROLLABLE_SEL);
21996        },
21997
21998        /**
21999         * Returns the scroll height of the wrapped content.
22000         * If this is larger than the window height minus section padding,
22001         * overflow scrolling is needed.
22002         *
22003         * @param  {Object} element jQuery object containing current section
22004         * @return {Number}
22005         */
22006        scrollHeight: function(element) {
22007            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
22008        },
22009
22010        /**
22011         * Called when overflow scrolling is no longer needed for a section.
22012         *
22013         * @param  {Object} element      jQuery object containing current section
22014         */
22015        remove: function(element) {
22016            var scrollable = element.find(SCROLLABLE_SEL);
22017            if (scrollable.length) {
22018                var iScrollInstance = scrollable.data('iscrollInstance');
22019                iScrollInstance.destroy();
22020
22021                scrollable.data('iscrollInstance', null);
22022            }
22023            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
22024        },
22025
22026        /**
22027         * Called when overflow scrolling has already been setup but the
22028         * window height has potentially changed.
22029         *
22030         * @param  {Object}
vendor: 16,384 bytes, lines 22030-22577
22030 element      jQuery object containing current section
22031         * @param  {Number} scrollHeight Current window height in pixels
22032         */
22033        update: function(element, scrollHeight) {
22034            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
22035            //short period of time.
22036            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
22037            clearTimeout(iscrollHandler.refreshId);
22038            iscrollHandler.refreshId = setTimeout(function(){
22039                $.each(iscrollHandler.iScrollInstances, function(){
22040                    $(this).get(0).refresh();
22041                });
22042            }, 150);
22043
22044            //updating the wrappers height
22045            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
22046        },
22047
22048        /**
22049         * Called to get any additional elements needed to wrap the section
22050         * content in order to facilitate overflow scrolling.
22051         *
22052         * @return {String|Object} Can be a string containing HTML,
22053         *                         a DOM element, or jQuery object.
22054         */
22055        wrapContent: function() {
22056            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
22057        }
22058    };
22059});
22060
22061
22062
22063/* ========================================================================
22064 * Bootstrap: collapse.js v3.1.1
22065 * http://getbootstrap.com/javascript/#collapse
22066 * ========================================================================
22067 * Copyright 2011-2014 Twitter, Inc.
22068 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22069 * ======================================================================== */
22070
22071
22072+function ($) {
22073  'use strict';
22074
22075  // COLLAPSE PUBLIC CLASS DEFINITION
22076  // ================================
22077
22078  var Collapse = function (element, options) {
22079    this.$element      = $(element)
22080    this.options       = $.extend({}, Collapse.DEFAULTS, options)
22081    this.transitioning = null
22082
22083    if (this.options.parent) this.$parent = $(this.options.parent)
22084    if (this.options.toggle) this.toggle()
22085  }
22086
22087  Collapse.DEFAULTS = {
22088    toggle: true
22089  }
22090
22091  Collapse.prototype.dimension = function () {
22092    var hasWidth = this.$element.hasClass('width')
22093    return hasWidth ? 'width' : 'height'
22094  }
22095
22096  Collapse.prototype.show = function () {
22097    if (this.transitioning || this.$element.hasClass('in')) return
22098
22099    var startEvent = $.Event('show.bs.collapse')
22100    this.$element.trigger(startEvent)
22101    if (startEvent.isDefaultPrevented()) return
22102
22103    var actives = this.$parent && this.$parent.find('> .panel > .in')
22104
22105    if (actives && actives.length) {
22106      var hasData = actives.data('bs.collapse')
22107      if (hasData && hasData.transitioning) return
22108      actives.collapse('hide')
22109      hasData || actives.data('bs.collapse', null)
22110    }
22111
22112    var dimension = this.dimension()
22113
22114    this.$element
22115      .removeClass('collapse')
22116      .addClass('collapsing')[dimension](0)
22117
22118    this.transitioning = 1
22119
22120    var complete = function (e) {
22121      if (e && e.target != this.$element[0]) return
22122      this.$element
22123        .removeClass('collapsing')
22124        .addClass('collapse in')[dimension]('auto')
22125      this.transitioning = 0
22126      this.$element.trigger('shown.bs.collapse')
22127    }
22128
22129    if (!$.support.transition) return complete.call(this)
22130
22131    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
22132
22133    this.$element
22134      .one($.support.transition.end, $.proxy(complete, this))
22135      .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
22136  }
22137
22138  Collapse.prototype.hide = function () {
22139    if (this.transitioning || !this.$element.hasClass('in')) return
22140
22141    var startEvent = $.Event('hide.bs.collapse')
22142    this.$element.trigger(startEvent)
22143    if (startEvent.isDefaultPrevented()) return
22144
22145    var dimension = this.dimension()
22146
22147    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
22148
22149    this.$element
22150      .addClass('collapsing')
22151      .removeClass('collapse')
22152      .removeClass('in')
22153
22154    this.transitioning = 1
22155
22156    var complete = function (e) {
22157      if (e && e.target != this.$element[0]) return
22158      this.transitioning = 0
22159      this.$element
22160        .trigger('hidden.bs.collapse')
22161        .removeClass('collapsing')
22162        .addClass('collapse')
22163    }
22164
22165    if (!$.support.transition) return complete.call(this)
22166
22167    this.$element
22168      [dimension](0)
22169      .one($.support.transition.end, $.proxy(complete, this))
22170      .emulateTransitionEnd(350)
22171  }
22172
22173  Collapse.prototype.toggle = function () {
22174    this[this.$element.hasClass('in') ? 'hide' : 'show']()
22175  }
22176
22177
22178  // COLLAPSE PLUGIN DEFINITION
22179  // ==========================
22180
22181  var old = $.fn.collapse
22182
22183  $.fn.collapse = function (option) {
22184    return this.each(function () {
22185      var $this   = $(this)
22186      var data    = $this.data('bs.collapse')
22187      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
22188
22189      if (!data && options.toggle && option == 'show') option = !option
22190      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
22191      if (typeof option == 'string') data[option]()
22192    })
22193  }
22194
22195  $.fn.collapse.Constructor = Collapse
22196
22197
22198  // COLLAPSE NO CONFLICT
22199  // ====================
22200
22201  $.fn.collapse.noConflict = function () {
22202    $.fn.collapse = old
22203    return this
22204  }
22205
22206
22207  // COLLAPSE DATA-API
22208  // =================
22209
22210  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
22211    var $this   = $(this), href
22212    var target  = $this.attr('data-target')
22213        || e.preventDefault()
22214        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
22215    //Edited by Uncode to replace ID in panel [START]
22216    var _target = href.replace(/^#/, "");
22217    if ( $('[data-id="' + _target + '"]').length ) {
22218      var $target = $('[data-id="' + _target + '"]')
22219    } else {
22220      var $target = $(target)
22221    }
22222    //Edited by Uncode to replace ID in panel [END]
22223    var data    = $target.data('bs.collapse')
22224    var option  = data ? 'toggle' : $this.data()
22225    var parent  = $this.attr('data-parent')
22226    var $parent = parent && $(parent)
22227
22228    if (!data || !data.transitioning) {
22229      if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
22230      $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
22231    }
22232
22233    $target.collapse(option)
22234  })
22235
22236}(jQuery);
22237
22238
22239/* ========================================================================
22240 * Bootstrap: tab.js v3.1.1
22241 * http://getbootstrap.com/javascript/#tabs
22242 * ========================================================================
22243 * Copyright 2011-2014 Twitter, Inc.
22244 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22245 * ======================================================================== */
22246
22247
22248+function ($) {
22249  'use strict';
22250
22251  // TAB CLASS DEFINITION
22252  // ====================
22253
22254  var Tab = function (element) {
22255    this.element = $(element)
22256  }
22257
22258  Tab.prototype.show = function () {
22259    var $this    = this.element
22260    var $ul      = $this.closest('ul:not(.dropdown-menu)')
22261    var selector = $this.data('target')
22262
22263    if (!selector) {
22264      selector = $this.attr('href')
22265      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
22266    }
22267
22268    if ($this.parent('li').hasClass('active')) return
22269
22270    var previous = $ul.find('.active:last a')[0]
22271    var e        = $.Event('show.bs.tab', {
22272      relatedTarget: previous
22273    })
22274
22275    $this.trigger(e)
22276
22277    if (e.isDefaultPrevented()) return
22278
22279    //Edited by Uncode to replace ID in panel [START]
22280    var _target = selector.replace(/^#/, "");
22281    if ( $('[data-id="' + _target + '"]').length )
22282      var $target = $('[data-id="' + _target + '"]')
22283    else
22284      var $target = $(selector)
22285    //Edited by Uncode to replace ID in panel [END]
22286
22287    this.activate($this.parent('li'), $ul)
22288    this.activate($target, $target.parent(), function () {
22289      $this.trigger({
22290        type: 'shown.bs.tab',
22291        relatedTarget: previous
22292      })
22293    })
22294  }
22295
22296  Tab.prototype.activate = function (element, container, callback) {
22297    var $active    = container.find('> .active')
22298    var transition = callback
22299      && $.support.transition
22300      && $active.hasClass('fade')
22301
22302    function next() {
22303      $active
22304        .removeClass('active')
22305        .find('> .dropdown-menu > .active')
22306        .removeClass('active')
22307
22308      element.addClass('active')
22309
22310      if (transition) {
22311        element[0].offsetWidth // reflow for transition
22312        element.addClass('in')
22313      } else {
22314        element.removeClass('fade')
22315      }
22316
22317      if (element.parent('.dropdown-menu')) {
22318        element.closest('li.dropdown').addClass('active')
22319      }
22320
22321      callback && callback()
22322    }
22323
22324    transition ?
22325      $active
22326        .one($.support.transition.end, next)
22327        .emulateTransitionEnd(150) :
22328      next()
22329
22330    $active.removeClass('in')
22331  }
22332
22333
22334  // TAB PLUGIN DEFINITION
22335  // =====================
22336
22337  var old = $.fn.tab
22338
22339  $.fn.tab = function ( option ) {
22340    return this.each(function () {
22341      var $this = $(this)
22342      var data  = $this.data('bs.tab')
22343
22344      if (!data) $this.data('bs.tab', (data = new Tab(this)))
22345      if (typeof option == 'string') data[option]()
22346    })
22347  }
22348
22349  $.fn.tab.Constructor = Tab
22350
22351
22352  // TAB NO CONFLICT
22353  // ===============
22354
22355  $.fn.tab.noConflict = function () {
22356    $.fn.tab = old
22357    return this
22358  }
22359
22360
22361  // TAB DATA-API
22362  // ============
22363
22364  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
22365    e.preventDefault()
22366    $(this).tab('show')
22367  })
22368
22369}(jQuery);
22370
22371
22372/* ========================================================================
22373 * Bootstrap: tooltip.js v3.1.1
22374 * http://getbootstrap.com/javascript/#tooltip
22375 * Inspired by the original jQuery.tipsy by Jason Frame
22376 * ========================================================================
22377 * Copyright 2011-2014 Twitter, Inc.
22378 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22379 * ======================================================================== */
22380
22381
22382+function ($) {
22383  'use strict';
22384
22385  // TOOLTIP PUBLIC CLASS DEFINITION
22386  // ===============================
22387
22388  var Tooltip = function (element, options) {
22389    this.type       =
22390    this.options    =
22391    this.enabled    =
22392    this.timeout    =
22393    this.hoverState =
22394    this.$element   = null
22395
22396    this.init('tooltip', element, options)
22397  }
22398
22399  Tooltip.DEFAULTS = {
22400    animation: true,
22401    placement: 'top',
22402    selector: false,
22403    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
22404    trigger: 'hover focus',
22405    title: '',
22406    delay: 0,
22407    html: false,
22408    container: false,
22409    viewport: {
22410      selector: 'body',
22411      padding: 0
22412    }
22413  }
22414
22415  Tooltip.prototype.init = function (type, element, options) {
22416    this.enabled   = true
22417    this.type      = type
22418    this.$element  = $(element)
22419    this.options   = this.getOptions(options)
22420    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
22421
22422    var triggers = this.options.trigger.split(' ')
22423
22424    for (var i = triggers.length; i--;) {
22425      var trigger = triggers[i]
22426
22427      if (trigger == 'click') {
22428        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
22429      } else if (trigger != 'manual') {
22430        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
22431        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
22432
22433        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
22434        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
22435      }
22436    }
22437
22438    this.options.selector ?
22439      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
22440      this.fixTitle()
22441  }
22442
22443  Tooltip.prototype.getDefaults = function () {
22444    return Tooltip.DEFAULTS
22445  }
22446
22447  Tooltip.prototype.getOptions = function (options) {
22448    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
22449
22450    if (options.delay && typeof options.delay == 'number') {
22451      options.delay = {
22452        show: options.delay,
22453        hide: options.delay
22454      }
22455    }
22456
22457    return options
22458  }
22459
22460  Tooltip.prototype.getDelegateOptions = function () {
22461    var options  = {}
22462    var defaults = this.getDefaults()
22463
22464    this._options && $.each(this._options, function (key, value) {
22465      if (defaults[key] != value) options[key] = value
22466    })
22467
22468    return options
22469  }
22470
22471  Tooltip.prototype.enter = function (obj) {
22472    var self = obj instanceof this.constructor ?
22473      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
22474
22475    clearTimeout(self.timeout)
22476
22477    self.hoverState = 'in'
22478
22479    if (!self.options.delay || !self.options.delay.show) return self.show()
22480
22481    self.timeout = setTimeout(function () {
22482      if (self.hoverState == 'in') self.show()
22483    }, self.options.delay.show)
22484  }
22485
22486  Tooltip.prototype.leave = function (obj) {
22487    var self = obj instanceof this.constructor ?
22488      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
22489
22490    clearTimeout(self.timeout)
22491
22492    self.hoverState = 'out'
22493
22494    if (!self.options.delay || !self.options.delay.hide) return self.hide()
22495
22496    self.timeout = setTimeout(function () {
22497      if (self.hoverState == 'out') self.hide()
22498    }, self.options.delay.hide)
22499  }
22500
22501  Tooltip.prototype.show = function () {
22502    var e = $.Event('show.bs.' + this.type)
22503
22504    if (this.hasContent() && this.enabled) {
22505      this.$element.trigger(e)
22506
22507      if (e.isDefaultPrevented()) return
22508      var that = this;
22509
22510      var $tip = this.tip()
22511
22512      this.setContent()
22513
22514      if (this.options.animation) $tip.addClass('fade')
22515
22516      var placement = typeof this.options.placement == 'function' ?
22517        this.options.placement.call(this, $tip[0], this.$element[0]) :
22518        this.options.placement
22519
22520      var autoToken = /\s?auto?\s?/i
22521      var autoPlace = autoToken.test(placement)
22522      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
22523
22524      $tip
22525        .detach()
22526        .css({ top: 0, left: 0, display: 'block' })
22527        .addClass(placement)
22528
22529      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
22530
22531      var pos          = this.getPosition()
22532      var actualWidth  = $tip[0].offsetWidth
22533      var actualHeight = $tip[0].offsetHeight
22534
22535      if (autoPlace) {
22536        var orgPlacement = placement
22537        var $parent      = this.$element.parent()
22538        var parentDim    = this.getPosition($parent)
22539
22540        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
22541                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
22542                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
22543                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
22544                    placement
22545
22546        $tip
22547          .removeClass(orgPlacement)
22548          .addClass(placement)
22549      }
22550
22551      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
22552
22553      this.applyPlacement(calculatedOffset, placement)
22554      this.hoverState = null
22555
22556      var complete = function() {
22557        that.$element.trigger('shown.bs.' + that.type)
22558      }
22559
22560      $.support.transition && this.$tip.hasClass('fade') ?
22561        $tip
22562          .one($.support.transition.end, complete)
22563          .emulateTransitionEnd(150) :
22564        complete()
22565    }
22566  }
22567
22568  Tooltip.prototype.applyPlacement = function (offset, placement) {
22569    var $tip   = this.tip()
22570    var width  = $tip[0].offsetWidth
22571    var height = $tip[0].offsetHeight
22572
22573    // manually read margins because getBoundingClientRect includes difference
22574    var marginTop = parseInt($tip.css('margin-top'), 10)
22575    var marginLeft = parseInt($tip.css('margin-left'), 10)
22576
22577    // we must check for NaN for i
22577e 8/9
22578    if (isNaN(marginTop))  marginTop  = 0
22579    if (isNaN(marginLeft)) marginLeft = 0
22580
22581    offset.top  = offset.top  + marginTop
22582    offset.left = offset.left + marginLeft
22583
22584    // $.fn.offset doesn't round pixel values
22585    // so we use setOffset directly with our own function B-0
22586    $.offset.setOffset($tip[0], $.extend({
22587      using: function (props) {
22588        $tip.css({
22589          top: Math.round(props.top),
22590          left: Math.round(props.left)
22591        })
22592      }
22593    }, offset), 0)
22594
22595    $tip.addClass('in')
22596
22597    // check to see if placing tip in new offset caused the tip to resize itself
22598    var actualWidth  = $tip[0].offsetWidth
22599    var actualHeight = $tip[0].offsetHeight
22600
22601    if (placement == 'top' && actualHeight != height) {
22602      offset.top = offset.top + height - actualHeight
22603    }
22604
22605    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
22606
22607    if (delta.left) offset.left += delta.left
22608    else offset.top += delta.top
22609
22610    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
22611    var arrowPosition       = delta.left ? 'left'        : 'top'
22612    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
22613
22614    $tip.offset(offset)
22615    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
22616  }
22617
22618  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
22619    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
22620  }
22621
22622  Tooltip.prototype.setContent = function () {
22623    var $tip  = this.tip()
22624    var title = this.getTitle()
22625
22626    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
22627    $tip.removeClass('fade in top bottom left right')
22628  }
22629
22630  Tooltip.prototype.hide = function () {
22631    var that = this
22632    var $tip = this.tip()
22633    var e    = $.Event('hide.bs.' + this.type)
22634
22635    function complete() {
22636      if (that.hoverState != 'in') $tip.detach()
22637      that.$element.trigger('hidden.bs.' + that.type)
22638    }
22639
22640    this.$element.trigger(e)
22641
22642    if (e.isDefaultPrevented()) return
22643
22644    $tip.removeClass('in')
22645
22646    $.support.transition && this.$tip.hasClass('fade') ?
22647      $tip
22648        .one($.support.transition.end, complete)
22649        .emulateTransitionEnd(150) :
22650      complete()
22651
22652    this.hoverState = null
22653
22654    return this
22655  }
22656
22657  Tooltip.prototype.fixTitle = function () {
22658    var $e = this.$element
22659    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
22660      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
22661    }
22662  }
22663
22664  Tooltip.prototype.hasContent = function () {
22665    return this.getTitle()
22666  }
22667
22668  Tooltip.prototype.getPosition = function ($element) {
22669    $element   = $element || this.$element
22670    var el     = $element[0]
22671    var isBody = el.tagName == 'BODY'
22672    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
22673      scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
22674      width:  isBody ? $(window).width()  : $element.outerWidth(),
22675      height: isBody ? $(window).height() : $element.outerHeight()
22676    }, isBody ? {top: 0, left: 0} : $element.offset())
22677  }
22678
22679  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
22680    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
22681           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
22682           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
22683        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
22684
22685  }
22686
22687  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
22688    var delta = { top: 0, left: 0 }
22689    if (!this.$viewport) return delta
22690
22691    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
22692    var viewportDimensions = this.getPosition(this.$viewport)
22693
22694    if (/right|left/.test(placement)) {
22695      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
22696      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
22697      if (topEdgeOffset < viewportDimensions.top) { // top overflow
22698        delta.top = viewportDimensions.top - topEdgeOffset
22699      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
22700        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
22700EdgeOffset
22701      }
22702    } else {
22703      var leftEdgeOffset  = pos.left - viewportPadding
22704      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
22705      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
22706        delta.left = viewportDimensions.left - leftEdgeOffset
22707      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
22708        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
22709      }
22710    }
22711
22712    return delta
22713  }
22714
22715  Tooltip.prototype.getTitle = function () {
22716    var title
22717    var $e = this.$element
22718    var o  = this.options
22719
22720    title = $e.attr('data-original-title')
22721      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
22722
22723    return title
22724  }
22725
22726  Tooltip.prototype.tip = function () {
22727    return this.$tip = this.$tip || $(this.options.template)
22728  }
22729
22730  Tooltip.prototype.arrow = function () {
22731    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
22732  }
22733
22734  Tooltip.prototype.validate = function () {
22735    if (!this.$element[0].parentNode) {
22736      this.hide()
22737      this.$element = null
22738      this.options  = null
22739    }
22740  }
22741
22742  Tooltip.prototype.enable = function () {
22743    this.enabled = true
22744  }
22745
22746  Tooltip.prototype.disable = function () {
22747    this.enabled = false
22748  }
22749
22750  Tooltip.prototype.toggleEnabled = function () {
22751    this.enabled = !this.enabled
22752  }
22753
22754  Tooltip.prototype.toggle = function (e) {
22755    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
22756    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
22757  }
22758
22759  Tooltip.prototype.destroy = function () {
22760    clearTimeout(this.timeout)
22761    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
22762  }
22763
22764
22765  // TOOLTIP PLUGIN DEFINITION
22766  // =========================
22767
22768  var old = $.fn.tooltip
22769
22770  $.fn.tooltip = function (option) {
22771    return this.each(function () {
22772      var $this   = $(this)
22773      var data    = $this.data('bs.tooltip')
22774      var options = typeof option == 'object' && option
22775
22776      if (!data && option == 'destroy') return
22777      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
22778      if (typeof option == 'string') data[option]()
22779    })
22780  }
22781
22782  $.fn.tooltip.Constructor = Tooltip
22783
22784
22785  // TOOLTIP NO CONFLICT
22786  // ===================
22787
22788  $.fn.tooltip.noConflict = function () {
22789    $.fn.tooltip = old
22790    return this
22791  }
22792
22793}(jQuery);
22794
22795
22796/* ========================================================================
22797 * Bootstrap: transition.js v3.1.1
22798 * http://getbootstrap.com/javascript/#transitions
22799 * ========================================================================
22800 * Copyright 2011-2014 Twitter, Inc.
22801 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22802 * ======================================================================== */
22803
22804
22805+function ($) {
22806  'use strict';
22807
22808  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
22809  // ============================================================
22810
22811  function transitionEnd() {
22812    var el = document.createElement('bootstrap')
22813
22814    var transEndEventNames = {
22815      WebkitTransition : 'webkitTransitionEnd',
22816      MozTransition    : 'transitionend',
22817      OTransition      : 'oTransitionEnd otransitionend',
22818      transition       : 'transitionend'
22819    }
22820
22821    for (var name in transEndEventNames) {
22822      if (el.style[name] !== undefined) {
22823        return { end: transEndEventNames[name] }
22824      }
22825    }
22826
22827    return false // explicit for ie8 (  ._.)
22828  }
22829
22830  // http://blog.alexmaccaw.com/css-transitions
22831  $.fn.emulateTransitionEnd = function (duration) {
22832    var called = false, $el = this
22833    $(this).one($.support.transition.end, function () { called = true })
22834    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
22835    setTimeout(callback, duration)
22836    return this
22837  }
22838
22839  $(function () {
22840    $.support.transition = transitionEnd()
22841  })
22842
22843}(jQuery);
22844
22845

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.