PageSourceSearch

https://www.avenueofstars.com.hk/wp-content/themes/uncode/library/js/plugins.js?ver=1427860823

js avenueofstars.com.hk collected 2026-09-24 22:20:49 UTC 737,184 bytes, 22,832 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			},      init: function() {
43				if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
44					$headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }',
45																					'.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
46				}
47			},
48			bindResize: function(eventName, resizeFunction) {
49				var timeoutId;
50				$(window).unbind(eventName).bind(eventName, function() {
51					if( timeoutId ) {
52						clearTimeout( timeoutId );
53					}
54					timeoutId = setTimeout( resizeFunction, 300 );
55				});
56			},
57			getStyleId: function(id)
58			{
59				return BigText.STYLE_ID + '-' + id;
60			},
61			generateStyleTag: function(id, css)
62			{
63				return $('<style>' + css.join('\n') + '</style>').attr('id', id);
64			},
65			clearCss: function(id)
66			{
67				var styleId = BigText.getStyleId(id);
68				$('#' + styleId).remove();
69			},
70			generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
71			{
72				var css = [];
73
74				BigText.clearCss(id);
75
76				for(var j=0, k=linesFontSizes.length; j<k; j++) {
77					css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
78						(minFontSizes[j] ? ' white-space: normal;' : '') +
79						(linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
80						(lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
81						'}');
82				}
83
84				return BigText.generateStyleTag(BigText.getStyleId(id), css);
85			},
86			jQueryMethod: function(options)
87			{
88				BigText.init();
89
90				options = $.extend({
91					minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
92					maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
93					childSelector: '',
94					resize: true
95				}, options || {});
96
97				this.each(function()
98				{
99					var $t = $(this).addClass('bigtext'),
100						maxWidth = $t.width(),
101						id = $t.attr('id'),
102						$children = options.childSelector ? $t.find( options.childSelector ) : $t.children();
103
104					if(!id) {
105						id = 'bigtext-id' + (counter++);
106						$t.attr('id', id);
107					}
108
109					if(options.resize) {
110						BigText.bindResize('resize.bigtext-event-' + id, function()
111						{
112							// TODO only call this if the width has changed.
113							BigText.jQueryMethod.call($('#' + id), options);
114						});
115					}
116
117					BigText.clearCss(id);
118
119					$children.addClass(function(lineNumber, className)
120					{
121						// remove existing line classes.
122						return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
123								BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
124					});
125
126					var sizes = calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize);
127					$headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));
128				});
129
130				return this.trigger('bigtext:complete');
131			}
132		};
133
134	function testLineDimensions($line, maxWidth, property, size, interval, units, previousWidth)
135	{
136		var width;
137		previousWidth = typeof previousWidth === 'number' ? previousWidth : 0;
138		$line.css(property, size + units);
139
140		width = $line.width();
141
142		if(width >= maxWidth) {
143
144			$line.css(property, '');
145
146			if(width === maxWidth) {
147				return {
148					match: 'exact',
149					size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
150				};
151			}
152
153			// Since this is an estimate, we calculate how far over the width we went with the new value.
154			// If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value.
155			// Otherwise, we revert to the underestimate.
156			var under = maxWidth - previousWidth,
157				over = width - maxWidth;
158
159			return {
160				match: 'estimate',
161				size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3))
162			};
163		}
164
165		return width;
166	}
167
168	function calculateSizes($t, $children, maxWidth, maxFontSize, minFontSize)
169	{
170		var $c = $t.clone(true)
171			.addClass('bigtext-cloned')
172			.css({
173				fontFamily: $t.css('font-family'),
174				textTransform: $t.css('text-transform'),
175				wordSpacing: $t.css('word-spacing'),
176				letterSpacing: $t.css('letter-spacing'),
177				position: 'absolute',
178				left: BigText.DEBUG_MODE ? 0 : -9999,
179				top: BigText.DEBUG_MODE ? 0 : -9999
180			})
181			.appendTo(document.body);
182
183		// font-size isn't the only thing we can modify, we can also mess with:
184		// word-spacing and letter-spacing. WebKit does not respect subpixel
185		// letter-spacing, word-spacing, or font-size.
186		// TODO try -webkit-transform: scale() as a workaround.
187		var fontSizes = [],
188			wordSpacings = [],
189			minFontSizes = [],
190			ratios = [];
191
192		$children.css('float', 'left').each(function() {
193			var $line = $(this),
194				// TODO replace 8, 4 with a proportional size to the calculated font-size.
195				intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1],
196				lineMax,
197				newFontSize;
198
199			if($line.hasClass(BigText.EXEMPT_CLASS)) {
200				fontSizes.push(null);
201				ratios.push(null);
202				minFontSizes.push(false);
203				return;
204			}
205
206			// TODO we can cache this ratio?
207			var autoGuessSubtraction = 32, // font size in px
208				currentFontSize = parseFloat($line.css('font-size')),
209				ratio = ( $line.width() / currentFontSize ).toFixed(6);
210
211			newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction;
212
213			outer: for(var m=0, n=intervals.length; m<n; m++) {
214				inner: for(var j=1, k=10; j<=k; j++) {
215					if(newFontSize + j*intervals[m] > maxFontSize) {
216						newFontSize = maxFontSize;
217						break outer;
218					}
219
220					lineMax = testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax);
221					if(typeof lineMax !== 'number') {
222						newFontSize = lineMax.size;
223
224						if(lineMax.match === 'exact') {
225							break outer;
226						}
227						break inner;
228					}
229				}
230			}
231
232			ratios.push(maxWidth / newFontSize);
233
234			if(newFontSize > maxFontSize) {
235				fontSizes.push(maxFontSize);
236				minFontSizes.push(false);
237			} else if(!!minFontSize && newFontSize < minFontSize) {
238				fontSizes.push(minFontSize);
239				minFontSizes.push(true);
240			} else {
241				fontSizes.push(newFontSize);
242				minFontSizes.push(false);
243			}
244		}).each(function(lineNumber) {
245			var $line = $(this),
246				wordSpacing = 0,
247				interval = 1,
248				maxWordSpacing;
249
250			if($line.hasClass(BigText.EXEMPT_CLASS)) {
251				wordSpacings.push(null);
252				return;
253			}
254
255			// must re-use font-size, even though it was removed above.
256			$line.css('font-size', fontSizes[lineNumber] + 'px');
257
258			for(var m=1, n=3; m<n; m+=interval) {
259				maxWordSpacing = testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing);
260				if(typeof maxWordSpacing !== 'number') {
261					wordSpacing = maxWordSpacing.size;
262					break;
263				}
264			}
265
266			$line.css('font-size', '');
267			wordSpacings.push(wordSpacing);
268		}).removeAttr('style');
269
270		if( !BigText.DEBUG_MODE ) {
271			$c.remove();
272		} else {
273			$c.css({
274				'background-color': 'rgba(255,255,255,.4)'
275			});
276		}
277
278		return {
279			fontSizes: fontSizes,
280			wordSpacings: wordSpacings,
281			ratios: ratios,
282			minFontSizes: minFontSizes
283		};
284	}
285
286	$.fn.bigtext = BigText.jQueryMethod;
287	window.BigText = BigText;
288
289})(this, jQuery);
290
291/*!
292 * Isotope PACKAGED v2.2.2
293 *
294 * Licensed GPLv3 for open source use
295 * or Isotope Commercial License for commercial use
296 *
297 * http://isotope.metafizzy.co
298 * Copyright 2015 Metafizzy
299 */
300
301/**
302 * Bridget makes jQuery widgets
303 * v1.1.0
304 * MIT license
305 */
306
307( function( window ) {
308
309
310
311// -------------------------- utils -------------------------- //
312
313var slice = Array.prototype.slice;
314
315function noop() {}
316
317// -------------------------- definition -------------------------- //
318
319function defineBridget( $ ) {
320
321// bail if no jQuery
322if ( !$ ) {
323	return;
324}
325
326// -------------------------- addOptionMethod -------------------------- //
327
328/**
329 * adds option method -> $().plugin('option', {...})
330 * @param {Function} PluginClass - constructor class
331 */
332function addOptionMethod( PluginClass ) {
333	// don't overwrite original option method
334	if ( PluginClass.prototype.option ) {
335		return;
336	}
337
338	// option setter
339	PluginClass.prototype.option = function( opts ) {
340		// bail out if not an object
341		if ( !$.isPlainObject( opts ) ){
342			return;
343		}
344		this.options = $.extend( true, this.options, opts );
345	};
346}
347
348// -------------------------- plugin bridge -------------------------- //
349
350// helper function for logging errors
351// $.error breaks jQuery chaining
352var logError = typeof console === 'undefined' ? noop :
353	function( message ) {
354		console.error( message );
355	};
356
357/**
358 * jQuery plugin bridge, access methods like $elem.plugin('method')
359 * @param {String} namespace - plugin name
360 * @param {Function} PluginClass - constructor class
361 */
362function bridge( namespace, PluginClass ) {
363	// add to jQuery fn namespace
364	$.fn[ namespace ] = function( options ) {
365		if ( typeof options === 'string' ) {
366			// call plugin method when first argument is a string
367			// get arguments for method
368			var args = slice.call( arguments, 1 );
369
370			for ( var i=0, len = this.length; i < len; i++ ) {
371				var elem = this[i];
372				var instance = $.data( elem, namespace );
373				if ( !instance ) {
374					logError( "cannot call methods on " + namespace + " prior to initialization; " +
375						"attempted to call '" + options + "'" );
376					continue;
377				}
378				if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
379					logError( "no such method '" + options + "' for " + namespace + " instance" );
380					continue;
381				}
382
383				// trigger method with arguments
384				var returnValue = instance[ options ].apply( instance, args );
385
386				// break look and return first value if provided
387				if ( returnValue !== undefined ) {
388					return returnValue;
389				}
390			}
391			// return this if no return value
392			return this;
393		} else {
394			return this.each( function() {
395				var instance = $.data( this, namespace );
396				if ( instance ) {
397					// apply options & init
398					instance.option( options );
399					instance._init();
400				} else {
401					// initialize new instance
402					instance = new PluginClass( this, options );
403					$.data( this, namespace, instance );
404				}
405			});
406		}
407	};
408
409}
410
411// -------------------------- bridget -------------------------- //
412
413/**
414 * converts a Prototypical class into a proper jQuery plugin
415 *   the class must have a ._init method
416 * @param {String} namespace - plugin name, used in $().pluginName
417 * @param {Function} PluginClass - constructor class
418 */
419$.bridget = function( namespace, PluginClass ) {
420	addOptionMethod( PluginClass );
421	bridge( namespace, PluginClass );
422};
423
424return $.bridget;
425
426}
427
428// transport
429if ( typeof define === 'function' && define.amd ) {
430	// AMD
431	define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
432} else if ( typeof exports === 'object' ) {
433	defineBridget( require('jquery') );
434} else {
435	// get jquery from browser global
436	defineBridget( window.jQuery );
437}
438
439})( window );
440
441/*!
442 * eventie v1.0.6
443 * event binding helper
444 *   eventie.bind( elem, 'click', myFn )
445 *   eventie.unbind( elem, 'click', myFn )
446 * MIT license
447 */
448
449/*jshint browser: true, undef: true, unused: true */
450/*global define: false, module: false */
451
452( function( window ) {
453
454
455
456var docElem = document.documentElement;
457
458var bind = function() {};
459
460function getIEEvent( obj ) {
461	var event = window.event;
462	// add event.target
463	event.target = event.target || event.srcElement || obj;
464	return event;
465}
466
467if ( docElem.addEventListener ) {
468	bind = function( obj, type, fn ) {
469		obj.addEventListener( type, fn, false );
470	};
471} else if ( docElem.attachEvent ) {
472	bind = function( obj, type, fn ) {
473		obj[ type + fn ] = fn.handleEvent ?
474			function() {
475				var event = getIEEvent( obj );
476				fn.handleEvent.call( fn, event );
477			} :
478			function() {
479				var event = getIEEvent( obj );
480				fn.call( obj, event );
481			};
482		obj.attachEvent( "on" + type, obj[ type + fn ] );
483	};
484}
485
486var unbind = function() {};
487
488if ( docElem.removeEventListener ) {
489	unbind = function( obj, type, fn ) {
490		obj.removeEventListener( type, fn, false );
491	};
492} else if ( docElem.detachEvent ) {
493	unbind = function( obj, type, fn ) {
494		obj.detachEvent( "on" + type, obj[ type + fn ] );
495		try {
496			delete obj[ type + fn ];
497		} catch ( err ) {
498			// can't delete window object properties
499			obj[ type + fn ] = undefined;
500		}
501	};
502}
503
504var eventie = {
505	bind: bind,
506	unbind: unbind
507};
508
509// ----- module definition ----- //
510
511if ( typeof define === 'function' && define.amd ) {
512	// AMD
513	define( 'eventie/eventie',eventie );
514} else if ( typeof exports === 'object' ) {
515	// CommonJS
516	module.exports = eventie;
517} else {
518	// browser global
519	window.eventie = eventie;
520}
521
522})( window );
523
524/*!
525 * EventEmitter v4.2.11 - git.io/ee
526 * Unlicense - http://unlicense.org/
527 * Oliver Caldwell - http://oli.me.uk/
528 * @preserve
529 */
530
531;(function () {
532		'use strict';
533
534		/**
535		 * Class for managing events.
536		 * Can be extended to provide event functionality in other classes.
537		 *
538		 * @class EventEmitter Manages event registering and emitting.
539		 */
540		function EventEmitter() {}
541
542		// Shortcuts to improve speed and size
543		var proto = EventEmitter.prototype;
544		var exports = this;
545		var originalGlobalValue = exports.EventEmitter;
546
547		/**
548		 * Finds the index of the listener for the event in its storage array.
549		 *
550		 * @param {Function[]} listeners Array of listeners to search through.
551		 * @param {Function} listener Method to look for.
552		 * @return {Number} Index of the specified listener, -1 if not found
553		 * @api private
554		 */
555		function indexOfListener(listeners, listener) {
556				var i = listeners.length;
557				while (i--) {
558						if (listeners[i].listener === listener) {
559								return i;
560						}
561				}
562
563				return -1;
564		}
565
566		/**
567		 * Alias a method while keeping the context correct, to allow for over
vendor: 16,384 bytes, lines 567-1025
567writing of target method.
568		 *
569		 * @param {String} name The name of the target method.
570		 * @return {Function} The aliased method
571		 * @api private
572		 */
573		function alias(name) {
574				return function aliasClosure() {
575						return this[name].apply(this, arguments);
576				};
577		}
578
579		/**
580		 * Returns the listener array for the specified event.
581		 * Will initialise the event object and listener arrays if required.
582		 * 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.
583		 * Each property in the object response is an array of listener functions.
584		 *
585		 * @param {String|RegExp} evt Name of the event to return the listeners from.
586		 * @return {Function[]|Object} All listener functions for the event.
587		 */
588		proto.getListeners = function getListeners(evt) {
589				var events = this._getEvents();
590				var response;
591				var key;
592
593				// Return a concatenated array of all matching events if
594				// the selector is a regular expression.
595				if (evt instanceof RegExp) {
596						response = {};
597						for (key in events) {
598								if (events.hasOwnProperty(key) && evt.test(key)) {
599										response[key] = events[key];
600								}
601						}
602				}
603				else {
604						response = events[evt] || (events[evt] = []);
605				}
606
607				return response;
608		};
609
610		/**
611		 * Takes a list of listener objects and flattens it into a list of listener functions.
612		 *
613		 * @param {Object[]} listeners Raw listener objects.
614		 * @return {Function[]} Just the listener functions.
615		 */
616		proto.flattenListeners = function flattenListeners(listeners) {
617				var flatListeners = [];
618				var i;
619
620				for (i = 0; i < listeners.length; i += 1) {
621						flatListeners.push(listeners[i].listener);
622				}
623
624				return flatListeners;
625		};
626
627		/**
628		 * 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.
629		 *
630		 * @param {String|RegExp} evt Name of the event to return the listeners from.
631		 * @return {Object} All listener functions for an event in an object.
632		 */
633		proto.getListenersAsObject = function getListenersAsObject(evt) {
634				var listeners = this.getListeners(evt);
635				var response;
636
637				if (listeners instanceof Array) {
638						response = {};
639						response[evt] = listeners;
640				}
641
642				return response || listeners;
643		};
644
645		/**
646		 * Adds a listener function to the specified event.
647		 * The listener will not be added if it is a duplicate.
648		 * If the listener returns true then it will be removed after it is called.
649		 * If you pass a regular expression as the event name then the listener will be added to all events that match it.
650		 *
651		 * @param {String|RegExp} evt Name of the event to attach the listener to.
652		 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
653		 * @return {Object} Current instance of EventEmitter for chaining.
654		 */
655		proto.addListener = function addListener(evt, listener) {
656				var listeners = this.getListenersAsObject(evt);
657				var listenerIsWrapped = typeof listener === 'object';
658				var key;
659
660				for (key in listeners) {
661						if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
662								listeners[key].push(listenerIsWrapped ? listener : {
663										listener: listener,
664										once: false
665								});
666						}
667				}
668
669				return this;
670		};
671
672		/**
673		 * Alias of addListener
674		 */
675		proto.on = alias('addListener');
676
677		/**
678		 * Semi-alias of addListener. It will add a listener that will be
679		 * automatically removed after its first execution.
680		 *
681		 * @param {String|RegExp} evt Name of the event to attach the listener to.
682		 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
683		 * @return {Object} Current instance of EventEmitter for chaining.
684		 */
685		proto.addOnceListener = function addOnceListener(evt, listener) {
686				return this.addListener(evt, {
687						listener: listener,
688						once: true
689				});
690		};
691
692		/**
693		 * Alias of addOnceListener.
694		 */
695		proto.once = alias('addOnceListener');
696
697		/**
698		 * 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.
699		 * You need to tell it what event names should be matched by a regex.
700		 *
701		 * @param {String} evt Name of the event to create.
702		 * @return {Object} Current instance of EventEmitter for chaining.
703		 */
704		proto.defineEvent = function defineEvent(evt) {
705				this.getListeners(evt);
706				return this;
707		};
708
709		/**
710		 * Uses defineEvent to define multiple events.
711		 *
712		 * @param {String[]} evts An array of event names to define.
713		 * @return {Object} Current instance of EventEmitter for chaining.
714		 */
715		proto.defineEvents = function defineEvents(evts) {
716				for (var i = 0; i < evts.length; i += 1) {
717						this.defineEvent(evts[i]);
718				}
719				return this;
720		};
721
722		/**
723		 * Removes a listener function from the specified event.
724		 * When passed a regular expression as the event name, it will remove the listener from all events that match it.
725		 *
726		 * @param {String|RegExp} evt Name of the event to remove the listener from.
727		 * @param {Function} listener Method to remove from the event.
728		 * @return {Object} Current instance of EventEmitter for chaining.
729		 */
730		proto.removeListener = function removeListener(evt, listener) {
731				var listeners = this.getListenersAsObject(evt);
732				var index;
733				var key;
734
735				for (key in listeners) {
736						if (listeners.hasOwnProperty(key)) {
737								index = indexOfListener(listeners[key], listener);
738
739								if (index !== -1) {
740										listeners[key].splice(index, 1);
741								}
742						}
743				}
744
745				return this;
746		};
747
748		/**
749		 * Alias of removeListener
750		 */
751		proto.off = alias('removeListener');
752
753		/**
754		 * Adds listeners in bulk using the manipulateListeners method.
755		 * 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.
756		 * You can also pass it a regular expression to add the array of listeners to all events that match it.
757		 * Yeah, this function does quite a bit. That's probably a bad thing.
758		 *
759		 * @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.
760		 * @param {Function[]} [listeners] An optional array of listener functions to add.
761		 * @return {Object} Current instance of EventEmitter for chaining.
762		 */
763		proto.addListeners = function addListeners(evt, listeners) {
764				// Pass through to manipulateListeners
765				return this.manipulateListeners(false, evt, listeners);
766		};
767
768		/**
769		 * Removes listeners in bulk using the manipulateListeners method.
770		 * 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.
771		 * You can also pass it an event name and an array of listeners to be removed.
772		 * You can also pass it a regular expression to remove the listeners from all events that match it.
773		 *
774		 * @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.
775		 * @param {Function[]} [listeners] An optional array of listener functions to remove.
776		 * @return {Object} Current instance of EventEmitter for chaining.
777		 */
778		proto.removeListeners = function removeListeners(evt, listeners) {
779				// Pass through to manipulateListeners
780				return this.manipulateListeners(true, evt, listeners);
781		};
782
783		/**
784		 * 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.
785		 * The first argument will determine if the listeners are removed (true) or added (false).
786		 * 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.
787		 * You can also pass it an event name and an array of listeners to be added/removed.
788		 * You can also pass it a regular expression to manipulate the listeners of all events that match it.
789		 *
790		 * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
791		 * @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.
792		 * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
793		 * @return {Object} Current instance of EventEmitter for chaining.
794		 */
795		proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
796				var i;
797				var value;
798				var single = remove ? this.removeListener : this.addListener;
799				var multiple = remove ? this.removeListeners : this.addListeners;
800
801				// If evt is an object then pass each of its properties to this method
802				if (typeof evt === 'object' && !(evt instanceof RegExp)) {
803						for (i in evt) {
804								if (evt.hasOwnProperty(i) && (value = evt[i])) {
805										// Pass the single listener straight through to the singular method
806										if (typeof value === 'function') {
807												single.call(this, i, value);
808										}
809										else {
810												// Otherwise pass back to the multiple function
811												multiple.call(this, i, value);
812										}
813								}
814						}
815				}
816				else {
817						// So evt must be a string
818						// And listeners must be an array of listeners
819						// Loop over it and pass each one to the multiple method
820						i = listeners.length;
821						while (i--) {
822								single.call(this, evt, listeners[i]);
823						}
824				}
825
826				return this;
827		};
828
829		/**
830		 * Removes all listeners from a specified event.
831		 * If you do not specify an event then all listeners will be removed.
832		 * That means every event will be emptied.
833		 * You can also pass a regex to remove all events that match it.
834		 *
835		 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
836		 * @return {Object} Current instance of EventEmitter for chaining.
837		 */
838		proto.removeEvent = function removeEvent(evt) {
839				var type = typeof evt;
840				var events = this._getEvents();
841				var key;
842
843				// Remove different things depending on the state of evt
844				if (type === 'string') {
845						// Remove all listeners for the specified event
846						delete events[evt];
847				}
848				else if (evt instanceof RegExp) {
849						// Remove all events matching the regex.
850						for (key in events) {
851								if (events.hasOwnProperty(key) && evt.test(key)) {
852										delete events[key];
853								}
854						}
855				}
856				else {
857						// Remove all listeners in all events
858						delete this._events;
859				}
860
861				return this;
862		};
863
864		/**
865		 * Alias of removeEvent.
866		 *
867		 * Added to mirror the node API.
868		 */
869		proto.removeAllListeners = alias('removeEvent');
870
871		/**
872		 * Emits an event of your choice.
873		 * When emitted, every listener attached to that event will be executed.
874		 * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
875		 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
876		 * So they will not arrive within the array on the other side, they will be separate.
877		 * You can also pass a regular expression to emit to all events that match it.
878		 *
879		 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
880		 * @param {Array} [args] Optional array of arguments to be passed to each listener.
881		 * @return {Object} Current instance of EventEmitter for chaining.
882		 */
883		proto.emitEvent = function emitEvent(evt, args) {
884				var listeners = this.getListenersAsObject(evt);
885				var listener;
886				var i;
887				var key;
888				var response;
889
890				for (key in listeners) {
891						if (listeners.hasOwnProperty(key)) {
892								i = listeners[key].length;
893
894								while (i--) {
895										// If the listener returns true then it shall be removed from the event
896										// The function is executed either with a basic call or an apply if there is an args array
897										listener = listeners[key][i];
898
899										if (listener.once === true) {
900												this.removeListener(evt, listener.listener);
901										}
902
903										response = listener.listener.apply(this, args || []);
904
905										if (response === this._getOnceReturnValue()) {
906												this.removeListener(evt, listener.listener);
907										}
908								}
909						}
910				}
911
912				return this;
913		};
914
915		/**
916		 * Alias of emitEvent
917		 */
918		proto.trigger = alias('emitEvent');
919
920		/**
921		 * 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.
922		 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
923		 *
924		 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
925		 * @param {...*} Optional additional arguments to be passed to each listener.
926		 * @return {Object} Current instance of EventEmitter for chaining.
927		 */
928		proto.emit = function emit(evt) {
929				var args = Array.prototype.slice.call(arguments, 1);
930				return this.emitEvent(evt, args);
931		};
932
933		/**
934		 * Sets the current value to check against when executing listeners. If a
935		 * listeners return value matches the one set here then it will be removed
936		 * after execution. This value defaults to true.
937		 *
938		 * @param {*} value The new value to check for when executing listeners.
939		 * @return {Object} Current instance of EventEmitter for chaining.
940		 */
941		proto.setOnceReturnValue = function setOnceReturnValue(value) {
942				this._onceReturnValue = value;
943				return this;
944		};
945
946		/**
947		 * Fetches the current value to check against when executing listeners. If
948		 * the listeners return value matches this one then it should be removed
949		 * automatically. It will return true by default.
950		 *
951		 * @return {*|Boolean} The current value to check for or the default, true.
952		 * @api private
953		 */
954		proto._getOnceReturnValue = function _getOnceReturnValue() {
955				if (this.hasOwnProperty('_onceReturnValue')) {
956						return this._onceReturnValue;
957				}
958				else {
959						return true;
960				}
961		};
962
963		/**
964		 * Fetches the events object and creates one if required.
965		 *
966		 * @return {Object} The events storage object.
967		 * @api private
968		 */
969		proto._getEvents = function _getEvents() {
970				return this._events || (this._events = {});
971		};
972
973		/**
974		 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
975		 *
976		 * @return {Function} Non conflicting EventEmitter class.
977		 */
978		EventEmitter.noConflict = function noConflict() {
979				exports.EventEmitter = originalGlobalValue;
980				return EventEmitter;
981		};
982
983		// Expose the class either via AMD, CommonJS or the global object
984		if (typeof define === 'function' && define.amd) {
985				define('eventEmitter/EventEmitter',[],function () {
986						return EventEmitter;
987				});
988		}
989		else if (typeof module === 'object' && module.exports){
990				module.exports = EventEmitter;
991		}
992		else {
993				exports.EventEmitter = EventEmitter;
994		}
995}.call(this));
996
997/*!
998 * getStyleProperty v1.0.4
999 * original by kangax
1000 * http://perfectionkills.com/feature-testing-css-properties/
1001 * MIT license
1002 */
1003
1004/*jshint browser: true, strict: true, undef: true */
1005/*global define: false, exports: false, module: false */
1006
1007( function( window ) {
1008
1009
1010
1011var prefixes = 'Webkit Moz ms Ms O'.split(' ');
1012var docElemStyle = document.documentElement.style;
1013
1014function getStyleProperty( propName ) {
1015	if ( !propName ) {
1016		return;
1017	}
1018
1019	// test standard property first
1020	if ( typeof docElemStyle[ propName ] === 'string' ) {
1021		return propName;
1022	}
1023
1024	// capitalize
1025	propName = pr
1025opName.charAt(0).toUpperCase() + propName.slice(1);
1026
1027	// test vendor specific properties
1028	var prefixed;
1029	for ( var i=0, len = prefixes.length; i < len; i++ ) {
1030		prefixed = prefixes[i] + propName;
1031		if ( typeof docElemStyle[ prefixed ] === 'string' ) {
1032			return prefixed;
1033		}
1034	}
1035}
1036
1037// transport
1038if ( typeof define === 'function' && define.amd ) {
1039	// AMD
1040	define( 'get-style-property/get-style-property',[],function() {
1041		return getStyleProperty;
1042	});
1043} else if ( typeof exports === 'object' ) {
1044	// CommonJS for Component
1045	module.exports = getStyleProperty;
1046} else {
1047	// browser global
1048	window.getStyleProperty = getStyleProperty;
1049}
1050
1051})( window );
1052
1053/*!
1054 * getSize v1.2.2
1055 * measure size of elements
1056 * MIT license
1057 */
1058
1059/*jshint browser: true, strict: true, undef: true, unused: true */
1060/*global define: false, exports: false, require: false, module: false, console: false */
1061
1062( function( window, undefined ) {
1063
1064
1065
1066// -------------------------- helpers -------------------------- //
1067
1068// get a number from a string, not a percentage
1069function getStyleSize( value ) {
1070	var num = parseFloat( value );
1071	// not a percent like '100%', and a number
1072	var isValid = value.indexOf('%') === -1 && !isNaN( num );
1073	return isValid && num;
1074}
1075
1076function noop() {}
1077
1078var logError = typeof console === 'undefined' ? noop :
1079	function( message ) {
1080		console.error( message );
1081	};
1082
1083// -------------------------- measurements -------------------------- //
1084
1085var measurements = [
1086	'paddingLeft',
1087	'paddingRight',
1088	'paddingTop',
1089	'paddingBottom',
1090	'marginLeft',
1091	'marginRight',
1092	'marginTop',
1093	'marginBottom',
1094	'borderLeftWidth',
1095	'borderRightWidth',
1096	'borderTopWidth',
1097	'borderBottomWidth'
1098];
1099
1100function getZeroSize() {
1101	var size = {
1102		width: 0,
1103		height: 0,
1104		innerWidth: 0,
1105		innerHeight: 0,
1106		outerWidth: 0,
1107		outerHeight: 0
1108	};
1109	for ( var i=0, len = measurements.length; i < len; i++ ) {
1110		var measurement = measurements[i];
1111		size[ measurement ] = 0;
1112	}
1113	return size;
1114}
1115
1116
1117
1118function defineGetSize( getStyleProperty ) {
1119
1120// -------------------------- setup -------------------------- //
1121
1122var isSetup = false;
1123
1124var getStyle, boxSizingProp, isBoxSizeOuter;
1125
1126/**
1127 * setup vars and functions
1128 * do it on initial getSize(), rather than on script load
1129 * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
1130 */
1131function setup() {
1132	// setup once
1133	if ( isSetup ) {
1134		return;
1135	}
1136	isSetup = true;
1137
1138	var getComputedStyle = window.getComputedStyle;
1139	getStyle = ( function() {
1140		var getStyleFn = getComputedStyle ?
1141			function( elem ) {
1142				return getComputedStyle( elem, null );
1143			} :
1144			function( elem ) {
1145				return elem.currentStyle;
1146			};
1147
1148			return function getStyle( elem ) {
1149				var style = getStyleFn( elem );
1150				if ( !style ) {
1151					logError( 'Style returned ' + style +
1152						'. Are you running this code in a hidden iframe on Firefox? ' +
1153						'See http://bit.ly/getsizebug1' );
1154				}
1155				return style;
1156			};
1157	})();
1158
1159	// -------------------------- box sizing -------------------------- //
1160
1161	boxSizingProp = getStyleProperty('boxSizing');
1162
1163	/**
1164	 * WebKit measures the outer-width on style.width on border-box elems
1165	 * IE & Firefox measures the inner-width
1166	 */
1167	if ( boxSizingProp ) {
1168		var div = document.createElement('div');
1169		div.style.width = '200px';
1170		div.style.padding = '1px 2px 3px 4px';
1171		div.style.borderStyle = 'solid';
1172		div.style.borderWidth = '1px 2px 3px 4px';
1173		div.style[ boxSizingProp ] = 'border-box';
1174
1175		var body = document.body || document.documentElement;
1176		body.appendChild( div );
1177		var style = getStyle( div );
1178
1179		isBoxSizeOuter = getStyleSize( style.width ) === 200;
1180		body.removeChild( div );
1181	}
1182
1183}
1184
1185// -------------------------- getSize -------------------------- //
1186
1187function getSize( elem ) {
1188	setup();
1189
1190	// use querySeletor if elem is string
1191	if ( typeof elem === 'string' ) {
1192		elem = document.querySelector( elem );
1193	}
1194
1195	// do not proceed on non-objects
1196	if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
1197		return;
1198	}
1199
1200	var style = getStyle( elem );
1201
1202	// if hidden, everything is 0
1203	if ( style.display === 'none' ) {
1204		return getZeroSize();
1205	}
1206
1207	var size = {};
1208	size.width = elem.offsetWidth;
1209	size.height = elem.offsetHeight;
1210
1211	var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
1212		style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
1213
1214	// get all measurements
1215	for ( var i=0, len = measurements.length; i < len; i++ ) {
1216		var measurement = measurements[i];
1217		var value = style[ measurement ];
1218		value = mungeNonPixel( elem, value );
1219		var num = parseFloat( value );
1220		// any 'auto', 'medium' value will be 0
1221		size[ measurement ] = !isNaN( num ) ? num : 0;
1222	}
1223
1224	var paddingWidth = size.paddingLeft + size.paddingRight;
1225	var paddingHeight = size.paddingTop + size.paddingBottom;
1226	var marginWidth = size.marginLeft + size.marginRight;
1227	var marginHeight = size.marginTop + size.marginBottom;
1228	var borderWidth = size.borderLeftWidth + size.borderRightWidth;
1229	var borderHeight = size.borderTopWidth + size.borderBottomWidth;
1230
1231	var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
1232
1233	// overwrite width and height if we can get it from style
1234	var styleWidth = getStyleSize( style.width );
1235	if ( styleWidth !== false ) {
1236		size.width = styleWidth +
1237			// add padding and border unless it's already including it
1238			( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
1239	}
1240
1241	var styleHeight = getStyleSize( style.height );
1242	if ( styleHeight !== false ) {
1243		size.height = styleHeight +
1244			// add padding and border unless it's already including it
1245			( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
1246	}
1247
1248	size.innerWidth = size.width - ( paddingWidth + borderWidth );
1249	size.innerHeight = size.height - ( paddingHeight + borderHeight );
1250
1251	size.outerWidth = size.width + marginWidth;
1252	size.outerHeight = size.height + marginHeight;
1253
1254	return size;
1255}
1256
1257// IE8 returns percent values, not pixels
1258// taken from jQuery's curCSS
1259function mungeNonPixel( elem, value ) {
1260	// IE8 and has percent value
1261	if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
1262		return value;
1263	}
1264	var style = elem.style;
1265	// Remember the original values
1266	var left = style.left;
1267	var rs = elem.runtimeStyle;
1268	var rsLeft = rs && rs.left;
1269
1270	// Put in the new values to get a computed value out
1271	if ( rsLeft ) {
1272		rs.left = elem.currentStyle.left;
1273	}
1274	style.left = value;
1275	value = style.pixelLeft;
1276
1277	// Revert the changed values
1278	style.left = left;
1279	if ( rsLeft ) {
1280		rs.left = rsLeft;
1281	}
1282
1283	return value;
1284}
1285
1286return getSize;
1287
1288}
1289
1290// transport
1291if ( typeof define === 'function' && define.amd ) {
1292	// AMD for RequireJS
1293	define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
1294} else if ( typeof exports === 'object' ) {
1295	// CommonJS for Component
1296	module.exports = defineGetSize( require('desandro-get-style-property') );
1297} else {
1298	// browser global
1299	window.getSize = defineGetSize( window.getStyleProperty );
1300}
1301
1302})( window );
1303
1304/*!
1305 * docReady v1.0.4
1306 * Cross browser DOMContentLoaded event emitter
1307 * MIT license
1308 */
1309
1310/*jshint browser: true, strict: true, undef: true, unused: true*/
1311/*global define: false, require: false, module: false */
1312
1313( function( window ) {
1314
1315
1316
1317var document = window.document;
1318// collection of functions to be triggered on ready
1319var queue = [];
1320
1321function docReady( fn ) {
1322	// throw out non-functions
1323	if ( typeof fn !== 'function' ) {
1324		return;
1325	}
1326
1327	if ( docReady.isReady ) {
1328		// ready now, hit it
1329		fn();
1330	} else {
1331		// queue function when ready
1332		queue.push( fn );
1333	}
1334}
1335
1336docReady.isReady = false;
1337
1338// triggered on various doc ready events
1339function onReady( event ) {
1340	// bail if already triggered or IE8 document is not ready just yet
1341	var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
1342	if ( docReady.isReady || isIE8NotReady ) {
1343		return;
1344	}
1345
1346	trigger();
1347}
1348
1349function trigger() {
1350	docReady.isReady = true;
1351	// process queue
1352	for ( var i=0, len = queue.length; i < len; i++ ) {
1353		var fn = queue[i];
1354		fn();
1355	}
1356}
1357
1358function defineDocReady( eventie ) {
1359	// trigger ready if page is ready
1360	if ( document.readyState === 'complete' ) {
1361		trigger();
1362	} else {
1363		// listen for events
1364		eventie.bind( document, 'DOMContentLoaded', onReady );
1365		eventie.bind( document, 'readystatechange', onReady );
1366		eventie.bind( window, 'load', onReady );
1367	}
1368
1369	return docReady;
1370}
1371
1372// transport
1373if ( typeof define === 'function' && define.amd ) {
1374	// AMD
1375	define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
1376} else if ( typeof exports === 'object' ) {
1377	module.exports = defineDocReady( require('eventie') );
1378} else {
1379	// browser global
1380	window.docReady = defineDocReady( window.eventie );
1381}
1382
1383})( window );
1384
1385/**
1386 * matchesSelector v1.0.3
1387 * matchesSelector( element, '.selector' )
1388 * MIT license
1389 */
1390
1391/*jshint browser: true, strict: true, undef: true, unused: true */
1392/*global define: false, module: false */
1393
1394( function( ElemProto ) {
1395
1396	'use strict';
1397
1398	var matchesMethod = ( function() {
1399		// check for the standard method name first
1400		if ( ElemProto.matches ) {
1401			return 'matches';
1402		}
1403		// check un-prefixed
1404		if ( ElemProto.matchesSelector ) {
1405			return 'matchesSelector';
1406		}
1407		// check vendor prefixes
1408		var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1409
1410		for ( var i=0, len = prefixes.length; i < len; i++ ) {
1411			var prefix = prefixes[i];
1412			var method = prefix + 'MatchesSelector';
1413			if ( ElemProto[ method ] ) {
1414				return method;
1415			}
1416		}
1417	})();
1418
1419	// ----- match ----- //
1420
1421	function match( elem, selector ) {
1422		return elem[ matchesMethod ]( selector );
1423	}
1424
1425	// ----- appendToFragment ----- //
1426
1427	function checkParent( elem ) {
1428		// not needed if already has parent
1429		if ( elem.parentNode ) {
1430			return;
1431		}
1432		var fragment = document.createDocumentFragment();
1433		fragment.appendChild( elem );
1434	}
1435
1436	// ----- query ----- //
1437
1438	// fall back to using QSA
1439	// thx @jonathantneal https://gist.github.com/3062955
1440	function query( elem, selector ) {
1441		// append to fragment if no parent
1442		checkParent( elem );
1443
1444		// match elem with all selected elems of parent
1445		var elems = elem.parentNode.querySelectorAll( selector );
1446		for ( var i=0, len = elems.length; i < len; i++ ) {
1447			// return true if match
1448			if ( elems[i] === elem ) {
1449				return true;
1450			}
1451		}
1452		// otherwise return false
1453		return false;
1454	}
1455
1456	// ----- matchChild ----- //
1457
1458	function matchChild( elem, selector ) {
1459		checkParent( elem );
1460		return match( elem, selector );
1461	}
1462
1463	// ----- matchesSelector ----- //
1464
1465	var matchesSelector;
1466
1467	if ( matchesMethod ) {
1468		// IE9 supports matchesSelector, but doesn't work on orphaned elems
1469		// check for that
1470		var div = document.createElement('div');
1471		var supportsOrphans = match( div, 'div' );
1472		matchesSelector = supportsOrphans ? match : matchChild;
1473	} else {
1474		matchesSelector = query;
1475	}
1476
1477	// transport
1478	if ( typeof define === 'function' && define.amd ) {
1479		// AMD
1480		define( 'matches-selector/matches-selector',[],function() {
1481			return matchesSelector;
1482		});
1483	} else if ( typeof exports === 'object' ) {
1484		module.exports = matchesSelector;
1485	}
1486	else {
1487		// browser global
1488		window.matchesSelector = matchesSelector;
1489	}
1490
1491})( Element.prototype );
1492
1493/**
1494 * Fizzy UI utils v1.0.1
1495 * MIT license
1496 */
1497
1498/*jshint browser: true, undef: true, unused: true, strict: true */
1499
1500( function( window, factory ) {
1501	/*global define: false, module: false, require: false */
1502	'use strict';
1503	// universal module definition
1504
1505	if ( typeof define == 'function' && define.amd ) {
1506		// AMD
1507		define( 'fizzy-ui-utils/utils',[
1508			'doc-ready/doc-ready',
1509			'matches-selector/matches-selector'
1510		], function( docReady, matchesSelector ) {
1511			return factory( window, docReady, matchesSelector );
1512		});
1513	} else if ( typeof exports == 'object' ) {
1514		// CommonJS
1515		module.exports = factory(
1516			window,
1517			require('doc-ready'),
1518			require('desandro-matches-selector')
1519		);
1520	} else {
1521		// browser global
1522		window.fizzyUIUtils = factory(
1523			window,
1524			window.docReady,
1525			window.matchesSelector
1526		);
1527	}
1528
1529}( window, function factory( window, docReady, matchesSelector ) {
1530
1531
1532
1533var utils = {};
1534
1535// ----- extend ----- //
1536
1537// extends objects
1538utils.extend = function( a, b ) {
1539	for ( var prop in b ) {
1540		a[ prop ] = b[ prop ];
1541	}
1542	return a;
1543};
1544
1545// ----- modulo ----- //
1546
1547utils.modulo = function( num, div ) {
1548	return ( ( num % div ) + div ) % div;
1549};
1550
1551// ----- isArray ----- //
1552
1553var objToString = Object.prototype.toString;
1554utils.isArray = function( obj ) {
1555	return objToString.call( obj ) == '[object Array]';
1556};
1557
1558// ----- makeArray ----- //
1559
1560// turn element or nodeList into an array
1561utils.makeArray = function( obj ) {
1562	var ary = [];
1563	if ( utils.isArray( obj ) ) {
1564		// use object if already an array
1565		ary = obj;
1566	} else if ( obj && typeof obj.length == 'number' ) {
1567		// convert nodeList to array
1568		for ( var i=0, len = obj.length; i < len; i++ ) {
1569			ary.push( obj[i] );
1570		}
1571	} else {
1572		// array of single index
1573		ary.push( obj );
1574	}
1575	return ary;
1576};
1577
1578// ----- indexOf ----- //
1579
1580// index of helper cause IE8
1581utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
1582		return ary.indexOf( obj );
1583	} : function( ary, obj ) {
1584		for ( var i=0, len = ary.length; i < len; i++ ) {
1585			if ( ary[i] === obj ) {
1586				return i;
1587			}
1588		}
1589		return -1;
1590	};
1591
1592// ----- removeFrom ----- //
1593
1594utils.removeFrom = function( ary, obj ) {
1595	var index = utils.indexOf( ary, obj );
1596	if ( index != -1 ) {
1597		ary.splice( index, 1 );
1598	}
1599};
1600
1601// ----- isElement ----- //
1602
1603// http://stackoverflow.com/a/384380/182183
1604utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
1605	function isElementDOM2( obj ) {
1606		return obj instanceof HTMLElement;
1607	} :
1608	function isElementQuirky( obj ) {
1609		return obj && typeof obj == 'object' &&
1610			obj.nodeType == 1 && typeof obj.nodeName == 'string';
1611	};
1612
1613// ----- setText ----- //
1614
1615utils.setText = ( function() {
1616	var setTextProperty;
1617	function setText( elem, text ) {
1618		// only check setTextProperty once
1619		setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
1620		elem[ setTextProperty ] = text;
1621	}
1622	return setText;
1623})();
1624
1625// ----- getParent ----- //
1626
1627utils.getParent = function( elem, selector ) {
1628	while ( elem != document.body ) {
1629		elem = elem.parentNode;
1630		if ( matchesSelector( elem, selector ) ) {
1631			return elem;
1632		}
1633	}
1634};
1635
1636// ----- getQueryElement ----- //
1637
1638// use element as selector string
1639utils.getQueryElement = function( elem ) {
1640	if ( typeof elem == 'string' ) {
1641		return document.querySelector( elem );
1642	}
1643	return elem;
1644};
1645
1646// ----- handleEvent ----- //
1647
1648// enable .ontype to trigger from .addEventListener( elem, 'type' )
1649utils.handleEvent = function( event ) {
1650	var method = 'on' + event.type;
1651	if ( this[ method ] ) {
1652		this[ method ]( event );
1653	}
1654};
1655
1656// ----- filterFindElements ----- //
1657
1658utils.filterFindElements = function( elems, selector ) {
1659	// make array of elems
1660	elems = utils.makeArray( elems );
1661	var ffElems = [];
1662
1663	for ( var i=0, len = elems.length; i < len; i++ ) {
1664		var elem = elems[i];
1665		// check that elem is an actual element
1666		if ( !utils.isElement( elem ) ) {
1667			continue;
1668		}
1669		// filter & find items if we have a selector
1670		if ( selector ) {
1671			// filter siblings
1672			if ( matchesSelector( elem, selector ) ) {
1673				ffElems.push( elem );
1674			}
1675			// find children
1676			var childElems = elem.querySelectorAll( selector );
1677			// concat childElems to filterFound array
1678			for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
1679				ffElems.push( childElems[j] );
1680			}
1681		} else {
1682			ffElems.push( elem );
1683		}
1684	}
1685
1686	return ffElems;
1687};
1688
1689// ----- debounceMethod ----- //
1690
1691utils.debounceMethod = function( _class, methodName, threshold ) {
1692	// original method
1693	var method = _class.prototype[ methodName ];
1694	var timeoutName = methodName + 'Timeout';
1695
1696	_class.prototype[ methodName ] = function() {
1697		var timeout = this[ timeoutName ];
1698		if ( timeout ) {
1699			clearTimeout( timeout );
1700		}
1701		var args = arguments;
1702
1703		var _this = this;
1704		this[ timeoutName ] = setTimeout( function() {
1705			method.apply( _this, args );
1706			delete _this[ timeoutName ];
1707		}, threshold || 100 );
1708	};
1709};
1710
1711// ----- htmlInit ----- //
1712
1713// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1714utils.toDashed = function( str ) {
1715	return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1716		return $1 + '-' + $2;
1717	}).toLowerCase();
1718};
1719
1720var console = window.console;
1721/**
1722 * allow user to initialize classes via .js-namespace class
1723 * htmlInit( Widget, 'widgetName' )
1724 * options are parsed from data-namespace-option attribute
1725 */
1726utils.htmlInit = function( WidgetClass, namespace ) {
1727	docReady( function() {
1728		var dashedNamespace = utils.toDashed( namespace );
1729		var elems = document.querySelectorAll( '.js-' + dashedNamespace );
1730		var dataAttr = 'data-' + dashedNamespace + '-options';
1731
1732		for ( var i=0, len = elems.length; i < len; i++ ) {
1733			var elem = elems[i];
1734			var attr = elem.getAttribute( dataAttr );
1735			var options;
1736			try {
1737				options = attr && JSON.parse( attr );
1738			} catch ( error ) {
1739				// log error, do not initialize
1740				if ( console ) {
1741					console.error( 'Error parsing ' + dataAttr + ' on ' +
1742						elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
1743						error );
1744				}
1745				continue;
1746			}
1747			// initialize
1748			var instance = new WidgetClass( elem, options );
1749			// make available via $().data('layoutname')
1750			var jQuery = window.jQuery;
1751			if ( jQuery ) {
1752				jQuery.data( elem, namespace, instance );
1753			}
1754		}
1755	});
1756};
1757
1758// -----  ----- //
1759
1760return utils;
1761
1762}));
1763
1764/**
1765 * Outlayer Item
1766 */
1767
1768( function( window, factory ) {
1769	'use strict';
1770	// universal module definition
1771	if ( typeof define === 'function' && define.amd ) {
1772		// AMD
1773		define( 'outlayer/item',[
1774				'eventEmitter/EventEmitter',
1775				'get-size/get-size',
1776				'get-style-property/get-style-property',
1777				'fizzy-ui-utils/utils'
1778			],
1779			function( EventEmitter, getSize, getStyleProperty, utils ) {
1780				return factory( window, EventEmitter, getSize, getStyleProperty, utils );
1781			}
1782		);
1783	} else if (typeof exports === 'object') {
1784		// CommonJS
1785		module.exports = factory(
1786			window,
1787			require('wolfy87-eventemitter'),
1788			require('get-size'),
1789			require('desandro-get-style-property'),
1790			require('fizzy-ui-utils')
1791		);
1792	} else {
1793		// browser global
1794		window.Outlayer = {};
1795		window.Outlayer.Item = factory(
1796			window,
1797			window.EventEmitter,
1798			window.getSize,
1799			window.getStyleProperty,
1800			window.fizzyUIUtils
1801		);
1802	}
1803
1804}( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) {
1805'use strict';
1806
1807// ----- helpers ----- //
1808
1809var getComputedStyle = window.getComputedStyle;
1810var getStyle = getComputedStyle ?
1811	function( elem ) {
1812		return getComputedStyle( elem, null );
1813	} :
1814	function( elem ) {
1815		return elem.currentStyle;
1816	};
1817
1818
1819function isEmptyObj( obj ) {
1820	for ( var prop in obj ) {
1821		return false;
1822	}
1823	prop = null;
1824	return true;
1825}
1826
1827// -------------------------- CSS3 support -------------------------- //
1828
1829var transitionProperty = getStyleProperty('transition');
1830var transformProperty = getStyleProperty('transform');
1831var supportsCSS3 = transitionProperty && transformProperty;
1832var is3d = !!getStyleProperty('perspective');
1833
1834var transitionEndEvent = {
1835	WebkitTransition: 'webkitTransitionEnd',
1836	MozTransition: 'transitionend',
1837	OTransition: 'otransitionend',
1838	transition: 'transitionend'
1839}[ transitionProperty ];
1840
1841// properties that could have vendor prefix
1842var prefixableProperties = [
1843	'transform',
1844	'transition',
1845	'transitionDuration',
1846	'transitionProperty'
1847];
1848
1849// cache all vendor properties
1850var vendorProperties = ( function() {
1851	var cache = {};
1852	for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
1853		var prop = prefixableProperties[i];
1854		var supportedProp = getStyleProperty( prop );
1855		if ( supportedProp && supportedProp !== prop ) {
1856			cache[ prop ] = supportedProp;
1857		}
1858	}
1859	return cache;
1860})();
1861
1862// -------------------------- Item -------------------------- //
1863
1864function Item( element, layout ) {
1865	if ( !element ) {
1866		return;
1867	}
1868
1869	this.element = element;
1870	// parent layout class, i.e. Masonry, Isotope, or Packery
1871	this.layout = layout;
1872	this.position = {
1873		x: 0,
1874		y: 0
1875	};
1876
1877	this._create();
1878}
1879
1880// inherit EventEmitter
1881utils.extend( Item.prototype, EventEmitter.prototype );
1882
1883Item.prototype._create = function() {
1884	// transition objects
1885	this._transn = {
1886		ingProperties: {},
1887		clean: {},
1888		onEnd: {}
1889	};
1890
1891	this.css({
1892		position: 'absolute'
1893	});
1894};
1895
1896// trigger specified handler for event type
1897Item.prototype.handleEvent = function( event ) {
1898	var method = 'on' + event.type;
1899	if ( this[ method ] ) {
1900		this[ method ]( event );
1901	}
1902};
1903
1904Item.prototype.getSize = function() {
1905	this.size = getSize( this.element );
1906};
1907
1908/**
1909 * apply CSS styles to element
1910 * @param {Object} style
1911 */
1912Item.prototype.css = function( style ) {
1913	var elemStyle = this.element.style;
1914
1915	for ( var prop in style ) {
1916		// use vendor property if available
1917		var supportedProp = vendorProperties[ prop ] || prop;
1918		elemStyle[ supportedProp ] = style[ prop ];
1919	}
1920};
1921
1922 // measure position, and sets it
1923Item.prototype.getPosition = function() {
1924	var style = getStyle( this.element );
1925	var layoutOptions = this.layout.options;
1926	var isOriginLeft = layoutOptions.isOriginLeft;
1927	var isOriginTop = layoutOptions.isOriginTop;
1928	var xValue = style[ isOriginLeft ? 'left' : 'right' ];
1929	var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
1930	// convert percent to pixels
1931	var layoutSize = this.layout.size;
1932	var x = xValue.indexOf('%') != -1 ?
1933		( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 );
1934	var y = yValue.indexOf('%') != -1 ?
1935		( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 );
1936
1937	// clean up 'auto' or other non-integer values
1938	x = isNaN( x ) ? 0 : x;
1939	y = isNaN( y ) ? 0 : y;
1940	// remove padding from measurement
1941	x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1942	y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1943
1944	this.position.x = x;
1945	this.position.y = y;
1946};
1947
1948// set settled position, apply padding
1949Item.prototype.layoutPosition = function() {
1950	var layoutSize = this.layout.size;
1951	var layoutOptions = this.layout.options;
1952	var style = {};
1953
1954	// x
1955	var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight';
1956	var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right';
1957	var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left';
1958
1959	var x = this.position.x + layoutSize[ xPadding ];
1960	// set in percentage or pixels
1961	style[ xProperty ] = this.getXValue( x );
1962	// reset other property
1963	style[ xResetProperty ] = '';
1964
1965	// y
1966	var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom';
1967	var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom';
1968	var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top';
1969
1970	var y = this.position.y + layoutSize[ yPadding ];
1971	// set in percentage or pixels
1972	style[ yProperty ] = this.getYValue( y );
1973	// reset other property
1974	style[ yResetProperty ] = '';
1975
1976	this.css( style );
1977	this.emitEvent( 'layout', [ this ] );
1978};
1979
1980Item.prototype.getXValue = function( x ) {
1981	var layoutOptions = this.layout.options;
1982	return layoutOptions.percentPosition && !layoutOptions.isHorizontal ?
1983		( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
1984};
1985
1986Item.prototype.getYValue = function( y ) {
1987	var layoutOptions = this.layout.options;
1988	return layoutOptions.percentPosition && layoutOptions.isHorizontal ?
1989		( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
1990};
1991
1992
1993Item.prototype._transitionTo = function( x, y ) {
1994	this.getPosition();
1995	// get current x & y from top/left
1996	var curX = this.position.x;
1997	var curY = this.position.y;
1998
1999	var compareX = parseInt( x, 10 );
2000	var compareY = parseInt( y, 10 );
2001	var didNotMove = compareX === this.position.x && compareY === this.position.y;
2002
2003	// save end position
2004	this.setPosition( x, y );
2005
2006	// if did not move and not transitioning, just go to layout
2007	if ( didNotMove && !this.isTransitioning ) {
2008		this.layoutPosition();
2009		return;
2010	}
2011
2012	var transX = x - curX;
2013	var transY = y - curY;
2014	var transitionStyle = {};
2015	transitionStyle.transform = this.getTranslate( transX, transY );
2016
2017	this.transition({
2018		to: transitionStyle,
2019		onTransitionEnd: {
2020			transform: this.layoutPosition
2021		},
2022		isCleaning: true
2023	});
2024};
2025
2026Item.prototype.getTranslate = function( x, y ) {
2027	// flip cooridinates if origin on right or bottom
2028	var layoutOptions = this.layout.options;
2029	x = layoutOptions.isOriginLeft ? x : -x;
2030	y = layoutOptions.isOriginTop ? y : -y;
2031
2032	if ( is3d ) {
2033		return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
2034	}
2035
2036	return 'translate(' + x + 'px, ' + y + 'px)';
2037};
2038
2039// non transition + transform support
2040Item.prototype.goTo = function( x, y ) {
2041	this.setPosition( x, y );
2042	this.layoutPosition();
2043};
2044
2045// use transition and transforms if supported
2046Item.prototype.moveTo = supportsCSS3 ?
2047	Item.prototype._transitionTo : Item.prototype.goTo;
2048
2049Item.prototype.setPosition = function( x, y ) {
2050	this.position.x = parseInt( x, 10 );
2051	this.position.y = parseInt( y, 10 );
2052};
2053
2054// ----- transition ----- //
2055
2056/**
2057 * @param {Object} style - CSS
2058 * @param {Function} onTransitionEnd
2059 */
2060
2061// non transition, just trigger callback
2062Item.prototype._nonTransition = function( args ) {
2063	this.css( args.to );
2064	if ( args.isCleaning ) {
2065		this._removeStyles( args.to );
2066	}
2067	for ( var prop in args.onTransitionEnd ) {
2068		args.onTransitionEnd[ prop ].call( this );
2069	}
2070};
2071
2072/**
2073 * proper transition
2074 * @param {Object} args - arguments
2075 *   @param {Object} to - style to transition to
2076 *   @param {Object} from - style to start transition from
2077 *   @param {Boolean} isCleaning - removes transition styles after transition
2078 *   @param {Function} onTransitionEnd - callback
2079 */
2080Item.prototype._transition = function( args ) {
2081	// redirect to nonTransition if no transition duration
2082	if ( !parseFloat( this.layout.options.transitionDuration ) ) {
2083		this._nonTransition( args );
2084		return;
2085	}
2086
2087	var _transition = this._transn;
2088	// keep track of onTransitionEnd callback by css property
2089	for ( var prop in args.onTransitionEnd ) {
2090		_transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
2091	}
2092	// keep track of properties that are transitioning
2093	for ( prop in args.to ) {
2094		_transition.ingProperties[ prop ] = true;
2095		// keep track of properties to clean up when transition is done
2096		if ( args.isCleaning ) {
2097			_transition.clean[ prop ] = true;
2098		}
2099	}
2100
2101	// set from styles
2102	if ( args.from ) {
2103		this.css( args.from );
2104		// force redraw. http://blog.alexmaccaw.com/css-transitions
vendor: 11,318 bytes, lines 2105-2573
2105		var h = this.element.offsetHeight;
2106		// hack for JSHint to hush about unused var
2107		h = null;
2108	}
2109	// enable transition
2110	this.enableTransition( args.to );
2111	// set styles that are transitioning
2112	this.css( args.to );
2113
2114	this.isTransitioning = true;
2115
2116};
2117
2118// dash before all cap letters, including first for
2119// WebkitTransform => -webkit-transform
2120function toDashedAll( str ) {
2121	return str.replace( /([A-Z])/g, function( $1 ) {
2122		return '-' + $1.toLowerCase();
2123	});
2124}
2125
2126var transitionProps = 'opacity,' +
2127	toDashedAll( vendorProperties.transform || 'transform' );
2128
2129Item.prototype.enableTransition = function(/* style */) {
2130	// HACK changing transitionProperty during a transition
2131	// will cause transition to jump
2132	if ( this.isTransitioning ) {
2133		return;
2134	}
2135
2136	// make `transition: foo, bar, baz` from style object
2137	// HACK un-comment this when enableTransition can work
2138	// while a transition is happening
2139	// var transitionValues = [];
2140	// for ( var prop in style ) {
2141	//   // dash-ify camelCased properties like WebkitTransition
2142	//   prop = vendorProperties[ prop ] || prop;
2143	//   transitionValues.push( toDashedAll( prop ) );
2144	// }
2145	// enable transition styles
2146	this.css({
2147		transitionProperty: transitionProps,
2148		transitionDuration: this.layout.options.transitionDuration
2149	});
2150	// listen for transition end event
2151	this.element.addEventListener( transitionEndEvent, this, false );
2152};
2153
2154Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
2155
2156// ----- events ----- //
2157
2158Item.prototype.onwebkitTransitionEnd = function( event ) {
2159	this.ontransitionend( event );
2160};
2161
2162Item.prototype.onotransitionend = function( event ) {
2163	this.ontransitionend( event );
2164};
2165
2166// properties that I munge to make my life easier
2167var dashedVendorProperties = {
2168	'-webkit-transform': 'transform',
2169	'-moz-transform': 'transform',
2170	'-o-transform': 'transform'
2171};
2172
2173Item.prototype.ontransitionend = function( event ) {
2174	// disregard bubbled events from children
2175	if ( event.target !== this.element ) {
2176		return;
2177	}
2178	var _transition = this._transn;
2179	// get property name of transitioned property, convert to prefix-free
2180	var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
2181
2182	// remove property that has completed transitioning
2183	delete _transition.ingProperties[ propertyName ];
2184	// check if any properties are still transitioning
2185	if ( isEmptyObj( _transition.ingProperties ) ) {
2186		// all properties have completed transitioning
2187		this.disableTransition();
2188	}
2189	// clean style
2190	if ( propertyName in _transition.clean ) {
2191		// clean up style
2192		this.element.style[ event.propertyName ] = '';
2193		delete _transition.clean[ propertyName ];
2194	}
2195	// trigger onTransitionEnd callback
2196	if ( propertyName in _transition.onEnd ) {
2197		var onTransitionEnd = _transition.onEnd[ propertyName ];
2198		onTransitionEnd.call( this );
2199		delete _transition.onEnd[ propertyName ];
2200	}
2201
2202	this.emitEvent( 'transitionEnd', [ this ] );
2203};
2204
2205Item.prototype.disableTransition = function() {
2206	this.removeTransitionStyles();
2207	this.element.removeEventListener( transitionEndEvent, this, false );
2208	this.isTransitioning = false;
2209};
2210
2211/**
2212 * removes style property from element
2213 * @param {Object} style
2214**/
2215Item.prototype._removeStyles = function( style ) {
2216	// clean up transition styles
2217	var cleanStyle = {};
2218	for ( var prop in style ) {
2219		cleanStyle[ prop ] = '';
2220	}
2221	this.css( cleanStyle );
2222};
2223
2224var cleanTransitionStyle = {
2225	transitionProperty: '',
2226	transitionDuration: ''
2227};
2228
2229Item.prototype.removeTransitionStyles = function() {
2230	// remove transition
2231	this.css( cleanTransitionStyle );
2232};
2233
2234// ----- show/hide/remove ----- //
2235
2236// remove element from DOM
2237Item.prototype.removeElem = function() {
2238	this.element.parentNode.removeChild( this.element );
2239	// remove display: none
2240	this.css({ display: '' });
2241	this.emitEvent( 'remove', [ this ] );
2242};
2243
2244Item.prototype.remove = function() {
2245	// just remove element if no transition support or no transition
2246	if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
2247		this.removeElem();
2248		return;
2249	}
2250
2251	// start transition
2252	var _this = this;
2253	this.once( 'transitionEnd', function() {
2254		_this.removeElem();
2255	});
2256	this.hide();
2257};
2258
2259Item.prototype.reveal = function() {
2260	delete this.isHidden;
2261	// remove display: none
2262	this.css({ display: '' });
2263
2264	var options = this.layout.options;
2265
2266	var onTransitionEnd = {};
2267	var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
2268	onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
2269
2270	this.transition({
2271		from: options.hiddenStyle,
2272		to: options.visibleStyle,
2273		isCleaning: true,
2274		onTransitionEnd: onTransitionEnd
2275	});
2276};
2277
2278Item.prototype.onRevealTransitionEnd = function() {
2279	// check if still visible
2280	// during transition, item may have been hidden
2281	if ( !this.isHidden ) {
2282		this.emitEvent('reveal');
2283	}
2284};
2285
2286/**
2287 * get style property use for hide/reveal transition end
2288 * @param {String} styleProperty - hiddenStyle/visibleStyle
2289 * @returns {String}
2290 */
2291Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) {
2292	var optionStyle = this.layout.options[ styleProperty ];
2293	// use opacity
2294	if ( optionStyle.opacity ) {
2295		return 'opacity';
2296	}
2297	// get first property
2298	for ( var prop in optionStyle ) {
2299		return prop;
2300	}
2301};
2302
2303Item.prototype.hide = function() {
2304	// set flag
2305	this.isHidden = true;
2306	// remove display: none
2307	this.css({ display: '' });
2308
2309	var options = this.layout.options;
2310
2311	var onTransitionEnd = {};
2312	var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
2313	onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
2314
2315	this.transition({
2316		from: options.visibleStyle,
2317		to: options.hiddenStyle,
2318		// keep hidden stuff hidden
2319		isCleaning: true,
2320		onTransitionEnd: onTransitionEnd
2321	});
2322};
2323
2324Item.prototype.onHideTransitionEnd = function() {
2325	// check if still hidden
2326	// during transition, item may have been un-hidden
2327	if ( this.isHidden ) {
2328		this.css({ display: 'none' });
2329		this.emitEvent('hide');
2330	}
2331};
2332
2333Item.prototype.destroy = function() {
2334	this.css({
2335		position: '',
2336		left: '',
2337		right: '',
2338		top: '',
2339		bottom: '',
2340		transition: '',
2341		transform: ''
2342	});
2343};
2344
2345return Item;
2346
2347}));
2348
2349/*!
2350 * Outlayer v1.4.2
2351 * the brains and guts of a layout library
2352 * MIT license
2353 */
2354
2355( function( window, factory ) {
2356	'use strict';
2357	// universal module definition
2358
2359	if ( typeof define == 'function' && define.amd ) {
2360		// AMD
2361		define( 'outlayer/outlayer',[
2362				'eventie/eventie',
2363				'eventEmitter/EventEmitter',
2364				'get-size/get-size',
2365				'fizzy-ui-utils/utils',
2366				'./item'
2367			],
2368			function( eventie, EventEmitter, getSize, utils, Item ) {
2369				return factory( window, eventie, EventEmitter, getSize, utils, Item);
2370			}
2371		);
2372	} else if ( typeof exports == 'object' ) {
2373		// CommonJS
2374		module.exports = factory(
2375			window,
2376			require('eventie'),
2377			require('wolfy87-eventemitter'),
2378			require('get-size'),
2379			require('fizzy-ui-utils'),
2380			require('./item')
2381		);
2382	} else {
2383		// browser global
2384		window.Outlayer = factory(
2385			window,
2386			window.eventie,
2387			window.EventEmitter,
2388			window.getSize,
2389			window.fizzyUIUtils,
2390			window.Outlayer.Item
2391		);
2392	}
2393
2394}( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) {
2395'use strict';
2396
2397// ----- vars ----- //
2398
2399var console = window.console;
2400var jQuery = window.jQuery;
2401var noop = function() {};
2402
2403// -------------------------- Outlayer -------------------------- //
2404
2405// globally unique identifiers
2406var GUID = 0;
2407// internal store of all Outlayer intances
2408var instances = {};
2409
2410
2411/**
2412 * @param {Element, String} element
2413 * @param {Object} options
2414 * @constructor
2415 */
2416function Outlayer( element, options ) {
2417	var queryElement = utils.getQueryElement( element );
2418	if ( !queryElement ) {
2419		if ( console ) {
2420			console.error( 'Bad element for ' + this.constructor.namespace +
2421				': ' + ( queryElement || element ) );
2422		}
2423		return;
2424	}
2425	this.element = queryElement;
2426	// add jQuery
2427	if ( jQuery ) {
2428		this.$element = jQuery( this.element );
2429	}
2430
2431	// options
2432	this.options = utils.extend( {}, this.constructor.defaults );
2433	this.option( options );
2434
2435	// add id for Outlayer.getFromElement
2436	var id = ++GUID;
2437	this.element.outlayerGUID = id; // expando
2438	instances[ id ] = this; // associate via id
2439
2440	// kick it off
2441	this._create();
2442
2443	if ( this.options.isInitLayout ) {
2444		this.layout();
2445	}
2446}
2447
2448// settings are for internal use only
2449Outlayer.namespace = 'outlayer';
2450Outlayer.Item = Item;
2451
2452// default options
2453Outlayer.defaults = {
2454	containerStyle: {
2455		position: 'relative'
2456	},
2457	isInitLayout: true,
2458	isOriginLeft: true,
2459	isOriginTop: true,
2460	isResizeBound: true,
2461	isResizingContainer: true,
2462	// item options
2463	transitionDuration: '0.4s',
2464	hiddenStyle: {
2465		opacity: 0,
2466		transform: 'scale(0.001)'
2467	},
2468	visibleStyle: {
2469		opacity: 1,
2470		transform: 'scale(1)'
2471	}
2472};
2473
2474// inherit EventEmitter
2475utils.extend( Outlayer.prototype, EventEmitter.prototype );
2476
2477/**
2478 * set options
2479 * @param {Object} opts
2480 */
2481Outlayer.prototype.option = function( opts ) {
2482	utils.extend( this.options, opts );
2483};
2484
2485Outlayer.prototype._create = function() {
2486	// get items from children
2487	this.reloadItems();
2488	// elements that affect layout, but are not laid out
2489	this.stamps = [];
2490	this.stamp( this.options.stamp );
2491	// set container style
2492	utils.extend( this.element.style, this.options.containerStyle );
2493
2494	// bind resize method
2495	if ( this.options.isResizeBound ) {
2496		this.bindResize();
2497	}
2498};
2499
2500// goes through all children again and gets bricks in proper order
2501Outlayer.prototype.reloadItems = function() {
2502	// collection of item elements
2503	this.items = this._itemize( this.element.children );
2504};
2505
2506
2507/**
2508 * turn elements into Outlayer.Items to be used in layout
2509 * @param {Array or NodeList or HTMLElement} elems
2510 * @returns {Array} items - collection of new Outlayer Items
2511 */
2512Outlayer.prototype._itemize = function( elems ) {
2513
2514	var itemElems = this._filterFindItemElements( elems );
2515	var Item = this.constructor.Item;
2516
2517	// create new Outlayer Items for collection
2518	var items = [];
2519	for ( var i=0, len = itemElems.length; i < len; i++ ) {
2520		var elem = itemElems[i];
2521		var item = new Item( elem, this );
2522		items.push( item );
2523	}
2524
2525	return items;
2526};
2527
2528/**
2529 * get item elements to be used in layout
2530 * @param {Array or NodeList or HTMLElement} elems
2531 * @returns {Array} items - item elements
2532 */
2533Outlayer.prototype._filterFindItemElements = function( elems ) {
2534	return utils.filterFindElements( elems, this.options.itemSelector );
2535};
2536
2537/**
2538 * getter method for getting item elements
2539 * @returns {Array} elems - collection of item elements
2540 */
2541Outlayer.prototype.getItemElements = function() {
2542	var elems = [];
2543	for ( var i=0, len = this.items.length; i < len; i++ ) {
2544		elems.push( this.items[i].element );
2545	}
2546	return elems;
2547};
2548
2549// ----- init & layout ----- //
2550
2551/**
2552 * lays out all items
2553 */
2554Outlayer.prototype.layout = function() {
2555	this._resetLayout();
2556	this._manageStamps();
2557
2558	// don't animate first layout
2559	var isInstant = this.options.isLayoutInstant !== undefined ?
2560		this.options.isLayoutInstant : !this._isLayoutInited;
2561	this.layoutItems( this.items, isInstant );
2562
2563	// flag for initalized
2564	this._isLayoutInited = true;
2565};
2566
2567// _init is alias for layout
2568Outlayer.prototype._init = Outlayer.prototype.layout;
2569
2570/**
2571 * logic before any new layout
2572 */
2573Outlayer.prototype._resetLayout = function() {
2574	this.getSize();
2575};
2576
2577
2578Outlayer.prototype.getSize = function() {
2579	this.size = getSize( this.element );
2580};
2581
2582/**
2583 * get measurement from option, for columnWidth, rowHeight, gutter
2584 * if option is String -> get element from selector string, & get size of element
2585 * if option is Element -> get size of element
2586 * else use option as a number
2587 *
2588 * @param {String} measurement
2589 * @param {String} size - width or height
2590 * @private
2591 */
2592Outlayer.prototype._getMeasurement = function( measurement, size ) {
2593	var option = this.options[ measurement ];
2594	var elem;
2595	if ( !option ) {
2596		// default to 0
2597		this[ measurement ] = 0;
2598	} else {
2599		// use option as an element
2600		if ( typeof option === 'string' ) {
2601			elem = this.element.querySelector( option );
2602		} else if ( utils.isElement( option ) ) {
2603			elem = option;
2604		}
2605		// use size of element, if element
2606		this[ measurement ] = elem ? getSize( elem )[ size ] : option;
2607	}
2608};
2609
2610/**
2611 * layout a collection of item elements
2612 * @api public
2613 */
2614Outlayer.prototype.layoutItems = function( items, isInstant ) {
2615	items = this._getItemsForLayout( items );
2616
2617	this._layoutItems( items, isInstant );
2618
2619	this._postLayout();
2620};
2621
2622/**
2623 * get the items to be laid out
2624 * you may want to skip over some items
2625 * @param {Array} items
2626 * @returns {Array} items
2627 */
2628Outlayer.prototype._getItemsForLayout = function( items ) {
2629	var layoutItems = [];
2630	for ( var i=0, len = items.length; i < len; i++ ) {
2631		var item = items[i];
2632		if ( !item.isIgnored ) {
2633			layoutItems.push( item );
2634		}
2635	}
2636	return layoutItems;
2637};
2638
2639/**
2640 * layout items
2641 * @param {Array} items
2642 * @param {Boolean} isInstant
2643 */
2644Outlayer.prototype._layoutItems = function( items, isInstant ) {
2645	this._emitCompleteOnItems( 'layout', items );
2646
2647	if ( !items || !items.length ) {
2648		// no items, emit event with empty array
2649		return;
2650	}
2651
2652	var queue = [];
2653
2654	for ( var i=0, len = items.length; i < len; i++ ) {
2655		var item = items[i];
2656		// get x/y object from method
2657		var position = this._getItemLayoutPosition( item );
2658		// enqueue
2659		position.item = item;
2660		position.isInstant = isInstant || item.isLayoutInstant;
2661		queue.push( position );
2662	}
2663
2664	this._processLayoutQueue( queue );
2665};
2666
2667/**
2668 * get item layout position
2669 * @param {Outlayer.Item} item
2670 * @returns {Object} x and y position
2671 */
2672Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
2673	return {
2674		x: 0,
2675		y: 0
2676	};
2677};
2678
2679/**
2680 * iterate over array and position each item
2681 * Reason being - separating this logic prevents 'layout invalidation'
2682 * thx @paul_irish
2683 * @param {Array} queue
2684 */
2685Outlayer.prototype._processLayoutQueue = function( queue ) {
2686	for ( var i=0, len = queue.length; i < len; i++ ) {
2687		var obj = queue[i];
2688		this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
2689	}
2690};
2691
2692/**
2693 * Sets position of item in DOM
2694 * @param {Outlayer.Item} item
2695 * @param {Number} x - horizontal position
2696 * @param {Number} y - vertical position
2697 * @param {Boolean} isInstant - disables transitions
2698 */
2699Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
2700	if ( isInstant ) {
2701		// if not transition, just set CSS
2702		item.goTo( x, y );
2703	} else {
2704		item.moveTo( x, y );
2705	}
2706};
2707
2708/**
2709 * Any logic you want to do after each layout,
2710 * i.e. size the container
2711 */
2712Outlayer.prototype._postLayout = function() {
2713	this.resizeContainer();
2714};
2715
2716Outlayer.prototype.resizeContainer = function() {
2717	if ( !this.options.isResizingContainer ) {
2718		return;
2719	}
2720	var size = this._getContainerSize();
2721	if ( size ) {
2722		this._setContainerMeasure( size.width, true );
2723		this._setContainerMeasure( size.height, false );
2724	}
2725};
2726
2727/**
2728 * Sets width or height of container if returned
2729 * @returns {Object} size
2730 *   @param {Number} width
2731 *   @param {Number} height
2732 */
2733Outlayer.prototype._getContainerSize = noop;
2734
2735/**
2736 * @param {Number} measure - size of width or height
2737 * @param {Boolean} isWidth
2738 */
2739Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
2740	if ( measure === undefined ) {
2741		return;
2742	}
2743
2744	var elemSize = this.size;
2745	// add padding and border width if border box
2746	if ( elemSize.isBorderBox ) {
2747		measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2748			elemSize.borderLeftWidth + elemSize.borderRightWidth :
2749			elemSize.paddingBottom + elemSize.paddingTop +
2750			elemSize.borderTopWidth + elemSize.borderBottomWidth;
2751	}
2752
2753	measure = Math.max( measure, 0 );
2754	this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2755};
2756
2757/**
2758 * emit eventComplete on a collection of items events
2759 * @param {String} eventName
2760 * @param {Array} items - Outlayer.Items
2761 */
2762Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) {
2763	var _this = this;
2764	function onComplete() {
2765		_this.dispatchEvent( eventName + 'Complete', null, [ items ] );
2766	}
2767
2768	var count = items.length;
2769	if ( !items || !count ) {
2770		onComplete();
2771		return;
2772	}
2773
2774	var doneCount = 0;
2775	function tick() {
2776		doneCount++;
2777		if ( doneCount === count ) {
2778			onComplete();
2779		}
2780	}
2781
2782	// bind callback
2783	for ( var i=0, len = items.length; i < len; i++ ) {
2784		var item = items[i];
2785		item.once( eventName, tick );
2786	}
2787};
2788
2789/**
2790 * emits events via eventEmitter and jQuery events
2791 * @param {String} type - name of event
2792 * @param {Event} event - original event
2793 * @param {Array} args - extra arguments
2794 */
2795Outlayer.prototype.dispatchEvent = function( type, event, args ) {
2796	// add original event to arguments
2797	var emitArgs = event ? [ event ].concat( args ) : args;
2798	this.emitEvent( type, emitArgs );
2799
2800	if ( jQuery ) {
2801		// set this.$element
2802		this.$element = this.$element || jQuery( this.element );
2803		if ( event ) {
2804			// create jQuery event
2805			var $event = jQuery.Event( event );
2806			$event.type = type;
2807			this.$element.trigger( $event, args );
2808		} else {
2809			// just trigger with type if no event available
2810			this.$element.trigger( type, args );
2811		}
2812	}
2813};
2814
2815// -------------------------- ignore & stamps -------------------------- //
2816
2817
2818/**
2819 * keep item in collection, but do not lay it out
2820 * ignored items do not get skipped in layout
2821 * @param {Element} elem
2822 */
2823Outlayer.prototype.ignore = function( elem ) {
2824	var item = this.getItem( elem );
2825	if ( item ) {
2826		item.isIgnored = true;
2827	}
2828};
2829
2830/**
2831 * return item to layout collection
2832 * @param {Element} elem
2833 */
2834Outlayer.prototype.unignore = function( elem ) {
2835	var item = this.getItem( elem );
2836	if ( item ) {
2837		delete item.isIgnored;
2838	}
2839};
2840
2841/**
2842 * adds elements to stamps
2843 * @param {NodeList, Array, Element, or String} elems
2844 */
2845Outlayer.prototype.stamp = function( elems ) {
2846	elems = this._find( elems );
2847	if ( !elems ) {
2848		return;
2849	}
2850
2851	this.stamps = this.stamps.concat( elems );
2852	// ignore
2853	for ( var i=0, len = elems.length; i < len; i++ ) {
2854		var elem = elems[i];
2855		this.ignore( elem );
2856	}
2857};
2858
2859/**
2860 * removes elements to stamps
2861 * @param {NodeList, Array, or Element} elems
2862 */
2863Outlayer.prototype.unstamp = function( elems ) {
2864	elems = this._find( elems );
2865	if ( !elems ){
2866		return;
2867	}
2868
2869	for ( var i=0, len = elems.length; i < len; i++ ) {
2870		var elem = elems[i];
2871		// filter out removed stamp elements
2872		utils.removeFrom( this.stamps, elem );
2873		this.unignore( elem );
2874	}
2875
2876};
2877
2878/**
2879 * finds child elements
2880 * @param {NodeList, Array, Element, or String} elems
2881 * @returns {Array} elems
2882 */
2883Outlayer.prototype._find = function( elems ) {
2884	if ( !elems ) {
2885		return;
2886	}
2887	// if string, use argument as selector string
2888	if ( typeof elems === 'string' ) {
2889		elems = this.element.querySelectorAll( elems );
2890	}
2891	elems = utils.makeArray( elems );
2892	return elems;
2893};
2894
2895Outlayer.prototype._manageStamps = function() {
2896	if ( !this.stamps || !this.stamps.length ) {
2897		return;
2898	}
2899
2900	this._getBoundingRect();
2901
2902	for ( var i=0, len = this.stamps.length; i < len; i++ ) {
2903		var stamp = this.stamps[i];
2904		this._manageStamp( stamp );
2905	}
2906};
2907
2908// update boundingLeft / Top
2909Outlayer.prototype._getBoundingRect = function() {
2910	// get bounding rect for container element
2911	var boundingRect = this.element.getBoundingClientRect();
2912	var size = this.size;
2913	this._boundingRect = {
2914		left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2915		top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2916		right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2917		bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2918	};
2919};
2920
2921/**
2922 * @param {Element} stamp
2923**/
2924Outlayer.prototype._manageStamp = noop;
2925
2926/**
2927 * get x/y position of element relative to container element
2928 * @param {Element} elem
2929 * @returns {Object} offset - has left, top, right, bottom
2930 */
2931Outlayer.prototype._getElementOffset = function( elem ) {
2932	var boundingRect = elem.getBoundingClientRect();
2933	var thisRect = this._boundingRect;
2934	var size = getSize( elem );
2935	var offset = {
2936		left: boundingRect.left - thisRect.left - size.marginLeft,
2937		top: boundingRect.top - thisRect.top - size.marginTop,
2938		right: thisRect.right - boundingRect.right - size.marginRight,
2939		bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2940	};
2941	return offset;
2942};
2943
2944// -------------------------- resize -------------------------- //
2945
2946// enable event handlers for listeners
2947// i.e. resize -> onresize
2948Outlayer.prototype.handleEvent = function( event ) {
2949	var method = 'on' + event.type;
2950	if ( this[ method ] ) {
2951		this[ method ]( event );
2952	}
2953};
2954
2955/**
2956 * Bind layout to window resizing
2957 */
2958Outlayer.prototype.bindResize = function() {
2959	// bind just one listener
2960	if ( this.isResizeBound ) {
2961		return;
2962	}
2963	eventie.bind( window, 'resize', this );
2964	this.isResizeBound = true;
2965};
2966
2967/**
2968 * Unbind layout to window resizing
2969 */
2970Outlayer.prototype.unbindResize = function() {
2971	if ( this.isResizeBound ) {
2972		eventie.unbind( window, 'resize', this );
2973	}
2974	this.isResizeBound = false;
2975};
2976
2977// original debounce by John Hann
2978// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
2979
2980// this fires every resize
2981Outlayer.prototype.onresize = function() {
2982	if ( this.resizeTimeout ) {
2983		clearTimeout( this.resizeTimeout );
2984	}
2985
2986	var _this = this;
2987	function delayed() {
2988		_this.resize();
2989		delete _this.resizeTimeout;
2990	}
2991
2992	this.resizeTimeout = setTimeout( delayed, 100 );
2993};
2994
2995// debounced, layout on resize
2996Outlayer.prototype.resize = function() {
2997	// don't trigger if size did not change
2998	// or if resize was unbound. See #9
2999	if ( !this.isResizeBound || !this.needsResizeLayout() ) {
3000		return;
3001	}
3002
3003	this.layout();
3004};
3005
3006/**
3007 * check if layout is needed post layout
3008 * @returns Boolean
3009 */
3010Outlayer.prototype.needsResizeLayout = function() {
3011	var size = getSize( this.element );
3012	// check that this.size and size are there
3013	// IE8 triggers resize on body size change, so they might not be
3014	var hasSizes = this.size && size;
3015	return hasSizes && size.innerWidth !== this.size.innerWidth;
3016};
3017
3018// -------------------------- methods -------------------------- //
3019
3020/**
3021 * add items to Outlayer instance
3022 * @param {Array or NodeList or Element} elems
3023 * @returns {Array} items - Outlayer.Items
3024**/
3025Outlayer.prototype.addItems = function( elems ) {
3026	var items = this._itemize( elems );
3027	// add items to collection
3028	if ( items.length ) {
3029		this.items = this.items.concat( items );
3030	}
3031	return items;
3032};
3033
3034/**
3035 * Layout newly-appended item elements
3036 * @param {Array or NodeList or Element} elems
3037 */
3038Outlayer.prototype.appended = function( elems ) {
3039	var items = this.addItems( elems );
3040	if ( !items.length ) {
3041		return;
3042	}
3043	// layout and reveal just the new items
3044	this.layoutItems( items, true );
3045	this.reveal( items );
3046};
3047
3048/**
3049 * Layout prepended elements
3050 * @param {Array or NodeList or Element} elems
3051 */
3052Outlayer.prototype.prepended = function( elems ) {
3053	var items = this._itemize( elems );
3054	if ( !items.length ) {
3055		return;
3056	}
3057	// add items to beginning of collection
3058	var previousItems = this.items.slice(0);
3059	this.items = items.concat( previousItems );
3060	// start new layout
3061	this._resetLayout();
3062	this._manageStamps();
3063	// layout new stuff without transition
3064	this.layoutItems( items, true );
3065	this.reveal( items );
3066	// layout previous items
3067	this.layoutItems( previousItems );
3068};
3069
3070/**
3071 * reveal a collection of items
3072 * @param {Array of Outlayer.Items} items
3073 */
3074Outlayer.prototype.reveal = function( items ) {
3075	this._emitCompleteOnItems( 'reveal', items );
3076
3077	var len = items && items.length;
3078	for ( var i=0; len && i < len; i++ ) {
3079		var item = items[i];
3080		item.reveal();
3081	}
3082};
3083
3084/**
3085 * hide a collection of items
3086 * @param {Array of Outlayer.Items} items
3087 */
3088Outlayer.prototype.hide = function( items ) {
3089	this._emitCompleteOnItems( 'hide', items );
3090
3091	var len = items && items.length;
3092	for ( var i=0; len && i < len; i++ ) {
3093		var item = items[i];
3094		item.hide();
3095	}
3096};
3097
3098/**
3099 * reveal item elements
3100 * @param {Array}, {Element}, {NodeList} items
3101 */
3102Outlayer.prototype.revealItemElements = function( elems ) {
3103	var items = this.getItems( elems );
3104	this.reveal( items );
3105};
3106
3107/**
3108 * hide item elements
3109 * @param {Array}, {Element}, {NodeList} items
3110 */
3111Outlayer.prototype.hideItemElements = function( elems ) {
3112	var items = this.getItems( elems );
3113	this.hide( items );
3114};
3115
3116/**
3117 * get Outlayer.Item, given an Element
3118 * @param {Element} elem
3119 * @param {Function} callback
3120 * @returns {Outlayer.Item} item
3121 */
3122Outlayer.prototype.getItem = function( elem ) {
3123	// loop through items to get the one that matches
3124	for ( var i=0, len = this.items.length; i < len; i++ ) {
3125		var item = this.items[i];
3126		if ( item.element === elem ) {
3127			// return item
3128			return item;
3129		}
3130	}
3131};
3132
3133/**
3134 * get collection of Outlayer.Items, given Elements
3135 * @param {Array} elems
3136 * @returns {Array} items - Outlayer.Items
3137 */
3138Outlayer.prototype.getItems = function( elems ) {
3139	elems = utils.makeArray( elems );
3140	var items = [];
3141	for ( var i=0, len = elems.length; i < len; i++ ) {
3142		var elem = elems[i];
3143		var item = this.getItem( elem );
3144		if ( item ) {
3145			items.push( item );
3146		}
3147	}
3148
3149	return items;
3150};
3151
3152/**
3153 * remove element(s) from instance and DOM
3154 * @param {Array or NodeList or Element} elems
3155 */
3156Outlayer.prototype.remove = function( elems ) {
3157	var removeItems = this.getItems( elems );
3158
3159	this._emitCompleteOnItems( 'remove', removeItems );
3160
3161	// bail if no items to remove
3162	if ( !removeItems || !removeItems.length ) {
3163		return;
3164	}
3165
3166	for ( var i=0, len = removeItems.length; i < len; i++ ) {
3167		var item = removeItems[i];
3168		item.remove();
3169		// remove item from collection
3170		utils.removeFrom( this.items, item );
3171	}
3172};
3173
3174// ----- destroy ----- //
3175
3176// remove and disable Outlayer instance
3177Outlayer.prototype.destroy = function() {
3178	// clean up dynamic styles
3179	var style = this.element.style;
3180	style.height = '';
3181	style.position = '';
3182	style.width = '';
3183	// destroy items
3184	for ( var i=0, len = this.items.length; i < len; i++ ) {
3185		var item = this.items[i];
3186		item.destroy();
3187	}
3188
3189	this.unbindResize();
3190
3191	var id = this.element.outlayerGUID;
3192	delete instances[ id ]; // remove reference to instance by id
3193	delete this.element.outlayerGUID;
3194	// remove data for jQuery
3195	if ( jQuery ) {
3196		jQuery.removeData( this.element, this.constructor.namespace );
3197	}
3198
3199};
3200
3201// -------------------------- data -------------------------- //
3202
3203/**
3204 * get Outlayer instance from element
3205 * @param {Element} elem
3206 * @returns {Outlayer}
3207 */
3208Outlayer.data = function( elem ) {
3209	elem = utils.getQueryElement( elem );
3210	var id = elem && elem.outlayerGUID;
3211	return id && instances[ id ];
3212};
3213
3214
3215// -------------------------- create Outlayer class -------------------------- //
3216
3217/**
3218 * create a layout class
3219 * @param {String} namespace
3220 */
3221Outlayer.create = function( namespace, options ) {
3222	// sub-class Outlayer
3223	function Layout() {
3224		Outlayer.apply( this, arguments );
3225	}
3226	// inherit Outlayer prototype, use Object.create if there
3227	if ( Object.create ) {
3228		Layout.prototype = Object.create( Outlayer.prototype );
3229	} else {
3230		utils.extend( Layout.prototype, Outlayer.prototype );
3231	}
3232	// set contructor, used for namespace and Item
3233	Layout.prototype.constructor = Layout;
3234
3235	Layout.defaults = utils.extend( {}, Outlayer.defaults );
3236	// apply new options
3237	utils.extend( Layout.defaults, options );
3238	// keep prototype.settings for backwards compatibility (Packery v1.2.0)
3239	Layout.prototype.settings = {};
3240
3241	Layout.namespace = namespace;
3242
3243	Layout.data = Outlayer.data;
3244
3245	// sub-class Item
3246	Layout.Item = function LayoutItem() {
3247		Item.apply( this, arguments );
3248	};
3249
3250	Layout.Item.prototype = new Item();
3251
3252	// -------------------------- declarative -------------------------- //
3253
3254	utils.htmlInit( Layout, namespace );
3255
3256	// -------------------------- jQuery bridge -------------------------- //
3257
3258	// make into jQuery plugin
3259	if ( jQuery && jQuery.bridget ) {
3260		jQuery.bridget( namespace, Layout );
3261	}
3262
3263	return Layout;
3264};
3265
3266// ----- fin ----- //
3267
3268// back in global
3269Outlayer.Item = Item;
3270
3271return Outlayer;
3272
3273}));
3274
3275
3276/**
3277 * Isotope Item
3278**/
3279
3280( function( window, factory ) {
3281'use strict';
3282	// universal module definition
3283	if ( typeof define == 'function' && define.amd ) {
3284		// AMD
3285		define( 'isotope/js/item',[
3286				'outlayer/outlayer'
3287			],
3288			factory );
3289	} else if ( typeof exports == 'object' ) {
3290		// CommonJS
3291		module.exports = factory(
3292			require('outlayer')
3293		);
3294	} else {
3295		// browser global
3296		window.Isotope = window.Isotope || {};
3297		window.Isotope.Item = factory(
3298			window.Outlayer
3299		);
3300	}
3301
3302}( window, function factory( Outlayer ) {
3303'use strict';
3304
3305// -------------------------- Item -------------------------- //
3306
3307// sub-class Outlayer Item
3308function Item() {
3309	Outlayer.Item.apply( this, arguments );
3310}
3311
3312Item.prototype = new Outlayer.Item();
3313
3314Item.prototype._create = function() {
3315	// assign id, used for original-order sorting
3316	this.id = this.layout.itemGUID++;
3317	Outlayer.Item.prototype._create.call( this );
3318	this.sortData = {};
3319};
3320
3321Item.prototype.updateSortData = function() {
3322	if ( this.isIgnored ) {
3323		return;
3324	}
3325	// default sorters
3326	this.sortData.id = this.id;
3327	// for backward compatibility
3328	this.sortData['original-order'] = this.id;
3329	this.sortData.random = Math.random();
3330	// go thru getSortData obj and apply the sorters
3331	var getSortData = this.layout.options.getSortData;
3332	var sorters = this.layout._sorters;
3333	for ( var key in getSortData ) {
3334		var sorter = sorters[ key ];
3335		this.sortData[ key ] = sorter( this.element, this );
3336	}
3337};
3338
3339var _destroy = Item.prototype.destroy;
3340Item.prototype.destroy = function() {
3341	// call super
3342	_destroy.apply( this, arguments );
3343	// reset display, #741
3344	this.css({
3345		display: ''
3346	});
3347};
3348
3349return Item;
3350
3351}));
3352
3353/**
3354 * Isotope LayoutMode
3355 */
3356
3357( function( window, factory ) {
3358	'use strict';
3359	// universal module definition
3360
3361	if ( typeof define == 'function' && define.amd ) {
3362		// AMD
3363		define( 'isotope/js/layout-mode',[
3364				'get-size/get-size',
3365				'outlayer/outlayer'
3366			],
3367			factory );
3368	} else if ( typeof exports == 'object' ) {
3369		// CommonJS
3370		module.exports = factory(
3371			require('get-size'),
3372			require('outlayer')
3373		);
3374	} else {
3375		// browser global
3376		window.Isotope = window.Isotope || {};
3377		window.Isotope.LayoutMode = factory(
3378			window.getSize,
3379			window.Outlayer
3380		);
3381	}
3382
3383}( window, function factory( getSize, Outlayer ) {
3384	'use strict';
3385
3386	// layout mode class
3387	function LayoutMode( isotope ) {
3388		this.isotope = isotope;
3389		// link properties
3390		if ( isotope ) {
3391			this.options = isotope.options[ this.namespace ];
3392			this.element = isotope.element;
3393			this.items = isotope.filteredItems;
3394			this.size = isotope.size;
3395		}
3396	}
3397
vendor: 4,949 bytes, lines 3398-3591
3398	/**
3399	 * some methods should just defer to default Outlayer method
3400	 * and reference the Isotope instance as `this`
3401	**/
3402	( function() {
3403		var facadeMethods = [
3404			'_resetLayout',
3405			'_getItemLayoutPosition',
3406			'_manageStamp',
3407			'_getContainerSize',
3408			'_getElementOffset',
3409			'needsResizeLayout'
3410		];
3411
3412		for ( var i=0, len = facadeMethods.length; i < len; i++ ) {
3413			var methodName = facadeMethods[i];
3414			LayoutMode.prototype[ methodName ] = getOutlayerMethod( methodName );
3415		}
3416
3417		function getOutlayerMethod( methodName ) {
3418			return function() {
3419				return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
3420			};
3421		}
3422	})();
3423
3424	// -----  ----- //
3425
3426	// for horizontal layout modes, check vertical size
3427	LayoutMode.prototype.needsVerticalResizeLayout = function() {
3428		// don't trigger if size did not change
3429		var size = getSize( this.isotope.element );
3430		// check that this.size and size are there
3431		// IE8 triggers resize on body size change, so they might not be
3432		var hasSizes = this.isotope.size && size;
3433		return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
3434	};
3435
3436	// ----- measurements ----- //
3437
3438	LayoutMode.prototype._getMeasurement = function() {
3439		this.isotope._getMeasurement.apply( this, arguments );
3440	};
3441
3442	LayoutMode.prototype.getColumnWidth = function() {
3443		this.getSegmentSize( 'column', 'Width' );
3444	};
3445
3446	LayoutMode.prototype.getRowHeight = function() {
3447		this.getSegmentSize( 'row', 'Height' );
3448	};
3449
3450	/**
3451	 * get columnWidth or rowHeight
3452	 * segment: 'column' or 'row'
3453	 * size 'Width' or 'Height'
3454	**/
3455	LayoutMode.prototype.getSegmentSize = function( segment, size ) {
3456		var segmentName = segment + size;
3457		var outerSize = 'outer' + size;
3458		// columnWidth / outerWidth // rowHeight / outerHeight
3459		this._getMeasurement( segmentName, outerSize );
3460		// got rowHeight or columnWidth, we can chill
3461		if ( this[ segmentName ] ) {
3462			return;
3463		}
3464		// fall back to item of first element
3465		var firstItemSize = this.getFirstItemSize();
3466		this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
3467			// or size of container
3468			this.isotope.size[ 'inner' + size ];
3469	};
3470
3471	LayoutMode.prototype.getFirstItemSize = function() {
3472		var firstItem = this.isotope.filteredItems[0];
3473		return firstItem && firstItem.element && getSize( firstItem.element );
3474	};
3475
3476	// ----- methods that should reference isotope ----- //
3477
3478	LayoutMode.prototype.layout = function() {
3479		this.isotope.layout.apply( this.isotope, arguments );
3480	};
3481
3482	LayoutMode.prototype.getSize = function() {
3483		this.isotope.getSize();
3484		this.size = this.isotope.size;
3485	};
3486
3487	// -------------------------- create -------------------------- //
3488
3489	LayoutMode.modes = {};
3490
3491	LayoutMode.create = function( namespace, options ) {
3492
3493		function Mode() {
3494			LayoutMode.apply( this, arguments );
3495		}
3496
3497		Mode.prototype = new LayoutMode();
3498
3499		// default options
3500		if ( options ) {
3501			Mode.options = options;
3502		}
3503
3504		Mode.prototype.namespace = namespace;
3505		// register in Isotope
3506		LayoutMode.modes[ namespace ] = Mode;
3507
3508		return Mode;
3509	};
3510
3511	return LayoutMode;
3512
3513}));
3514
3515/*!
3516 * Masonry v3.3.1
3517 * Cascading grid layout library
3518 * http://masonry.desandro.com
3519 * MIT License
3520 * by David DeSandro
3521 */
3522
3523( function( window, factory ) {
3524	'use strict';
3525	// universal module definition
3526	if ( typeof define === 'function' && define.amd ) {
3527		// AMD
3528		define( 'masonry/masonry',[
3529				'outlayer/outlayer',
3530				'get-size/get-size',
3531				'fizzy-ui-utils/utils'
3532			],
3533			factory );
3534	} else if ( typeof exports === 'object' ) {
3535		// CommonJS
3536		module.exports = factory(
3537			require('outlayer'),
3538			require('get-size'),
3539			require('fizzy-ui-utils')
3540		);
3541	} else {
3542		// browser global
3543		window.Masonry = factory(
3544			window.Outlayer,
3545			window.getSize,
3546			window.fizzyUIUtils
3547		);
3548	}
3549
3550}( window, function factory( Outlayer, getSize, utils ) {
3551
3552
3553
3554// -------------------------- masonryDefinition -------------------------- //
3555
3556	// create an Outlayer layout class
3557	var Masonry = Outlayer.create('masonry');
3558
3559	Masonry.prototype._resetLayout = function() {
3560		this.getSize();
3561		this._getMeasurement( 'columnWidth', 'outerWidth' );
3562		this._getMeasurement( 'gutter', 'outerWidth' );
3563		this.measureColumns();
3564
3565		// reset column Y
3566		var i = this.cols;
3567		this.colYs = [];
3568		while (i--) {
3569			this.colYs.push( 0 );
3570		}
3571
3572		this.maxY = 0;
3573	};
3574
3575	Masonry.prototype.measureColumns = function() {
3576		this.getContainerWidth();
3577		// if columnWidth is 0, default to outerWidth of first item
3578		if ( !this.columnWidth ) {
3579			var firstItem = this.items[0];
3580			var firstItemElem = firstItem && firstItem.element;
3581			// columnWidth fall back to item of first element
3582			this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
3583				// if first elem has no width, default to size of container
3584				this.containerWidth;
3585		}
3586
3587		var columnWidth = this.columnWidth += this.gutter;
3588
3589		// calculate columns
3590		var containerWidth = this.containerWidth + this.gutter;
3591		var cols = containerWidth / columnWidth;
3592		// fix rounding errors, typically with gutters
3593		var excess = columnWidth - containerWidth % columnWidth;
3594		// if overshoot is less than a pixel, round up, otherwise floor it
3595		var mathMethod = excess && excess < 1 ? 'round' : 'floor';
3596		cols = Math[ mathMethod ]( cols );
3597		this.cols = Math.max( cols, 1 );
3598	};
3599
3600	Masonry.prototype.getContainerWidth = function() {
3601		// container is parent if fit width
3602		var container = this.options.isFitWidth ? this.element.parentNode : this.element;
3603		// check that this.size and size are there
3604		// IE8 triggers resize on body size change, so they might not be
3605		var size = getSize( container );
3606		this.containerWidth = size && size.innerWidth;
3607	};
3608
3609	Masonry.prototype._getItemLayoutPosition = function( item ) {
3610		item.getSize();
3611		// how many columns does this brick span
3612		var remainder = item.size.outerWidth % this.columnWidth;
3613		var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
3614		// round if off by 1 pixel, otherwise use ceil
3615		var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
3616		colSpan = Math.min( colSpan, this.cols );
3617
3618		var colGroup = this._getColGroup( colSpan );
3619		// get the minimum Y value from the columns
3620		var minimumY = Math.min.apply( Math, colGroup );
3621		var shortColIndex = utils.indexOf( colGroup, minimumY );
3622
3623		// position the brick
3624		var position = {
3625			x: this.columnWidth * shortColIndex,
3626			y: minimumY
3627		};
3628
3629		// apply setHeight to necessary columns
3630		var setHeight = minimumY + item.size.outerHeight;
3631		var setSpan = this.cols + 1 - colGroup.length;
3632		for ( var i = 0; i < setSpan; i++ ) {
3633			this.colYs[ shortColIndex + i ] = setHeight;
3634		}
3635
3636		return position;
3637	};
3638
3639	/**
3640	 * @param {Number} colSpan - number of columns the element spans
3641	 * @returns {Array} colGroup
3642	 */
3643	Masonry.prototype._getColGroup = function( colSpan ) {
3644		if ( colSpan < 2 ) {
3645			// if brick spans only one column, use all the column Ys
3646			return this.colYs;
3647		}
3648
3649		var colGroup = [];
3650		// how many different places could this brick fit horizontally
3651		var groupCount = this.cols + 1 - colSpan;
3652		// for each group potential horizontal position
3653		for ( var i = 0; i < groupCount; i++ ) {
3654			// make an array of colY values for that one group
3655			var groupColYs = this.colYs.slice( i, i + colSpan );
3656			// and get the max value of the array
3657			colGroup[i] = Math.max.apply( Math, groupColYs );
3658		}
3659		return colGroup;
3660	};
3661
3662	Masonry.prototype._manageStamp = function( stamp ) {
3663		var stampSize = getSize( stamp );
3664		var offset = this._getElementOffset( stamp );
3665		// get the columns that this stamp affects
3666		var firstX = this.options.isOriginLeft ? offset.left : offset.right;
3667		var lastX = firstX + stampSize.outerWidth;
3668		var firstCol = Math.floor( firstX / this.columnWidth );
3669		firstCol = Math.max( 0, firstCol );
3670		var lastCol = Math.floor( lastX / this.columnWidth );
3671		// lastCol should not go over if multiple of columnWidth #425
3672		lastCol -= lastX % this.columnWidth ? 0 : 1;
3673		lastCol = Math.min( this.cols - 1, lastCol );
3674		// set colYs to bottom of the stamp
3675		var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) +
3676			stampSize.outerHeight;
3677		for ( var i = firstCol; i <= lastCol; i++ ) {
3678			this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
3679		}
3680	};
3681
3682	Masonry.prototype._getContainerSize = function() {
3683		this.maxY = Math.max.apply( Math, this.colYs );
3684		var size = {
3685			height: this.maxY
3686		};
3687
3688		if ( this.options.isFitWidth ) {
3689			size.width = this._getContainerFitWidth();
3690		}
3691
3692		return size;
3693	};
3694
3695	Masonry.prototype._getContainerFitWidth = function() {
3696		var unusedCols = 0;
3697		// count unused columns
3698		var i = this.cols;
3699		while ( --i ) {
3700			if ( this.colYs[i] !== 0 ) {
3701				break;
3702			}
3703			unusedCols++;
3704		}
3705		// fit container to columns that have been used
3706		return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
3707	};
3708
3709	Masonry.prototype.needsResizeLayout = function() {
3710		var previousWidth = this.containerWidth;
3711		this.getContainerWidth();
3712		return previousWidth !== this.containerWidth;
3713	};
3714
3715	return Masonry;
3716
3717}));
3718
3719/*!
3720 * Masonry layout mode
3721 * sub-classes Masonry
3722 * http://masonry.desandro.com
3723 */
3724
3725( function( window, factory ) {
3726	'use strict';
3727	// universal module definition
3728	if ( typeof define == 'function' && define.amd ) {
3729		// AMD
3730		define( 'isotope/js/layout-modes/masonry',[
3731				'../layout-mode',
3732				'masonry/masonry'
3733			],
3734			factory );
3735	} else if ( typeof exports == 'object' ) {
3736		// CommonJS
3737		module.exports = factory(
3738			require('../layout-mode'),
3739			require('masonry-layout')
3740		);
3741	} else {
3742		// browser global
3743		factory(
3744			window.Isotope.LayoutMode,
3745			window.Masonry
3746		);
3747	}
3748
3749}( window, function factory( LayoutMode, Masonry ) {
3750'use strict';
3751
3752// -------------------------- helpers -------------------------- //
3753
3754// extend objects
3755function extend( a, b ) {
3756	for ( var prop in b ) {
3757		a[ prop ] = b[ prop ];
3758	}
3759	return a;
3760}
3761
3762// -------------------------- masonryDefinition -------------------------- //
3763
3764	// create an Outlayer layout class
vendor: 8,024 bytes, lines 3765-4098
3765	var MasonryMode = LayoutMode.create('masonry');
3766
3767	// save on to these methods
3768	var _getElementOffset = MasonryMode.prototype._getElementOffset;
3769	var layout = MasonryMode.prototype.layout;
3770	var _getMeasurement = MasonryMode.prototype._getMeasurement;
3771
3772	// sub-class Masonry
3773	extend( MasonryMode.prototype, Masonry.prototype );
3774
3775	// set back, as it was overwritten by Masonry
3776	MasonryMode.prototype._getElementOffset = _getElementOffset;
3777	MasonryMode.prototype.layout = layout;
3778	MasonryMode.prototype._getMeasurement = _getMeasurement;
3779
3780	var measureColumns = MasonryMode.prototype.measureColumns;
3781	MasonryMode.prototype.measureColumns = function() {
3782		// set items, used if measuring first item
3783		this.items = this.isotope.filteredItems;
3784		measureColumns.call( this );
3785	};
3786
3787	// HACK copy over isOriginLeft/Top options
3788	var _manageStamp = MasonryMode.prototype._manageStamp;
3789	MasonryMode.prototype._manageStamp = function() {
3790		this.options.isOriginLeft = this.isotope.options.isOriginLeft;
3791		this.options.isOriginTop = this.isotope.options.isOriginTop;
3792		_manageStamp.apply( this, arguments );
3793	};
3794
3795	return MasonryMode;
3796
3797}));
3798
3799/**
3800 * fitRows layout mode
3801 */
3802
3803( function( window, factory ) {
3804	'use strict';
3805	// universal module definition
3806	if ( typeof define == 'function' && define.amd ) {
3807		// AMD
3808		define( 'isotope/js/layout-modes/fit-rows',[
3809				'../layout-mode'
3810			],
3811			factory );
3812	} else if ( typeof exports == 'object' ) {
3813		// CommonJS
3814		module.exports = factory(
3815			require('../layout-mode')
3816		);
3817	} else {
3818		// browser global
3819		factory(
3820			window.Isotope.LayoutMode
3821		);
3822	}
3823
3824}( window, function factory( LayoutMode ) {
3825'use strict';
3826
3827var FitRows = LayoutMode.create('fitRows');
3828
3829FitRows.prototype._resetLayout = function() {
3830	this.x = 0;
3831	this.y = 0;
3832	this.maxY = 0;
3833	this._getMeasurement( 'gutter', 'outerWidth' );
3834};
3835
3836FitRows.prototype._getItemLayoutPosition = function( item ) {
3837	item.getSize();
3838
3839	var itemWidth = item.size.outerWidth + this.gutter;
3840	// if this element cannot fit in the current row
3841	var containerWidth = this.isotope.size.innerWidth + this.gutter;
3842	if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
3843		this.x = 0;
3844		this.y = this.maxY;
3845	}
3846
3847	var position = {
3848		x: this.x,
3849		y: this.y
3850	};
3851
3852	this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
3853	this.x += itemWidth;
3854
3855	return position;
3856};
3857
3858FitRows.prototype._getContainerSize = function() {
3859	return { height: this.maxY };
3860};
3861
3862return FitRows;
3863
3864}));
3865
3866/**
3867 * vertical layout mode
3868 */
3869
3870( function( window, factory ) {
3871	'use strict';
3872	// universal module definition
3873	if ( typeof define == 'function' && define.amd ) {
3874		// AMD
3875		define( 'isotope/js/layout-modes/vertical',[
3876				'../layout-mode'
3877			],
3878			factory );
3879	} else if ( typeof exports == 'object' ) {
3880		// CommonJS
3881		module.exports = factory(
3882			require('../layout-mode')
3883		);
3884	} else {
3885		// browser global
3886		factory(
3887			window.Isotope.LayoutMode
3888		);
3889	}
3890
3891}( window, function factory( LayoutMode ) {
3892'use strict';
3893
3894var Vertical = LayoutMode.create( 'vertical', {
3895	horizontalAlignment: 0
3896});
3897
3898Vertical.prototype._resetLayout = function() {
3899	this.y = 0;
3900};
3901
3902Vertical.prototype._getItemLayoutPosition = function( item ) {
3903	item.getSize();
3904	var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
3905		this.options.horizontalAlignment;
3906	var y = this.y;
3907	this.y += item.size.outerHeight;
3908	return { x: x, y: y };
3909};
3910
3911Vertical.prototype._getContainerSize = function() {
3912	return { height: this.y };
3913};
3914
3915return Vertical;
3916
3917}));
3918
3919/*!
3920 * Isotope v2.2.2
3921 *
3922 * Licensed GPLv3 for open source use
3923 * or Isotope Commercial License for commercial use
3924 *
3925 * http://isotope.metafizzy.co
3926 * Copyright 2015 Metafizzy
3927 */
3928
3929( function( window, factory ) {
3930	'use strict';
3931	// universal module definition
3932
3933	if ( typeof define == 'function' && define.amd ) {
3934		// AMD
3935		define( [
3936				'outlayer/outlayer',
3937				'get-size/get-size',
3938				'matches-selector/matches-selector',
3939				'fizzy-ui-utils/utils',
3940				'isotope/js/item',
3941				'isotope/js/layout-mode',
3942				// include default layout modes
3943				'isotope/js/layout-modes/masonry',
3944				'isotope/js/layout-modes/fit-rows',
3945				'isotope/js/layout-modes/vertical'
3946			],
3947			function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
3948				return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
3949			});
3950	} else if ( typeof exports == 'object' ) {
3951		// CommonJS
3952		module.exports = factory(
3953			window,
3954			require('outlayer'),
3955			require('get-size'),
3956			require('desandro-matches-selector'),
3957			require('fizzy-ui-utils'),
3958			require('./item'),
3959			require('./layout-mode'),
3960			// include default layout modes
3961			require('./layout-modes/masonry'),
3962			require('./layout-modes/fit-rows'),
3963			require('./layout-modes/vertical')
3964		);
3965	} else {
3966		// browser global
3967		window.Isotope = factory(
3968			window,
3969			window.Outlayer,
3970			window.getSize,
3971			window.matchesSelector,
3972			window.fizzyUIUtils,
3973			window.Isotope.Item,
3974			window.Isotope.LayoutMode
3975		);
3976	}
3977
3978}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
3979	Item, LayoutMode ) {
3980
3981
3982
3983// -------------------------- vars -------------------------- //
3984
3985var jQuery = window.jQuery;
3986
3987// -------------------------- helpers -------------------------- //
3988
3989var trim = String.prototype.trim ?
3990	function( str ) {
3991		return str.trim();
3992	} :
3993	function( str ) {
3994		return str.replace( /^\s+|\s+$/g, '' );
3995	};
3996
3997var docElem = document.documentElement;
3998
3999var getText = docElem.textContent ?
4000	function( elem ) {
4001		return elem.textContent;
4002	} :
4003	function( elem ) {
4004		return elem.innerText;
4005	};
4006
4007// -------------------------- isotopeDefinition -------------------------- //
4008
4009	// create an Outlayer layout class
4010	var Isotope = Outlayer.create( 'isotope', {
4011		layoutMode: "masonry",
4012		isJQueryFiltering: true,
4013		sortAscending: true
4014	});
4015
4016	Isotope.Item = Item;
4017	Isotope.LayoutMode = LayoutMode;
4018
4019	Isotope.prototype._create = function() {
4020		this.itemGUID = 0;
4021		// functions that sort items
4022		this._sorters = {};
4023		this._getSorters();
4024		// call super
4025		Outlayer.prototype._create.call( this );
4026
4027		// create layout modes
4028		this.modes = {};
4029		// start filteredItems with all items
4030		this.filteredItems = this.items;
4031		// keep of track of sortBys
4032		this.sortHistory = [ 'original-order' ];
4033		// create from registered layout modes
4034		for ( var name in LayoutMode.modes ) {
4035			this._initLayoutMode( name );
4036		}
4037	};
4038
4039	Isotope.prototype.reloadItems = function() {
4040		// reset item ID counter
4041		this.itemGUID = 0;
4042		// call super
4043		Outlayer.prototype.reloadItems.call( this );
4044	};
4045
4046	Isotope.prototype._itemize = function() {
4047		var items = Outlayer.prototype._itemize.apply( this, arguments );
4048		// assign ID for original-order
4049		for ( var i=0, len = items.length; i < len; i++ ) {
4050			var item = items[i];
4051			item.id = this.itemGUID++;
4052		}
4053		this._updateItemsSortData( items );
4054		return items;
4055	};
4056
4057
4058	// -------------------------- layout -------------------------- //
4059
4060	Isotope.prototype._initLayoutMode = function( name ) {
4061		var Mode = LayoutMode.modes[ name ];
4062		// set mode options
4063		// HACK extend initial options, back-fill in default options
4064		var initialOpts = this.options[ name ] || {};
4065		this.options[ name ] = Mode.options ?
4066			utils.extend( Mode.options, initialOpts ) : initialOpts;
4067		// init layout mode instance
4068		this.modes[ name ] = new Mode( this );
4069	};
4070
4071
4072	Isotope.prototype.layout = function() {
4073		// if first time doing layout, do all magic
4074		if ( !this._isLayoutInited && this.options.isInitLayout ) {
4075			this.arrange();
4076			return;
4077		}
4078		this._layout();
4079	};
4080
4081	// private method to be used in layout() & magic()
4082	Isotope.prototype._layout = function() {
4083		// don't animate first layout
4084		var isInstant = this._getIsInstant();
4085		// layout flow
4086		this._resetLayout();
4087		this._manageStamps();
4088		this.layoutItems( this.filteredItems, isInstant );
4089
4090		// flag for initalized
4091		this._isLayoutInited = true;
4092	};
4093
4094	// filter + sort + layout
4095	Isotope.prototype.arrange = function( opts ) {
4096		// set any options pass
4097		this.option( opts );
4098		this._getIsInstant();
4099		// filter, sort, and layout
4100
4101		// filter
4102		var filtered = this._filter( this.items );
4103		this.filteredItems = filtered.matches;
4104
4105		var _this = this;
4106		function hideReveal() {
4107			_this.reveal( filtered.needReveal );
4108			_this.hide( filtered.needHide );
4109		}
4110
4111		this._bindArrangeComplete();
4112
4113		if ( this._isInstant ) {
4114			this._noTransition( hideReveal );
4115		} else {
4116			hideReveal();
4117		}
4118
4119		this._sort();
4120		this._layout();
4121	};
4122	// alias to _init for main plugin method
4123	Isotope.prototype._init = Isotope.prototype.arrange;
4124
4125	// HACK
4126	// Don't animate/transition first layout
4127	// Or don't animate/transition other layouts
4128	Isotope.prototype._getIsInstant = function() {
4129		var isInstant = this.options.isLayoutInstant !== undefined ?
4130			this.options.isLayoutInstant : !this._isLayoutInited;
4131		this._isInstant = isInstant;
4132		return isInstant;
4133	};
4134
4135	// listen for layoutComplete, hideComplete and revealComplete
4136	// to trigger arrangeComplete
4137	Isotope.prototype._bindArrangeComplete = function() {
4138		// listen for 3 events to trigger arrangeComplete
4139		var isLayoutComplete, isHideComplete, isRevealComplete;
4140		var _this = this;
4141		function arrangeParallelCallback() {
4142			if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
4143				_this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
4144			}
4145		}
4146		this.once( 'layoutComplete', function() {
4147			isLayoutComplete = true;
4148			arrangeParallelCallback();
4149		});
4150		this.once( 'hideComplete', function() {
4151			isHideComplete = true;
4152			arrangeParallelCallback();
4153		});
4154		this.once( 'revealComplete', function() {
4155			isRevealComplete = true;
4156			arrangeParallelCallback();
4157		});
4158	};
4159
4160	// -------------------------- filter -------------------------- //
4161
4162	Isotope.prototype._filter = function( items ) {
4163		var filter = this.options.filter;
4164		filter = filter || '*';
4165		var matches = [];
4166		var hiddenMatched = [];
4167		var visibleUnmatched = [];
4168
4169		var test = this._getFilterTest( filter );
4170
4171		// test each item
4172		for ( var i=0, len = items.length; i < len; i++ ) {
4173			var item = items[i];
4174			if ( item.isIgnored ) {
4175				continue;
4176			}
4177			// add item to either matched or unmatched group
4178			var isMatched = test( item );
4179			// item.isFilterMatched = isMatched;
4180			// add to matches if its a match
4181			if ( isMatched ) {
4182				matches.push( item );
4183			}
4184			// add to additional group if item needs to be hidden or revealed
4185			if ( isMatched && item.isHidden ) {
4186				hiddenMatched.push( item );
4187			} else if ( !isMatched && !item.isHidden ) {
4188				visibleUnmatched.push( item );
4189			}
4190		}
4191
4192		// return collections of items to be manipulated
4193		return {
4194			matches: matches,
4195			needReveal: hiddenMatched,
4196			needHide: visibleUnmatched
4197		};
4198	};
4199
4200	// get a jQuery, function, or a matchesSelector test given the filter
4201	Isotope.prototype._getFilterTest = function( filter ) {
4202		if ( jQuery && this.options.isJQueryFiltering ) {
4203			// use jQuery
4204			return function( item ) {
4205				return jQuery( item.element ).is( filter );
4206			};
4207		}
4208		if ( typeof filter == 'function' ) {
4209			// use filter as function
4210			return function( item ) {
4211				return filter( item.element );
4212			};
4213		}
4214		// default, use filter as selector string
4215		return function( item ) {
4216			return matchesSelector( item.element, filter );
4217		};
4218	};
4219
4220	// -------------------------- sorting -------------------------- //
4221
4222	/**
4223	 * @params {Array} elems
4224	 * @public
4225	 */
4226	Isotope.prototype.updateSortData = function( elems ) {
4227		// get items
4228		var items;
4229		if ( elems ) {
4230			elems = utils.makeArray( elems );
4231			items = this.getItems( elems );
4232		} else {
4233			// update all items if no elems provided
4234			items = this.items;
4235		}
4236
4237		this._getSorters();
4238		this._updateItemsSortData( items );
4239	};
4240
4241	Isotope.prototype._getSorters = function() {
4242		var getSortData = this.options.getSortData;
4243		for ( var key in getSortData ) {
4244			var sorter = getSortData[ key ];
4245			this._sorters[ key ] = mungeSorter( sorter );
4246		}
4247	};
4248
4249	/**
4250	 * @params {Array} items - of Isotope.Items
4251	 * @private
4252	 */
4253	Isotope.prototype._updateItemsSortData = function( items ) {
4254		// do not update if no items
4255		var len = items && items.length;
4256
4257		for ( var i=0; len && i < len; i++ ) {
4258			var item = items[i];
4259			item.updateSortData();
4260		}
4261	};
4262
4263	// ----- munge sorter ----- //
4264
4265	// encapsulate this, as we just need mungeSorter
4266	// other functions in here are just for munging
4267	var mungeSorter = ( function() {
4268		// add a magic layer to sorters for convienent shorthands
4269		// `.foo-bar` will use the text of .foo-bar querySelector
4270		// `[foo-bar]` will use attribute
4271		// you can also add parser
4272		// `.foo-bar parseInt` will parse that as a number
4273		function mungeSorter( sorter ) {
4274			// if not a string, return function or whatever it is
4275			if ( typeof sorter != 'string' ) {
4276				return sorter;
4277			}
4278			// parse the sorter string
4279			var args = trim( sorter ).split(' ');
4280			var query = args[0];
4281			// check if query looks like [an-attribute]
4282			var attrMatch = query.match( /^\[(.+)\]$/ );
4283			var attr = attrMatch && attrMatch[1];
4284			var getValue = getValueGetter( attr, query );
4285			// use second argument as a parser
4286			var parser = Isotope.sortDataParsers[ args[1] ];
4287			// parse the value, if there was a parser
4288			sorter = parser ? function( elem ) {
4289				return elem && parser( getValue( elem ) );
4290			} :
4291			// otherwise just return value
4292			function( elem ) {
4293				return elem && getValue( elem );
4294			};
4295
4296			return sorter;
4297		}
4298
4299		// get an attribute getter, or get text of the querySelector
4300		function getValueGetter( attr, query ) {
4301			var getValue;
4302			// if query looks like [foo-bar], get attribute
4303			if ( attr ) {
4304				getValue = function( elem ) {
4305					return elem.getAttribute( attr );
4306				};
4307			} else {
4308				// otherwise, assume its a querySelector, and get its text
4309				getValue = function( elem ) {
4310					var child = elem.querySelector( query );
4311					return child && getText( child );
4312				};
4313			}
4314			return getValue;
4315		}
4316
4317		return mungeSorter;
4318	})();
4319
4320	// parsers used in getSortData shortcut strings
4321	Isotope.sortDataParsers = {
4322		'parseInt': function( val ) {
4323			return parseInt( val, 10 );
4324		},
4325		'parseFloat': function( val ) {
4326			return parseFloat( val );
4327		}
4328	};
4329
4330	// ----- sort method ----- //
4331
4332	// sort filteredItem order
4333	Isotope.prototype._sort = function() {
4334		var sortByOpt = this.options.sortBy;
4335		if ( !sortByOpt ) {
4336			return;
4337		}
4338		// concat all sortBy and sortHistory
4339		var sortBys = [].concat.apply( sortByOpt, this.sortHistory );
4340		// sort magic
4341		var itemSorter = getItemSorter( sortBys, this.options.sortAscending );
4342		this.filteredItems.sort( itemSorter );
4343		// keep track of sortBy History
4344		if ( sortByOpt != this.sortHistory[0] ) {
4345			// add to front, oldest goes in last
4346			this.sortHistory.unshift( sortByOpt );
4347		}
4348	};
4349
4350	// returns a function used for sorting
4351	function getItemSorter( sortBys, sortAsc ) {
4352		return function sorter( itemA, itemB ) {
4353			// cycle through all sortKeys
4354			for ( var i = 0, len = sortBys.length; i < len; i++ ) {
4355				var sortBy = sortBys[i];
4356				var a = itemA.sortData[ sortBy ];
4357				var b = itemB.sortData[ sortBy ];
4358				if ( a > b || a < b ) {
4359					// if sortAsc is an object, use the value given the sortBy key
4360					var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
4361					var direction = isAscending ? 1 : -1;
4362					return ( a > b ? 1 : -1 ) * direction;
4363				}
4364			}
4365			return 0;
4366		};
4367	}
4368
4369	// -------------------------- methods -------------------------- //
4370
4371	// get layout mode
4372	Isotope.prototype._mode = function() {
4373		var layoutMode = this.options.layoutMode;
4374		var mode = this.modes[ layoutMode ];
4375		if ( !mode ) {
4376			// TODO console.error
4377			throw new Error( 'No layout mode: ' + layoutMode );
4378		}
4379		// HACK sync mode's options
4380		// any options set after init for layout mode need to be synced
4381		mode.options = this.options[ layoutMode ];
4382		return mode;
4383	};
4384
4385	Isotope.prototype._resetLayout = function() {
4386		// trigger original reset layout
4387		Outlayer.prototype._resetLayout.call( this );
4388		this._mode()._resetLayout();
4389	};
4390
4391	Isotope.prototype._getItemLayoutPosition = function( item  ) {
4392		return this._mode()._getItemLayoutPosition( item );
4393	};
4394
4395	Isotope.prototype._manageStamp = function( stamp ) {
4396		this._mode()._manageStamp( stamp );
4397	};
4398
4399	Isotope.prototype._getContainerSize = function() {
4400		return this._mode()._getContainerSize();
4401	};
4402
4403	Isotope.prototype.needsResizeLayout = function() {
4404		return this._mode().needsResizeLayout();
4405	};
4406
4407	// -------------------------- adding & removing -------------------------- //
4408
4409	// HEADS UP overwrites default Outlayer appended
4410	Isotope.prototype.appended = function( elems ) {
4411		var items = this.addItems( elems );
4412		if ( !items.length ) {
4413			return;
4414		}
4415		// filter, layout, reveal new items
4416		var filteredItems = this._filterRevealAdded( items );
4417		// add to filteredItems
4418		this.filteredItems = this.filteredItems.concat( filteredItems );
4419	};
4420
4421	// HEADS UP overwrites default Outlayer prepended
4422	Isotope.prototype.prepended = function( elems ) {
4423		var items = this._itemize( elems );
4424		if ( !items.length ) {
4425			return;
4426		}
4427		// start new layout
4428		this._resetLayout();
4429		this._manageStamps();
4430		// filter, layout, reveal new items
4431		var filteredItems = this._filterRevealAdded( items );
4432		// layout previous items
4433		this.layoutItems( this.filteredItems );
4434		// add to items and filteredItems
4435		this.filteredItems = filteredItems.concat( this.filteredItems );
4436		this.items = items.concat( this.items );
4437	};
4438
4439	Isotope.prototype._filterRevealAdded = function( items ) {
4440		var filtered = this._filter( items );
4441		this.hide( filtered.needHide );
4442		// reveal all new items
4443		this.reveal( filtered.matches );
4444		// layout new items, no transition
4445		this.layoutItems( filtered.matches, true );
4446		return filtered.matches;
4447	};
4448
4449	/**
4450	 * Filter, sort, and layout newly-appended item elements
4451	 * @param {Array or NodeList or Element} elems
4452	 */
4453	Isotope.prototype.insert = function( elems ) {
4454		var items = this.addItems( elems );
4455		if ( !items.length ) {
4456			return;
4457		}
4458		// append item elements
4459		var i, item;
4460		var len = items.length;
4461		for ( i=0; i < len; i++ ) {
4462			item = items[i];
4463			this.element.appendChild( item.element );
4464		}
4465		// filter new stuff
4466		var filteredInsertItems = this._filter( items ).matches;
4467		// set flag
4468		for ( i=0; i < len; i++ ) {
4469			items[i].isLayoutInstant = true;
4470		}
4471		this.arrange();
4472		// reset flag
4473		for ( i=0; i < len; i++ ) {
4474			delete items[i].isLayoutInstant;
4475		}
4476		this.reveal( filteredInsertItems );
4477	};
4478
4479	var _remove = Isotope.prototype.remove;
4480	Isotope.prototype.remove = function( elems ) {
4481		elems = utils.makeArray( elems );
4482		var removeItems = this.getItems( elems );
4483		// do regular thing
4484		_remove.call( this, elems );
4485		// bail if no items to remove
4486		var len = removeItems && removeItems.length;
4487		if ( !len ) {
4488			return;
4489		}
4490		// remove elems from filteredItems
4491		for ( var i=0; i < len; i++ ) {
4492			var item = removeItems[i];
4493			// remove item from collection
4494			utils.removeFrom( this.filteredItems, item );
4495		}
4496	};
4497
4498	Isotope.prototype.shuffle = function() {
4499		// update random sortData
4500		for ( var i=0, len = this.items.length; i < len; i++ ) {
4501			var item = this.items[i];
4502			item.sortData.random = Math.random();
4503		}
4504		this.options.sortBy = 'random';
4505		this._sort();
4506		this._layout();
4507	};
4508
4509	/**
4510	 * trigger fn without transition
4511	 * kind of hacky to have this in the first place
4512	 * @param {Function} fn
4513	 * @returns ret
4514	 * @private
4515	 */
4516	Isotope.prototype._noTransition = function( fn ) {
4517		// save transitionDuration before disabling
4518		var transitionDuration = this.options.transitionDuration;
4519		// disable transition
4520		this.options.transitionDuration = 0;
4521		// do it
4522		var returnValue = fn.call( this );
4523		// re-enable transition for reveal
4524		this.options.transitionDuration = transitionDuration;
4525		return returnValue;
4526	};
4527
4528	// ----- helper methods ----- //
4529
4530	/**
4531	 * getter method for getting filtered item elements
4532	 * @returns {Array} elems - collection of item elements
4533	 */
4534	Isotope.prototype.getFilteredItemElements = function() {
4535		var elems = [];
4536		for ( var i=0, len = this.filteredItems.length; i < len; i++ ) {
4537			elems.push( this.filteredItems[i].element );
4538		}
4539		return elems;
4540	};
4541
4542	// -----  ----- //
4543
4544	return Isotope;
4545
4546}));
4547
4548
4549/*!
4550 * Packery layout mode PACKAGED v2.0.1
4551 * sub-classes Packery
4552 */
4553
4554!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);
4554e?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")}
4554,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};
4554this.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});
4555
4556/*!
4557 * cellsByRows layout mode for Isotope
4558 * v1.1.3
4559 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html
4560 */
4561
4562/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */
4563
4564( function( window, factory ) {
4565	// universal module definition
4566	/* jshint strict: false */ /*globals define, module, require */
4567	if ( typeof define === 'function' && define.amd ) {
4568		// AMD
4569		define( [
4570				'isotope/js/layout-mode'
4571			],
4572			factory );
4573	} else if ( typeof exports === 'object' ) {
4574		// CommonJS
4575		module.exports = factory(
4576			require('isotope-layout/js/layout-mode')
4577		);
4578	} else {
4579		// browser global
4580		factory(
4581			window.Isotope.LayoutMode
4582		);
4583	}
4584
4585}( window, function factory( LayoutMode ) {
4586	'use strict';
4587
4588	var CellsByRow = LayoutMode.create( 'cellsByRow' );
4589	var proto = CellsByRow.prototype;
4590
4591	proto._resetLayout = function() {
4592		// reset properties
4593		this.itemIndex = 0;
4594		// measurements
4595		this.getColumnWidth();
4596		this.getRowHeight();
4597		// set cols
4598		this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth );
4599		this.cols = Math.max( this.cols, 1 );
4600	};
4601
4602	proto._getItemLayoutPosition = function( item ) {
4603		item.getSize();
4604		var col = this.itemIndex % this.cols;
4605		var row = Math.floor( this.itemIndex / this.cols );
4606		// center item within cell
4607		var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2;
4608		var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2;
4609		this.itemIndex++;
4610		return { x: x, y: y };
4611	};
4612
4613	proto._getContainerSize = function() {
4614		return {
4615			height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight
4616		};
4617	};
4618
4619	return CellsByRow;
4620
4621}));
4622
4623/*!
4624	 --------------------------------
4625	 Infinite Scroll
4626	 --------------------------------
4627	 + https://github.com/paulirish/infinite-scroll
4628	 + version 2.1.0
4629	 + Copyright 2011/12 Paul Irish & Luke Shumard
4630	 + Licensed under the MIT license
4631
4632	 + Documentation: http://infinite-scroll.com/
4633*/
4634;(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
4634ohVeDeCfXkcCQqDVQcQhn+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
4634iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/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
4634ing"){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;
4634r.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";
4634switch(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"])}});
4635
4636/*!
4637Waypoints - 4.0.1
4638Copyright © 2011-2016 Caleb Troughton
4639Licensed under the MIT license.
4640https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
4641*/
4642(function() {
4643	'use strict'
4644
4645	var keyCounter = 0
4646	var allWaypoints = {}
4647
4648	/* http://imakewebthings.com/waypoints/api/waypoint */
4649	function Waypoint(options) {
4650		if (!options) {
4651			throw new Error('No options passed to Waypoint constructor')
4652		}
4653		if (!options.element) {
4654			throw new Error('No element option passed to Waypoint constructor')
4655		}
4656		if (!options.handler) {
4657			throw new Error('No handler option passed to Waypoint constructor')
4658		}
4659
4660		this.key = 'waypoint-' + keyCounter
4661		this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
4662		this.element = this.options.element
4663		this.adapter = new Waypoint.Adapter(this.element)
4664		this.callback = options.handler
4665		this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
4666		this.enabled = this.options.enabled
4667		this.triggerPoint = null
4668		this.group = Waypoint.Group.findOrCreate({
4669			name: this.options.group,
4670			axis: this.axis
4671		})
4672		this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
4673
4674		if (Waypoint.offsetAliases[this.options.offset]) {
4675			this.options.offset = Waypoint.offsetAliases[this.options.offset]
4676		}
4677		this.group.add(this)
4678		this.context.add(this)
4679		allWaypoints[this.key] = this
4680		keyCounter += 1
4681	}
4682
4683	/* Private */
4684	Waypoint.prototype.queueTrigger = function(direction) {
4685		this.group.queueTrigger(this, direction)
4686	}
4687
4688	/* Private */
4689	Waypoint.prototype.trigger = function(args) {
4690		if (!this.enabled) {
4691			return
4692		}
4693		if (this.callback) {
4694			this.callback.apply(this, args)
4695		}
4696	}
4697
4698	/* Public */
4699	/* http://imakewebthings.com/waypoints/api/destroy */
4700	Waypoint.prototype.destroy = function() {
4701		this.context.remove(this)
4702		this.group.remove(this)
4703		delete allWaypoints[this.key]
4704	}
4705
4706	/* Public */
4707	/* http://imakewebthings.com/waypoints/api/disable */
4708	Waypoint.prototype.disable = function() {
4709		this.enabled = false
4710		return this
4711	}
4712
4713	/* Public */
4714	/* http://imakewebthings.com/waypoints/api/enable */
4715	Waypoint.prototype.enable = function() {
4716		this.context.refresh()
4717		this.enabled = true
4718		return this
4719	}
4720
4721	/* Public */
4722	/* http://imakewebthings.com/waypoints/api/next */
4723	Waypoint.prototype.next = function() {
4724		return this.group.next(this)
4725	}
4726
4727	/* Public */
4728	/* http://imakewebthings.com/waypoints/api/previous */
4729	Waypoint.prototype.previous = function() {
4730		return this.group.previous(this)
4731	}
4732
4733	/* Private */
4734	Waypoint.invokeAll = function(method) {
4735		var allWaypointsArray = []
4736		for (var waypointKey in allWaypoints) {
4737			allWaypointsArray.push(allWaypoints[waypointKey])
4738		}
4739		for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
4740			allWaypointsArray[i][method]()
4741		}
4742	}
4743
4744	/* Public */
4745	/* http://imakewebthings.com/waypoints/api/destroy-all */
4746	Waypoint.destroyAll = function() {
4747		Waypoint.invokeAll('destroy')
4748	}
4749
4750	/* Public */
4751	/* http://imakewebthings.com/waypoints/api/disable-all */
4752	Waypoint.disableAll = function() {
4753		Waypoint.invokeAll('disable')
4754	}
4755
4756	/* Public */
4757	/* http://imakewebthings.com/waypoints/api/enable-all */
4758	Waypoint.enableAll = function() {
4759		Waypoint.Context.refreshAll()
4760		for (var waypointKey in allWaypoints) {
4761			allWaypoints[waypointKey].enabled = true
4762		}
4763		return this
4764	}
4765
4766	/* Public */
4767	/* http://imakewebthings.com/waypoints/api/refresh-all */
4768	Waypoint.refreshAll = function() {
4769		Waypoint.Context.refreshAll()
4770	}
4771
4772	/* Public */
4773	/* http://imakewebthings.com/waypoints/api/viewport-height */
4774	Waypoint.viewportHeight = function() {
4775		return window.innerHeight || document.documentElement.clientHeight
4776	}
4777
4778	/* Public */
4779	/* http://imakewebthings.com/waypoints/api/viewport-width */
4780	Waypoint.viewportWidth = function() {
4781		return document.documentElement.clientWidth
4782	}
4783
4784	Waypoint.adapters = []
4785
4786	Waypoint.defaults = {
4787		context: window,
4788		continuous: true,
4789		enabled: true,
4790		group: 'default',
4791		horizontal: false,
4792		offset: 0
4793	}
4794
4795	Waypoint.offsetAliases = {
4796		'bottom-in-view': function() {
4797			return this.context.innerHeight() - this.adapter.outerHeight()
4798		},
4799		'right-in-view': function() {
4800			return this.context.innerWidth() - this.adapter.outerWidth()
4801		}
4802	}
4803
4804	window.Waypoint = Waypoint
4805}())
4806;(function() {
4807	'use strict'
4808
4809	function requestAnimationFrameShim(callback) {
4810		window.setTimeout(callback, 1000 / 60)
4811	}
4812
4813	var keyCounter = 0
4814	var contexts = {}
4815	var Waypoint = window.Waypoint
4816	var oldWindowLoad = window.onload
4817
4818	/* http://imakewebthings.com/waypoints/api/context */
4819	function Context(element) {
4820		this.element = element
4821		this.Adapter = Waypoint.Adapter
4822		this.adapter = new this.Adapter(element)
4823		this.key = 'waypoint-context-' + keyCounter
4824		this.didScroll = false
4825		this.didResize = false
4826		this.oldScroll = {
4827			x: this.adapter.scrollLeft(),
4828			y: this.adapter.scrollTop()
4829		}
4830		this.waypoints = {
4831			vertical: {},
4832			horizontal: {}
4833		}
4834
4835		element.waypointContextKey = this.key
4836		contexts[element.waypointContextKey] = this
4837		keyCounter += 1
4838		if (!Waypoint.windowContext) {
4839			Waypoint.windowContext = true
4840			Waypoint.windowContext = new Context(window)
4841		}
4842
4843		this.createThrottledScrollHandler()
4844		this.createThrottledResizeHandler()
4845	}
4846
4847	/* Private */
4848	Context.prototype.add = function(waypoint) {
4849		var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
4850		this.waypoints[axis][waypoint.key] = waypoint
4851		this.refresh()
4852	}
4853
4854	/* Private */
4855	Context.prototype.checkEmpty = function() {
4856		var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
4857		var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
4858		var isWindow = this.element == this.element.window
4859		if (horizontalEmpty && verticalEmpty && !isWindow) {
4860			this.adapter.off('.waypoints')
4861			delete contexts[this.key]
4862		}
4863	}
4864
4865	/* Private */
4866	Context.prototype.createThrottledResizeHandler = function() {
4867		var self = this
4868
4869		function resizeHandler() {
4870			self.handleResize()
4871			self.didResize = false
4872		}
4873
4874		this.adapter.on('resize.waypoints', function() {
4875			if (!self.didResize) {
4876				self.didResize = true
4877				Waypoint.requestAnimationFrame(resizeHandler)
4878			}
4879		})
4880	}
4881
4882	/* Private */
4883	Context.prototype.createThrottledScrollHandler = function() {
4884		var self = this
4885		function scrollHandler() {
4886			self.handleScroll()
4887			self.didScroll = false
4888		}
4889
4890		this.adapter.on('scroll.waypoints', function() {
4891			if (!self.didScroll || Waypoint.isTouch) {
4892				self.didScroll = true
4893				Waypoint.requestAnimationFrame(scrollHandler)
4894			}
4895		})
4896	}
4897
4898	/* Private */
4899	Context.prototype.handleResize = function() {
4900		Waypoint.Context.refreshAll()
4901	}
4902
4903	/* Private */
4904	Context.prototype.handleScroll = function() {
4905		var triggeredGroups = {}
4906		var axes = {
4907			horizontal: {
4908				newScroll: this.adapter.scrollLeft(),
4909				oldScroll: this.oldScroll.x,
4910				forward: 'right',
4911				backward: 'left'
4912			},
4913			vertical: {
4914				newScroll: this.adapter.scrollTop(),
4915				oldScroll: this.oldScroll.y,
4916				forward: 'down',
4917				backward: 'up'
4918			}
4919		}
4920
4921		for (var axisKey in axes) {
4922			var axis = axes[axisKey]
4923			var isForward = axis.newScroll > axis.oldScroll
4924			var direction = isForward ? axis.forward : axis.backward
4925
4926			for (var waypointKey in this.waypoints[axisKey]) {
4927				var waypoint = this.waypoints[axisKey][waypointKey]
4928				if (waypoint.triggerPoint === null) {
4929					continue
4930				}
4931				var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
4932				var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
4933				var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
4934				var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
4935				if (crossedForward || crossedBackward) {
4936					waypoint.queueTrigger(direction)
4937					triggeredGroups[waypoint.group.id] = waypoint.group
4938				}
4939			}
4940		}
4941
4942		for (var groupKey in triggeredGroups) {
4943			triggeredGroups[groupKey].flushTriggers()
4944		}
4945
4946		this.oldScroll = {
4947			x: axes.horizontal.newScroll,
4948			y: axes.vertical.newScroll
4949		}
4950	}
4951
4952	/* Private */
4953	Context.prototype.innerHeight = function() {
4954		/*eslint-disable eqeqeq */
4955		if (this.element == this.element.window) {
4956			return Waypoint.viewportHeight()
4957		}
4958		/*eslint-enable eqeqeq */
4959		return this.adapter.innerHeight()
4960	}
4961
4962	/* Private */
4963	Context.prototype.remove = function(waypoint) {
4964		delete this.waypoints[waypoint.axis][waypoint.key]
4965		this.checkEmpty()
4966	}
4967
4968	/* Private */
4969	Context.prototype.innerWidth = function() {
4970		/*eslint-disable eqeqeq */
4971		if (this.element == this.element.window) {
4972			return Waypoint.viewportWidth()
4973		}
4974		/*eslint-enable eqeqeq */
4975		return this.adapter.innerWidth()
4976	}
4977
4978	/* Public */
4979	/* http://imakewebthings.com/waypoints/api/context-destroy */
4980	Context.prototype.destroy = function() {
4981		var allWaypoints = []
4982		for (var axis in this.waypoints) {
4983			for (var waypointKey in this.waypoints[axis]) {
4984				allWaypoints.push(this.waypoints[axis][waypointKey])
4985			}
4986		}
4987		for (var i = 0, end = allWaypoints.length; i < end; i++) {
4988			allWaypoints[i].destroy()
4989		}
4990	}
4991
4992	/* Public */
4993	/* http://imakewebthings.com/waypoints/api/context-refresh */
4994	Context.prototype.refresh = function() {
4995		/*eslint-disable eqeqeq */
4996		var isWindow = this.element == this.element.window
4997		/*eslint-enable eqeqeq */
4998		var contextOffset = isWindow ? undefined : this.adapter.offset()
4999		var triggeredGroups = {}
5000		var axes
5001
5002		this.handleScroll()
5003		axes = {
5004			horizontal: {
5005				contextOffset: isWindow ? 0 : contextOffset.left,
5006				contextScroll: isWindow ? 0 : this.oldScroll.x,
5007				contextDimension: this.innerWidth(),
5008				oldScroll: this.oldScroll.x,
5009				forward: 'right',
5010				backward: 'left',
5011				offsetProp: 'left'
5012			},
5013			vertical: {
5014				contextOffset: isWindow ? 0 : contextOffset.top,
5015				contextScroll: isWindow ? 0 : this.oldScroll.y,
5016				contextDimension: this.innerHeight(),
5017				oldScroll: this.oldScroll.y,
5018				forward: 'down',
5019				backward: 'up',
5020				offsetProp: 'top'
5021			}
5022		}
5023
5024		for (var axisKey in axes) {
5025			var axis = axes[axisKey]
5026			for (var waypointKey in this.waypoints[axisKey]) {
5027				var waypoint = this.waypoints[axisKey][waypointKey]
5028				var adjustment = waypoint.options.offset
5029				var oldTriggerPoint = waypoint.triggerPoint
5030				var elementOffset = 0
5031				var freshWaypoint = oldTriggerPoint == null
5032				var contextModifier, wasBeforeScroll, nowAfterScroll
5033				var triggeredBackward, triggeredForward
5034
5035				if (waypoint.element !== waypoint.element.window) {
5036					elementOffset = waypoint.adapter.offset()[axis.offsetProp]
5037				}
5038
5039				if (typeof adjustment === 'function') {
5040					adjustment = adjustment.apply(waypoint)
5041				}
5042				else if (typeof adjustment === 'string') {
5043					adjustment = parseFloat(adjustment)
5044					if (waypoint.options.offset.indexOf('%') > - 1) {
5045						adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
5046					}
5047				}
5048
5049				contextModifier = axis.contextScroll - axis.contextOffset
5050				waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
5051				wasBeforeScroll = oldTriggerPoint < axis.oldScroll
5052				nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
5053				triggeredBackward = wasBeforeScroll && nowAfterScroll
5054				triggeredForward = !wasBeforeScroll && !nowAfterScroll
5055
5056				if (!freshWaypoint && triggeredBackward) {
5057					waypoint.queueTrigger(axis.backward)
5058					triggeredGroups[waypoint.group.id] = waypoint.group
5059				}
5060				else if (!freshWaypoint && triggeredForward) {
5061					waypoint.queueTrigger(axis.forward)
5062					triggeredGroups[waypoint.group.id] = waypoint.group
5063				}
5064				else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
5065					waypoint.queueTrigger(axis.forward)
5066					triggeredGroups[waypoint.group.id] = waypoint.group
5067				}
5068			}
5069		}
5070
5071		Waypoint.requestAnimationFrame(function() {
5072			for (var groupKey in triggeredGroups) {
5073				triggeredGroups[groupKey].flushTriggers()
5074			}
5075		})
5076
5077		return this
5078	}
5079
5080	/* Private */
5081	Context.findOrCreateByElement = function(element) {
5082		return Context.findByElement(element) || new Context(element)
5083	}
5084
5085	/* Private */
5086	Context.refreshAll = function() {
5087		for (var contextId in contexts) {
5088			contexts[contextId].refresh()
5089		}
5090	}
5091
5092	/* Public */
5093	/* http://imakewebthings.com/waypoints/api/context-find-by-element */
5094	Context.findByElement = function(element) {
5095		return contexts[element.waypointContextKey]
5096	}
5097
5098	window.onload = function() {
5099		if (oldWindowLoad) {
5100			oldWindowLoad()
5101		}
5102		Context.refreshAll()
5103	}
5104
5105
5106	Waypoint.requestAnimationFrame = function(callback) {
5107		var requestFn = window.requestAnimationFrame ||
5108			window.mozRequestAnimationFrame ||
5109			window.webkitRequestAnimationFrame ||
5110			requestAnimationFrameShim
5111		requestFn.call(window, callback)
5112	}
5113	Waypoint.Context = Context
5114}())
5115;(function() {
5116	'use strict'
5117
5118	function byTriggerPoint(a, b) {
5119		return a.triggerPoint - b.triggerPoint
5120	}
5121
5122	function byReverseTriggerPoint(a, b) {
5123		return b.triggerPoint - a.triggerPoint
5124	}
5125
5126	var groups = {
5127		vertical: {},
5128		horizontal: {}
5129	}
5130	var Waypoint = window.Waypoint
5131
5132	/* http://imakewebthings.com/waypoints/api/group */
5133	function Group(options) {
5134		this.name = options.name
5135		this.axis = options.axis
5136		this.id = this.name + '-' + this.axis
5137		this.waypoints = []
5138		this.clearTriggerQueues()
5139		groups[this.axis][this.name] = this
5140	}
5141
5142	/* Private */
5143	Group.prototype.add = function(waypoint) {
5144		this.waypoints.push(waypoint)
5145	}
5146
5147	/* Private */
5148	Group.prototype.clearTriggerQueues = function() {
5149		this.triggerQueues = {
5150			up: [],
5151			down: [],
5152			left: [],
5153			right: []
5154		}
5155	}
5156
5157	/* Private */
5158	Group.prototype.flushTriggers = function() {
5159		for (var direction in this.triggerQueues) {
5160			var waypoints = this.triggerQueues[direction]
5161			var reverse = direction === 'up' || direction === 'left'
5162			waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
5163			for (var i = 0, end = waypoints.length; i < end; i += 1) {
5164				var waypoint = waypoints[i]
5165				if (waypoint.options.continuous || i === waypoints.length - 1) {
5166					waypoint.trigger([direction])
5167				}
5168			}
5169		}
5170		this.clearTriggerQueues()
5171	}
5172
5173	/* Private */
5174	Group.prototype.next = function(waypoint) {
5175		this.waypoints.sort(byTriggerPoint)
5176		var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
5177		var isLast = index === this.waypoints.length - 1
5178		return isLast ? null : this.waypoints[index + 1]
5179	}
5180
5181	/* Private */
5182	Group.prototype.previous = function(waypoint) {
5183		this.waypoints.sort(byTriggerPoint)
5184		var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
5185		return index ? this.waypoints[index - 1] : null
5186	}
5187
5188	/* Private */
5189	Group.prototype.queueTrigger = function(waypoint, direction) {
5190		this.triggerQueues[direction].push(waypoint)
5191	}
5192
5193	/* Private */
5194	Group.prototype.remove = function(waypoint) {
5195		var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
5196		if (index > -1) {
5197			this.waypoints.splice(index, 1)
5198		}
5199	}
5200
5201	/* Public */
5202	/* http://imakewebthings.com/waypoints/api/first */
5203	Group.prototype.first = function() {
5204		return this.waypoints[0]
5205	}
5206
5207	/* Public */
5208	/* http://imakewebthings.com/waypoints/api/last */
5209	Group.prototype.last = function() {
5210		return this.waypoints[this.waypoints.length - 1]
5211	}
5212
5213	/* Private */
5214	Group.findOrCreate = function(options) {
5215		return groups[options.axis][options.name] || new Group(options)
5216	}
5217
5218	Waypoint.Group = Group
5219}())
5220;(function() {
5221	'use strict'
5222
5223	var $ = window.jQuery
5224	var Waypoint = window.Waypoint
5225
5226	function JQueryAdapter(element) {
5227		this.$element = $(element)
5228	}
5229
5230	$.each([
5231		'innerHeight',
5232		'innerWidth',
5233		'off',
5234		'offset',
5235		'on',
5236		'outerHeight',
5237		'outerWidth',
5238		'scrollLeft',
5239		'scrollTop'
5240	], function(i, method) {
5241		JQueryAdapter.prototype[method] = function() {
5242			var args = Array.prototype.slice.call(arguments)
5243			return this.$element[method].apply(this.$element, args)
5244		}
5245	})
5246
5247	$.each([
5248		'extend',
5249		'inArray',
5250		'isEmptyObject'
5251	], function(i, method) {
5252		JQueryAdapter[method] = $[method]
5253	})
5254
5255	Waypoint.adapters.push({
5256		name: 'jquery',
5257		Adapter: JQueryAdapter
5258	})
5259	Waypoint.Adapter = JQueryAdapter
5260}())
5261;(function() {
5262	'use strict'
5263
5264	var Waypoint = window.Waypoint
5265
5266	function createExtension(framework) {
5267		return function() {
5268			var waypoints = []
5269			var overrides = arguments[0]
5270
5271			if (framework.isFunction(arguments[0])) {
5272				overrides = framework.extend({}, arguments[1])
5273				overrides.handler = arguments[0]
5274			}
5275
5276			this.each(function() {
5277				var options = framework.extend({}, overrides, {
5278					element: this
5279				})
5280				if (typeof options.context === 'string') {
5281					options.context = framework(this).closest(options.context)[0]
5282				}
5283				waypoints.push(new Waypoint(options))
5284			})
5285
5286			return waypoints
5287		}
5288	}
5289
5290	if (window.jQuery) {
5291		window.jQuery.fn.waypoint = createExtension(window.jQuery)
5292	}
5293	if (window.Zepto) {
5294		window.Zepto.fn.waypoint = createExtension(window.Zepto)
5295	}
5296}())
5297;
5298
5299/*!
5300Waypoints Inview Shortcut - 4.0.1
5301Copyright © 2011-2016 Caleb Troughton
5302Licensed under the MIT license.
5303https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
5304*/
5305(function() {
5306	'use strict'
5307
5308	function noop() {}
5309
5310	var Waypoint = window.Waypoint
5311
5312	/* http://imakewebthings.com/waypoints/shortcuts/inview */
5313	function Inview(options) {
5314		this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
5315		this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
5316		this.waypoints = []
5317		this.element = this.options.element
5318		this.createWaypoints()
5319	}
5320
5321	/* Private */
5322	Inview.prototype.createWaypoints = function() {
5323		var configs = {
5324			vertical: [{
5325				down: 'enter',
5326				up: 'exited',
5327				offset: '100%'
5328			}, {
5329				down: 'entered',
5330				up: 'exit',
5331				offset: 'bottom-in-view'
5332			}, {
5333				down: 'exit',
5334				up: 'entered',
5335				offset: 0
5336			}, {
5337				down: 'exited',
5338				up: 'enter',
5339				offset: function() {
5340					return -this.adapter.outerHeight()
5341				}
5342			}],
5343			horizontal: [{
5344				right: 'enter',
5345				left: 'exited',
5346				offset: '100%'
5347			}, {
5348				right: 'entered',
5349				left: 'exit',
5350				offset: 'right-in-view'
5351			}, {
5352				right: 'exit',
5353				left: 'entered',
5354				offset: 0
5355			}, {
5356				right: 'exited',
5357				left: 'enter',
5358				offset: function() {
5359					return -this.adapter.outerWidth()
5360				}
5361			}]
5362		}
5363
5364		for (var i = 0, end = configs[this.axis].length; i < end; i++) {
5365			var config = configs[this.axis][i]
5366			this.createWaypoint(config)
5367		}
5368	}
5369
5370	/* Private */
5371	Inview.prototype.createWaypoint = function(config) {
5372		var self = this
5373		this.waypoints.push(new Waypoint({
5374			context: this.options.context,
5375			element: this.options.element,
5376			enabled: this.options.enabled,
5377			handler: (function(config) {
5378				return function(direction) {
5379					self.options[config[direction]].call(self, direction)
5380				}
5381			}(config)),
5382			offset: config.offset,
5383			horizontal: this.options.horizontal
5384		}))
5385	}
5386
5387	/* Public */
5388	Inview.prototype.destroy = function() {
5389		for (var i = 0, end = this.waypoints.length; i < end; i++) {
5390			this.waypoints[i].destroy()
5391		}
5392		this.waypoints = []
5393	}
5394
5395	Inview.prototype.disable = function() {
5396		for (var i = 0, end = this.waypoints.length; i < end; i++) {
5397			this.waypoints[i].disable()
5398		}
5399	}
5400
5401	Inview.prototype.enable = function() {
5402		for (var i = 0, end = this.waypoints.length; i < end; i++) {
5403			this.waypoints[i].enable()
5404		}
5405	}
5406
5407	Inview.defaults = {
5408		context: window,
5409		enabled: true,
5410		enter: noop,
5411		entered: noop,
5412		exit: noop,
5413		exited: noop
5414	}
5415
5416	Waypoint.Inview = Inview
5417}())
5418;
5419
5420/*
5421 * SmartMenus jQuery v0.9.6
5422 * http://www.smartmenus.org/
5423 *
5424 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd.
5425 * http://vadikom.com/
5426 *
5427 * Released under the MIT license:
5428 * http://www.opensource.org/licenses/MIT
5429 */
5430
5431(function($) {
5432
5433	var menuTrees = [],
5434		IE = !!window.createPopup, // we need to detect it, unfortunately
5435		IElt9 = IE && !document.defaultView,
5436		IElt8 = IE && !document.querySelector,
5437		IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined',
5438		mouse = false, // optimize for touch by default - we will detect for mouse input
5439		mouseDetectionEnabled = false;
5440
5441	// Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.)
5442	function initMouseDetection(disable) {
5443		if (!mouseDetectionEnabled && !disable) {
5444			// if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present
5445			// 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)
5446			var firstTime = true,
5447				lastMove = null;
5448			$(document).bind({
5449				'mousemove.smartmenus_mouse': function(e) {
5450					var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() };
5451					if (lastMove) {
5452						var deltaX = Math.abs(lastMove.x - thisMove.x),
5453							deltaY = Math.abs(lastMove.y - thisMove.y);
5454						if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
5455							mouse = true;
5456							// 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
5457							if (firstTime) {
5458								var $a = $(e.target).closest('a');
5459								if ($a.is('a')) {
5460									$.each(menuTrees, function() {
5461										if ($.contains(this.$root[0], $a[0])) {
5462											this.itemEnter({ currentTarget: $a[0] });
5463											return false;
5464										}
5465									});
5466								}
5467								firstTime = false;
5468							}
5469						}
5470					}
5471					lastMove = thisMove;
5472				},
5473				'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) {
5474					if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) {
5475						mouse = false;
5476					}
5477				}
5478			});
5479			mouseDetectionEnabled = true;
5480		} else if (mouseDetectionEnabled && disable) {
5481			$(document).unbind('.smartmenus_mouse');
5482			mouseDetectionEnabled = false;
5483		}
5484	};
5485
5486	$.SmartMenus = function(elm, options) {
5487		this.$root = $(elm);
5488		this.opts = options;
5489		this.rootId = ''; // internal
5490		this.$subArrow = null;
5491		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)
5492		this.activatedItems = []; // stores last activated A's for each level
5493		this.visibleSubMenus = []; // stores visible sub menus UL's
5494		this.showTimeout = 0;
5495		this.hideTimeout = 0;
5496		this.scrollTimeout = 0;
5497		this.clickActivated = false;
5498		this.zIndexInc = 0;
5499		this.$firstLink = null; // we'll use these for some tests
5500		this.$firstSub = null; // at runtime so we'll cache them
5501		this.disabled = false;
5502		this.$disableOverlay = null;
5503		this.init();
5504	};
5505
5506	$.extend($.SmartMenus, {
5507		hideAll: function() {
5508			$.each(menuTrees, function() {
5509				this.menuHideAll();
5510			});
5511		},
5512		destroy: function() {
5513			while (menuTrees.length) {
5514				menuTrees[0].destroy();
5515			}
5516			initMouseDetection(true);
5517		},
5518		prototype: {
5519			init: function(refresh) {
5520				var self = this;
5521
5522				if (!refresh) {
5523					menuTrees.push(this);
5524
5525					this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, '');
5526
5527					if (this.$root.hasClass('sm-rtl')) {
5528						this.opts.rightToLeftSubMenus = true;
5529					}
5530
5531					// init root (main menu)
5532					this.$root
5533						.data('smartmenus', this)
5534						.attr('data-smartmenus-id', this.rootId)
5535						.dataSM('level', 1)
5536						.bind({
5537							'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
5538							'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this)
5539						})
5540						.delegate('a', {
5541							'mouseenter.smartmenus': $.proxy(this.itemEnter, this),
5542							'mouseleave.smartmenus': $.proxy(this.itemLeave, this),
5543							'mousedown.smartmenus': $.proxy(this.itemDown, this),
5544							'focus.smartmenus': $.proxy(this.itemFocus, this),
5545							'blur.smartmenus': $.proxy(this.itemBlur, this),
5546							'click.smartmenus': $.proxy(this.itemClick, this),
5547							'touchend.smartmenus': $.proxy(this.itemTouchEnd, this)
5548						});
5549
5550					var eNamespace = '.smartmenus' + this.rootId;
5551					// hide menus on tap or click outside the root UL
5552					if (this.opts.hideOnClick) {
5553						$(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this))
5554							.bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this))
5555							.bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this))
5556							// for Opera Mobile < 11.5, webOS browser, etc. we'll check click too
5557							.bind('click' + eNamespace, $.proxy(this.docClick, this));
5558					}
5559					// hide sub menus on resize
5560					$(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
5561					$(window).bind('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
5562
5563					if (this.opts.subIndicators) {
5564						this.$subArrow = $('<span/>').addClass('sub-arrow');
5565						if (this.opts.subIndicatorsText) {
5566							this.$subArrow.html(this.opts.subIndicatorsText);
5567						}
5568					}
5569
5570					// make sure mouse detection is enabled
5571					initMouseDetection();
5572				}
5573
5574				// init sub menus
5575				this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0);
5576
5577				this.$firstLink = this.$root.find('a').eq(0);
5578
5579				// find current item
5580				if (this.opts.markCurrentItem) {
5581					var reDefaultDoc = /(index|default)\.[^#\?\/]*/i,
5582						reHash = /#.*/,
5583						locHref = window.location.href.replace(reDefaultDoc, ''),
5584						locHrefNoHash = locHref.replace(reHash, '');
5585					this.$root.find('a').each(function() {
5586						var href = this.href.replace(reDefaultDoc, ''),
5587							$this = $(this);
5588						if (href == locHref || href == locHrefNoHash) {
5589							$this.addClass('current');
5590							if (self.opts.markCurrentTree) {
5591								$this.parents('li').each(function() {
5592									var $this = $(this);
5593									if ($this.dataSM('sub')) {
5594										$this.children('a').addClass('current');
5595									}
5596								});
5597							}
5598						}
5599					});
5600				}
5601			},
5602			destroy: function() {
5603				this.menuHideAll();
5604				this.$root
5605					.removeData('smartmenus')
5606					.removeAttr('data-smartmenus-id')
5607					.removeDataSM('level')
5608					.unbind('.smartmenus')
5609					.undelegate('.smartmenus');
5610				var eNamespace = '.smartmenus' + this.rootId;
5611				$(document).unbind(eNamespace);
5612				$(window).unbind(eNamespace);
5613				if (this.opts.subIndicators) {
5614					this.$subArrow = null;
5615				}
5616				var self = this;
5617				$.each(this.subMenus, function() {
5618					if (this.hasClass('mega-menu')) {
5619						this.find('ul').removeDataSM('in-mega');
5620					}
5621					if (this.dataSM('shown-before')) {
5622						if (IElt8) {
5623							this.children().css({ styleFloat: '', width: '' });
5624						}
5625						if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) {
5626							if (!IE6) {
5627								this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap');
5628							} else {
5629								this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', '');
5630							}
5631						}
5632						if (this.dataSM('scroll-arrows')) {
5633							this.dataSM('scroll-arrows').remove();
5634						}
5635						this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' });
5636					}
5637					if (self.opts.subIndicators) {
5638						this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove();
5639					}
5640					this.removeDataSM('shown-before')
5641						.removeDataSM('ie-shim')
5642						.removeDataSM('scroll-arrows')
5643						.removeDataSM('parent-a')
5644						.removeDataSM('level')
5645						.removeDataSM('beforefirstshowfired')
5646						.parent().removeDataSM('sub');
5647				});
5648				if (this.opts.markCurrentItem) {
5649					this.$root.find('a.current').removeClass('current');
5650				}
5651				this.$root = null;
5652				this.$firstLink = null;
5653				this.$firstSub = null;
5654				if (this.$disableOverlay) {
5655					this.$disableOverlay.remove();
5656					this.$disableOverlay = null;
5657				}
5658				menuTrees.splice($.inArray(this, menuTrees), 1);
5659			},
5660			disable: function(noOverlay) {
5661				if (!this.disabled) {
5662					this.menuHideAll();
5663					// display overlay over the menu to prevent interaction
5664					if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) {
5665						var pos = this.$root.offset();
5666						this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({
5667							position: 'absolute',
5668							top: pos.top,
5669							left: pos.left,
5670							width: this.$root.outerWidth(),
5671							height: this.$root.outerHeight(),
5672							zIndex: this.getStartZIndex() + 1,
5673							opacity: 0
5674						}).appendTo(document.body);
5675					}
5676					this.disabled = true;
5677				}
5678			},
5679			docClick: function(e) {
5680				// hide on any click outside the menu or on a menu link
5681				if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) {
5682					this.menuHideAll($(e.target));
5683				}
5684			},
5685			docTouchEnd: function(e) {
5686				if (!this.lastTouch) {
5687					return;
5688				}
5689				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))) {
5690					if (this.hideTimeout) {
5691						clearTimeout(this.hideTimeout);
5692						this.hideTimeout = 0;
5693					}
5694					// hide with a delay to prevent triggering accidental unwanted click on some page element
5695					var self = this;
5696					this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350);
5697				}
5698				this.lastTouch = null;
5699			},
5700			docTouchMove: function(e) {
5701				if (!this.lastTouch) {
5702					return;
5703				}
5704				var touchPoint = e.originalEvent.touches[0];
5705				this.lastTouch.x2 = touchPoint.pageX;
5706				this.lastTouch.y2 = touchPoint.pageY;
5707			},
5708			docTouchStart: function(e) {
5709				var touchPoint = e.originalEvent.touches[0];
5710				this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target };
5711			},
5712			enable: function() {
5713				if (this.disabled) {
5714					if (this.$disableOverlay) {
5715						this.$disableOverlay.remove();
5716						this.$disableOverlay = null;
5717					}
5718					this.disabled = false;
5719				}
5720			},
5721			getHeight: function($elm) {
5722				return this.getOffset($elm, true);
5723			},
5724			// returns precise width/height float values in IE9+, FF4+, recent WebKit
5725			// http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
5726			getOffset: function($elm, height) {
5727				var old;
5728				if ($elm.css('display') == 'none') {
5729					old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility };
5730					$elm.css({ position: 'absolute', visibility: 'hidden' }).show();
5731				}
5732				var defaultView = $elm[0].ownerDocument.defaultView,
5733					compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null),
5734					val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']);
5735				if (val) {
5736					val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft'])
5737						+ parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight'])
5738						+ parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth'])
5739						+ parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']);
5740				} else {
5741					val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth;
5742				}
5743				if (old) {
5744					$elm.hide().css(old);
5745				}
5746				return val;
5747			},
5748			getWidth: function($elm) {
5749				return this.getOffset($elm);
5750			},
5751			getStartZIndex: function() {
5752				var zIndex = parseInt(this.$root.css('z-index'));
5753				return !isNaN(zIndex) ? zIndex : 1;
5754			},
5755			handleEvents: function() {
5756				return !this.disabled && this.isCSSOn();
5757			},
5758			handleItemEvents: function($a) {
5759				return this.handleEvents() && !this.isLinkInMegaMenu($a);
5760			},
5761			isCollapsible: function() {
5762				return this.$firstSub.css('position') == 'static';
5763			},
5764			isCSSOn: function() {
5765				return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'inline';
5766			},
5767			isFixed: function() {
5768				return this.$root.css('position') == 'fixed';
5769			},
5770			isLinkInMegaMenu: function($a) {
5771				return !$a.parent().parent().dataSM('level');
5772			},
5773			isTouchMode: function() {
5774				return !mouse || this.isCollapsible();
5775			},
5776			itemActivate: function($a) {
5777				var $li = $a.parent(),
5778					$ul = $li.parent(),
5779					level = $ul.dataSM('level');
5780				// 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
5781				if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) {
5782					var self = this;
5783					$($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() {
5784						self.itemActivate($(this).dataSM('parent-a'));
5785					});
5786				}
5787				// hide any visible deeper level sub menus
5788				if (this.visibleSubMenus.length > level) {
5789					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--) {
5790						this.menuHide(this.visibleSubMenus[i]);
5791					}
5792				}
5793				// save new active item and sub menu for this level
5794				this.activatedItems[level - 1] = $a;
5795				this.visibleSubMenus[level - 1] = $ul;
5796				if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) {
5797					return;
5798				}
5799				// show the sub menu if this item has one
5800				var $sub = $li.dataSM('sub');
5801				if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) {
5802					this.menuShow($sub);
5803				}
5804			},
5805			itemBlur: function(e) {
5806				var $a = $(e.currentTarget);
5807				if (!this.handleItemEvents($a)) {
5808					return;
5809				}
5810				this.$root.triggerHandler('blur.smapi', $a[0]);
5811			},
5812			itemClick: function(e) {
5813				var $a = $(e.currentTarget);
5814
5815				if (!this.handleItemEvents($a)) {
5816					return;
5817				}
5818				$a.removeDataSM('mousedown');
5819				if (this.$root.triggerHandler('click.smapi', $a[0]) === false) {
5820					return false;
5821				}
5822				var $sub = $a.parent().dataSM('sub');
5823				if (this.isTouchMode()) {
5824					// undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu
5825					if ($a.dataSM('href')) {
5826						$a.attr('href', $a.dataSM('href')).removeDataSM('href');
5827					}
5828					// if the sub is not visible
5829					if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
5830						// try to activate the item and show the sub
5831						this.itemActivate($a);
5832						// if "itemActivate" showed the sub, prevent the click so that the link is not loaded
5833						// 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
5834						if ($sub.is(':visible')) {
5835							return false;
5836						}
5837					}
5838				} else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) {
5839					this.clickActivated = true;
5840					this.menuShow($sub);
5841					return false;
5842				}
5843				if ($a.hasClass('disabled')) {
5844					return false;
5845				}
5846				if (this.$root.triggerHandler('select.smapi', $a[0]) === false) {
5847					return false;
5848				}
5849			},
5850			itemDown: function(e) {
5851				var $a = $(e.currentTarget);
5852				if (!this.handleItemEvents($a)) {
5853					return;
5854				}
5855				$a.dataSM('mousedown', true);
5856			},
5857			itemEnter: function(e) {
5858				var $a = $(e.currentTarget);
5859				if (!this.handleItemEvents($a)) {
5860					return;
5861				}
5862				if (!this.isTouchMode()) {
5863					if (this.showTimeout) {
5864						clearTimeout(this.showTimeout);
5865						this.showTimeout = 0;
5866					}
5867					var self = this;
5868					this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout);
5869				}
5870				this.$root.triggerHandler('mouseenter.smapi', $a[0]);
5871			},
5872			itemFocus: function(e) {
5873				var $a = $(e.currentTarget);
5874				if (!this.handleItemEvents($a)) {
5875					return;
5876				}
5877				// 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
5878				if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) {
5879					this.itemActivate($a);
5880				}
5881				this.$root.triggerHandler('focus.smapi', $a[0]);
5882			},
5883			itemLeave: function(e) {
5884				var $a = $(e.currentTarget);
5885				if (!this.handleItemEvents($a)) {
5886					return;
5887				}
5888				if (!this.isTouchMode()) {
5889					if ($a[0].blur) {
5890						$a[0].blur();
5891					}
5892					if (this.showTimeout) {
5893						clearTimeout(this.showTimeout);
5894						this.showTimeout = 0;
5895					}
5896				}
5897				$a.removeDataSM('mousedown');
5898				this.$root.triggerHandler('mouseleave.smapi', $a[0]);
5899			},
5900			itemTouchEnd: function(e) {
5901				var $a = $(e.currentTarget);
5902				if (!this.handleItemEvents($a)) {
5903					return;
5904				}
5905				// prevent the address bar on iPhone from sliding down when expanding a sub menu
5906				var $sub = $a.parent().dataSM('sub');
5907				if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
5908					$a.dataSM('href', $a.attr('href'));
5909					$a.attr('href', '#');
5910				}
5911			},
5912			menuFixLayout: function($ul) {
5913				// fixes a menu that is being shown for the first time
5914				if (!$ul.dataSM('shown-before')) {
5915					$ul.hide().dataSM('shown-before', true);
5916					// fix the layout of the items in IE<8
5917					if (IElt8) {
5918						$ul.children().css({ styleFloat: 'left', width: '100%' });
5919					}
5920				}
5921			},
5922			menuHide: function($sub) {
5923				if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) {
5924					return;
5925				}
5926				$sub.stop(true, true);
5927				if ($sub.is(':visible')) {
5928					var complete = function() {
5929						// unset z-index
5930						if (IElt9) {
5931							$sub.parent().css('z-index', '');
5932						} else {
5933							$sub.css('z-index', '');
5934						}
5935					};
5936					// if sub is collapsible (mobile view)
5937					if (this.isCollapsible()) {
5938						if (this.opts.collapsibleHideFunction) {
5939							this.opts.collapsibleHideFunction.call(this, $sub, complete);
5940						} else {
5941							$sub.hide(this.opts.collapsibleHideDuration, complete);
5942						}
5943					} else {
5944						if (this.opts.hideFunction) {
5945							this.opts.hideFunction.call(this, $sub, complete);
5946						} else {
5947							$sub.hide(this.opts.hideDuration, complete);
5948						}
5949					}
5950					// remove IE iframe shim
5951					if ($sub.dataSM('ie-shim')) {
5952						$sub.dataSM('ie-shim').remove();
5953					}
5954					// deactivate scrolling if it is activated for this sub
5955					if ($sub.dataSM('scroll')) {
5956						$sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide();
5957					}
5958					// unhighlight parent item
5959					$sub.dataSM('parent-a').removeClass('highlighted');
5960					var level = $sub.dataSM('level');
5961					this.activatedItems.splice(level - 1, 1);
5962					this.visibleSubMenus.splice(level - 1, 1);
5963					this.$root.triggerHandler('hide.smapi', $sub[0]);
5964				}
5965			},
5966			menuHideAll: function($item) {
5967				if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return;
5968				if (this.showTimeout) {
5969					clearTimeout(this.showTimeout);
5970					this.showTimeout = 0;
5971				}
5972				// hide all subs
5973				for (var i = this.visibleSubMenus.length - 1; i > 0; i--) {
5974					this.menuHide(this.visibleSubMenus[i]);
5975				}
5976				// hide root if it's popup
5977				if (this.opts.isPopup) {
5978					this.$root.stop(true, true);
5979					if (this.$root.is(':visible')) {
5980						if (this.opts.hideFunction) {
5981							this.opts.hideFunction.call(this, this.$root);
5982						} else {
5983							this.$root.hide(this.opts.hideDuration);
5984						}
5985						// remove IE iframe shim
5986						if (this.$root.dataSM('ie-shim')) {
5987							this.$root.dataSM('ie-shim').remove();
5988						}
5989					}
5990				}
5991				this.activatedItems = [];
5992				this.visibleSubMenus = [];
5993				this.clickActivated = false;
5994				// reset z-index increment
5995				this.zIndexInc = 0;
5996			},
5997			menuIframeShim: function($ul) {
5998				// create iframe shim for the menu
5999				if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
6000					$ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
6001						.css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
6002					);
6003				}
6004			},
6005			menuInit: function($ul) {
6006				if (!$ul.dataSM('in-mega')) {
6007					this.subMenus.push($ul);
6008					// mark UL's in mega drop downs (if any) so we can neglect them
6009					if ($ul.hasClass('mega-menu')) {
6010						$ul.find('ul').dataSM('in-mega', true);
6011					}
6012					// get level (much faster than, for example, using parentsUntil)
6013					var level = 2,
6014						par = $ul[0];
6015					while ((par = par.parentNode.parentNode) != this.$root[0]) {
6016						level++;
6017					}
6018					// cache stuff
6019					$ul.dataSM('parent-a', $ul.prevAll('a').eq(-1))
6020						.dataSM('level', level)
6021						.parent().dataSM('sub', $ul);
6022					// add sub indicator to parent item
6023					if (this.opts.subIndicators) {
6024						$ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone());
6025					}
6026				}
6027			},
6028			menuPosition: function($sub) {
6029				var fixIE = $('html.ie').length;
6030				// if (fixIE) {
6031				// 	var $rowParent = $($sub).closest('.main-menu-container');
6032				// 	$rowParent.height($rowParent.height());
6033				// }
6034				var $a = $sub.dataSM('parent-a'),
6035					$li = $sub.parent(),
6036					$ul = $sub.parent().parent(),
6037					$container = $ul.closest('.row-menu-inner'),
6038					level = $sub.dataSM('level'),
6039					subW = this.getWidth($sub),
6040					subH = this.getHeight($sub),
6041					itemOffset = $a.offset(),
6042					itemX = itemOffset.left,
6043					itemY = itemOffset.top,
6044					itemW = this.getWidth($a),
6045					itemH = this.getHeight($a),
6046					$win = $(window),
6047					winX = $win.scrollLeft(),
6048					winY = $win.scrollTop(),
6049					winW = $win.width(),
6050					winH = $win.height(),
6051					containerW = $container.width(),
6052					containerOffsetX = containerW + ((winW - containerW) / 2),
6053					horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'),
6054					subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
6055					subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
6056					x, y, leftPos;
6057				if (horizontalParent) {
6058					x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX;
6059					y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
6060				} else {
6061					x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX;
6062					y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
6063				}
6064				if (this.opts.keepInViewport && !this.isCollapsible()) {
6065					if (this.isFixed()) {
6066						itemX -= winX;
6067						itemY -= winY;
6068						winX = winY = 0;
6069					}
6070					var absX = itemX + x,
6071						absY = itemY + y;
6072					if (this.opts.rightToLeftSubMenus && absX < winX) {
6073						x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
6074					} else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) {
6075						x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW;
6076					}
6077					if (!horizontalParent) {
6078						if (subH < winH && absY + subH > winY + winH) {
6079							y += winY + winH - subH - absY;
6080						} else if (subH >= winH || absY < winY) {
6081							y += winY - absY;
6082						}
6083					}
6084					// do we need scrolling?
6085					// 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH"
6086					if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) {
6087						var self = this;
6088						if (!$sub.dataSM('scroll-arrows')) {
6089							$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]])
6090								.bind({
6091									mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); },
6092									mouseleave: function(e) {
6093										self.menuScrollStop($sub);
6094										self.menuScrollOut($sub, e);
6095									},
6096									'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
6097								})
6098								.insertAfter($sub)
6099							);
6100						}
6101						// bind events to show/hide arrows on hover and save scrolling data for this sub
6102						var vportY = winY - (itemY + itemH);
6103						$sub.dataSM('scroll', {
6104								vportY: vportY,
6105								subH: subH,
6106								winH: winH,
6107								step: 1
6108							})
6109							.bind({
6110								'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); },
6111								'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); },
6112								'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); }
6113							})
6114							.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
6114StartZIndex() + this.zIndexInc })
6115							.eq(0).css('margin-top', vportY).end()
6116							.eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end()
6117							.eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
6118					}
6119				}
6120				// if ($sub.hasClass('mega-menu-inner')) {
6121				// 	if ($('.menu-wrapper .megamenu-diff').length > 0) {
6122				// 		leftPos = parseFloat($('.menu-wrapper .megamenu-diff').outerWidth());
6123				// 		leftPos = -leftPos;
6124				// 	} else leftPos = parseFloat($('.menu-wrapper .main-menu-container').css('paddingLeft'));
6125
6126				// 	if ($('body.header-full-width').length > 0) {
6127				// 		$sub.css({ width: $('.box-container').width()});
6128				// 		leftPos = (leftPos - parseFloat($('.menu-wrapper .row-menu-inner').css('paddingLeft')));
6129				// 	} else $sub.css({ width: containerW});
6130				// 	leftPos = leftPos + 'px';
6131
6132				// } else {
6133				// 	leftPos = $li.position().left + 'px';
6134				// }
6135				if ($sub.hasClass('mega-menu-inner')) {
6136					$sub.css({ width: containerW});
6137					if ($('body.hmenu-center-split').length > 0 && !$sub.closest('.navbar-cta').length ) {
6138						leftPos = - ($sub.closest('.menu-primary-inner')[0].offsetLeft) + 'px';
6139					} else {
6140						if ( $sub.closest('.navbar-cta').length && !$('body.hmenu').length && !$('body.hmenu-center').length ) {
6141							leftPos = - ( parseFloat($sub.closest('.navbar-cta').offset().left) - parseFloat($sub.closest('.row-menu-inner').find('.logo-container').offset().left) ) + 'px';
6142						} else if ($sub.closest('.row-menu-inner').find('.logo-container').length > 0 && !$('body.hmenu-center-split').length) {
6143							leftPos = - (parseFloat($sub.closest('.row-menu-inner').find('.logo-container').css('paddingRight')) + ($sub.closest('.row-menu-inner').find('.logo-container').width())) + 'px';
6144						} else {
6145							leftPos = '0px';
6146						}
6147					}
6148				} else {
6149					leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px';
6150					x = (level > 2 && x >= 0) ? x + (parseFloat($li.closest('ul').css('paddingLeft')) * 2) + 1 : x - 1;
6151				}
6152
6153				$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) });
6154				// IE iframe shim
6155				this.menuIframeShim($sub);
6156				if ($sub.dataSM('ie-shim')) {
6157					$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) });
6158				}
6159			},
6160			menuScroll: function($sub, up, wheel) {
6161				var y = parseFloat($sub.css('margin-top')),
6162					scroll = $sub.dataSM('scroll'),
6163					end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH),
6164					step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
6165				$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
6166				y = parseFloat($sub.css('margin-top'));
6167				// show opposite arrow if appropriate
6168				if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
6169					$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
6170				}
6171				// accelerate when not using mousewheel to scroll
6172				if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
6173					$sub.dataSM('scroll').step += 0.5;
6174				}
6175				// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
6176				if (Math.abs(y - end) < 1) {
6177					$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
6178					$sub.dataSM('scroll').step = 1;
6179				} else if (!wheel) {
6180					var self = this;
6181					this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
6182				}
6183			},
6184			menuScrollMousewheel: function($sub, e) {
6185				var $closestSub = $(e.target).closest('ul');
6186				while ($closestSub.dataSM('in-mega')) {
6187					$closestSub = $closestSub.parent().closest('ul');
6188				}
6189				if ($closestSub[0] == $sub[0]) {
6190					var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
6191					if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
6192						this.menuScroll($sub, up, true);
6193					}
6194				}
6195				e.preventDefault();
6196			},
6197			menuScrollOut: function($sub, e) {
6198				var reClass = /^scroll-(up|down)/,
6199					$closestSub = $(e.relatedTarget).closest('ul');
6200				while ($closestSub.dataSM('in-mega')) {
6201					$closestSub = $closestSub.parent().closest('ul');
6202				}
6203				if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
6204					$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
6205				}
6206			},
6207			menuScrollOver: function($sub, e) {
6208				var reClass = /^scroll-(up|down)/,
6209					$closestSub = $(e.target).closest('ul');
6210				while ($closestSub.dataSM('in-mega')) {
6211					$closestSub = $closestSub.parent().closest('ul');
6212				}
6213				if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
6214					$sub.dataSM('scroll-arrows').css('visibility', 'visible');
6215				}
6216			},
6217			menuScrollStop: function($sub) {
6218				if (this.scrollTimeout) {
6219					clearTimeout(this.scrollTimeout);
6220					this.scrollTimeout = 0;
6221					$sub.dataSM('scroll').step = 1;
6222				}
6223			},
6224			menuShow: function($sub) {
6225				if (!$sub.dataSM('beforefirstshowfired')) {
6226					$sub.dataSM('beforefirstshowfired', true);
6227					if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
6228						return;
6229					}
6230				}
6231				if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
6232					return;
6233				}
6234				this.menuFixLayout($sub);
6235				$sub.stop(true, true);
6236				if (!$sub.is(':visible')) {
6237					// set z-index - for IE < 9 set it to the parent LI
6238					var zIndex = this.getStartZIndex() + (++this.zIndexInc);
6239					if (IElt9) {
6240						$sub.parent().css('z-index', zIndex);
6241					} else {
6242						$sub.css('z-index', zIndex);
6243					}
6244					// highlight parent item
6245					if (this.opts.keepHighlighted || this.isCollapsible()) {
6246						if ($sub.dataSM('parent-a').attr('data-type') != 'title')
6247							$sub.dataSM('parent-a').addClass('highlighted');
6248					}
6249					// min/max-width fix - no way to rely purely on CSS as all UL's are nested
6250					if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
6251						if (!IElt8) {
6252							$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
6253							if (this.opts.subMenusMinWidth) {
6254								$sub.css('min-width', this.opts.subMenusMinWidth);
6255							}
6256							if (this.opts.subMenusMaxWidth) {
6257								var noMaxWidth = this.getWidth($sub);
6258								$sub.css('max-width', this.opts.subMenusMaxWidth);
6259								if (noMaxWidth > this.getWidth($sub)) {
6260									$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
6261								}
6262							}
6263						// IE6,7
6264						} else {
6265							$sub.children().css('styleFloat', 'none');
6266							if (IE6) {
6267								$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
6268									.children().children('a').css('white-space', 'nowrap');
6269							} else { // IE7
6270								$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
6271								if (this.opts.subMenusMinWidth) {
6272									$sub.css('min-width', this.opts.subMenusMinWidth);
6273								}
6274							}
6275							if (this.opts.subMenusMaxWidth) {
6276								var noMaxWidth = $sub.width();
6277								if (IE6) {
6278									var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
6279									if (noMaxWidth > maxWidth) {
6280										$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
6281									} else {
6282										$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
6283									}
6284								} else { // IE7
6285									$sub.css('max-width', this.opts.subMenusMaxWidth);
6286									if (noMaxWidth > $sub.width()) {
6287										$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
6288									} else {
6289										$sub.width(noMaxWidth);
6290									}
6291								}
6292							} else {
6293								$sub.width($sub.width());
6294							}
6295							$sub.children().css('styleFloat', 'left');
6296						}
6297					}
6298					this.menuPosition($sub);
6299					// insert IE iframe shim
6300					if ($sub.dataSM('ie-shim')) {
6301						$sub.dataSM('ie-shim').insertBefore($sub);
6302					}
6303					var complete = function() {
6304						// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
6305						$sub.css('overflow', '');
6306					};
6307					// if sub is collapsible (mobile view)
6308					if (this.isCollapsible()) {
6309						if (this.opts.collapsibleShowFunction) {
6310							this.opts.collapsibleShowFunction.call(this, $sub, complete);
6311						} else {
6312							$sub.show(this.opts.collapsibleShowDuration, complete);
6313						}
6314					} else {
6315						if (this.opts.showFunction) {
6316							this.opts.showFunction.call(this, $sub, complete);
6317						} else {
6318							$sub.show(this.opts.showDuration, complete);
6319						}
6320					}
6321					// save new sub menu for this level
6322					this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
6323					this.$root.triggerHandler('show.smapi', $sub[0]);
6324				}
6325			},
6326			popupHide: function(noHideTimeout) {
6327				if (this.hideTimeout) {
6328					clearTimeout(this.hideTimeout);
6329					this.hideTimeout = 0;
6330				}
6331				var self = this;
6332				this.hideTimeout = setTimeout(function() {
6333					self.menuHideAll();
6334				}, noHideTimeout ? 1 : this.opts.hideTimeout);
6335			},
6336			popupShow: function(left, top) {
6337				if (!this.opts.isPopup) {
6338					alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
6339					return;
6340				}
6341				if (this.hideTimeout) {
6342					clearTimeout(this.hideTimeout);
6343					this.hideTimeout = 0;
6344				}
6345				this.menuFixLayout(this.$root);
6346				this.$root.stop(true, true);
6347				if (!this.$root.is(':visible')) {
6348					this.$root.css({ left: left, top: top });
6349					// IE iframe shim
6350					this.menuIframeShim(this.$root);
6351					if (this.$root.dataSM('ie-shim')) {
6352						this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
6352: left, top: top }).insertBefore(this.$root);
6353					}
6354					// show menu
6355					if (this.opts.showFunction) {
6356						this.opts.showFunction.call(this, this.$root);
6357					} else {
6358						this.$root.show(this.opts.showDuration);
6359					}
6360					this.visibleSubMenus[0] = this.$root;
6361				}
6362			},
6363			refresh: function() {
6364				this.menuHideAll();
6365				this.$root.find('ul').each(function() {
6366						var $this = $(this);
6367						if ($this.dataSM('scroll-arrows')) {
6368							$this.dataSM('scroll-arrows').remove();
6369						}
6370					})
6371					.removeDataSM('in-mega')
6372					.removeDataSM('shown-before')
6373					.removeDataSM('ie-shim')
6374					.removeDataSM('scroll-arrows')
6375					.removeDataSM('parent-a')
6376					.removeDataSM('level')
6377					.removeDataSM('beforefirstshowfired');
6378				this.$root.find('a.has-submenu').removeClass('has-submenu')
6379					.parent().removeDataSM('sub');
6380				if (this.opts.subIndicators) {
6381					this.$root.find('span.sub-arrow').remove();
6382				}
6383				if (this.opts.markCurrentItem) {
6384					this.$root.find('a.current').removeClass('current');
6385				}
6386				this.subMenus = [];
6387				this.init(true);
6388			},
6389			rootOut: function(e) {
6390				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
6391					return;
6392				}
6393				if (this.hideTimeout) {
6394					clearTimeout(this.hideTimeout);
6395					this.hideTimeout = 0;
6396				}
6397				if (!this.opts.showOnClick || !this.opts.hideOnClick) {
6398					var self = this;
6399					this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
6400				}
6401			},
6402			rootOver: function(e) {
6403				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
6404					return;
6405				}
6406				if (this.hideTimeout) {
6407					clearTimeout(this.hideTimeout);
6408					this.hideTimeout = 0;
6409				}
6410			},
6411			winResize: function(e) {
6412				if (!this.handleEvents()) {
6413					// we still need to resize the disable overlay if it's visible
6414					if (this.$disableOverlay) {
6415						var pos = this.$root.offset();
6416						this.$disableOverlay.css({
6417							top: pos.top,
6418							left: pos.left,
6419							width: this.$root.outerWidth(),
6420							height: this.$root.outerHeight()
6421						});
6422					}
6423					return;
6424				}
6425				// hide sub menus on resize - on mobile do it only on orientation change
6426				if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
6427					if (this.activatedItems.length) {
6428						this.activatedItems[this.activatedItems.length - 1][0].blur();
6429					}
6430					this.menuHideAll();
6431				}
6432			}
6433		}
6434	});
6435
6436	$.fn.dataSM = function(key, val) {
6437		if (val) {
6438			return this.data(key + '_smartmenus', val);
6439		}
6440		return this.data(key + '_smartmenus');
6441	}
6442
6443	$.fn.removeDataSM = function(key) {
6444		return this.removeData(key + '_smartmenus');
6445	}
6446
6447	$.fn.smartmenus = function(options) {
6448		if (typeof options == 'string') {
6449			var args = arguments,
6450				method = options;
6451			Array.prototype.shift.call(args);
6452			return this.each(function() {
6453				var smartmenus = $(this).data('smartmenus');
6454				if (smartmenus && smartmenus[method]) {
6455					smartmenus[method].apply(smartmenus, args);
6456				}
6457			});
6458		}
6459		var opts = $.extend({}, $.fn.smartmenus.defaults, options);
6460		return this.each(function() {
6461			new $.SmartMenus(this, opts);
6462		});
6463	}
6464
6465	// default settings
6466	$.fn.smartmenus.defaults = {
6467		isPopup:		false,		// is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
6468		mainMenuSubOffsetX:	0,		// pixels offset from default position
6469		mainMenuSubOffsetY:	0,		// pixels offset from default position
6470		subMenusSubOffsetX:	0,		// pixels offset from default position
6471		subMenusSubOffsetY:	0,		// pixels offset from default position
6472		subMenusMinWidth:	'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
6473		subMenusMaxWidth:	'20em',		// max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
6474		subIndicators: 		true,		// create sub menu indicators - creates a SPAN and inserts it in the A
6475		subIndicatorsPos: 	'prepend',	// position of the SPAN relative to the menu item content ('prepend', 'append')
6476		subIndicatorsText:	'+',		// [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
6477		scrollStep: 		30,		// pixels step when scrolling long sub menus that do not fit in the viewport height
6478		scrollInterval:		30,		// interval between each scrolling step
6479		scrollAccelerate:	true,		// accelerate scrolling or use a fixed step
6480		showTimeout:		250,		// timeout before showing the sub menus
6481		hideTimeout:		500,		// timeout before hiding the sub menus
6482		showDuration:		0,		// duration for show animation - set to 0 for no animation - matters only if showFunction:null
6483		showFunction:		null,		// custom function to use when showing a sub menu (the default is the jQuery 'show')
6484							// don't forget to call complete() at the end of whatever you do
6485							// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
6486		hideDuration:		0,		// duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
6487		hideFunction:		function($ul, complete) { $ul.fadeOut(200, complete); },	// custom function to use when hiding a sub menu (the default is the jQuery 'hide')
6488							// don't forget to call complete() at the end of whatever you do
6489							// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
6490		collapsibleShowDuration:0,		// duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
6491		collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); },	// custom function to use when showing a collapsible sub menu
6492							// (i.e. when mobile styles are used to make the sub menus collapsible)
6493		collapsibleHideDuration:0,		// duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
6494		collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); },	// custom function to use when hiding a collapsible sub menu
6495							// (i.e. when mobile styles are used to make the sub menus collapsible)
6496		showOnClick:		false,		// show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
6497		hideOnClick:		true,		// hide the sub menus on click/tap anywhere on the page
6498		keepInViewport:		true,		// reposition the sub menus if needed to make sure they always appear inside the viewport
6499		keepHighlighted:	true,		// keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
6500		markCurrentItem:	false,		// automatically add the 'current' class to the A element of the item linking to the current URL
6501		markCurrentTree:	true,		// add the 'current' class also to the A elements of all ancestor items of the current item
6502		rightToLeftSubMenus:	false,		// right to left display of the sub menus (check the CSS for the sub indicators' position)
6503		bottomToTopSubMenus:	false,		// bottom to top display of the sub menus
6504		overlapControlsInIE:	true		// make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
6505	};
6506
6507})(jQuery);
6508
6509/*
6510 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
6511 *
6512 * Uses the built in easing capabilities added In jQuery 1.1
6513 * to offer multiple easing options
6514 *
6515 * TERMS OF USE - jQuery Easing
6516 *
6517 * Open source under the BSD License.
6518 *
6519 * Copyright © 2008 George McGinley Smith
6520 * All rights reserved.
6521 *
6522 * Redistribution and use in source and binary forms, with or without modification,
6523 * are permitted provided that the following conditions are met:
6524 *
6525 * Redistributions of source code must retain the above copyright notice, this list of
6526 * conditions and the following disclaimer.
6527 * Redistributions in binary form must reproduce the above copyright notice, this list
6528 * of conditions and the following disclaimer in the documentation and/or other materials
6529 * provided with the distribution.
6530 *
6531 * Neither the name of the author nor the names of contributors may be used to endorse
6532 * or promote products derived from this software without specific prior written permission.
6533 *
6534 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
6535 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
6536 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
6537 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
vendor: 5,087 bytes, lines 6538-6683
6538 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
6539 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
6540 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6541 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
6542 * OF THE POSSIBILITY OF SUCH DAMAGE.
6543 *
6544*/
6545
6546// t: current time, b: begInnIng value, c: change In value, d: duration
6547jQuery.easing['jswing'] = jQuery.easing['swing'];
6548
6549jQuery.extend( jQuery.easing,
6550{
6551	def: 'easeOutQuad',
6552	swing: function (x, t, b, c, d) {
6553		//alert(jQuery.easing.default);
6554		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
6555	},
6556	easeInQuad: function (x, t, b, c, d) {
6557		return c*(t/=d)*t + b;
6558	},
6559	easeOutQuad: function (x, t, b, c, d) {
6560		return -c *(t/=d)*(t-2) + b;
6561	},
6562	easeInOutQuad: function (x, t, b, c, d) {
6563		if ((t/=d/2) < 1) return c/2*t*t + b;
6564		return -c/2 * ((--t)*(t-2) - 1) + b;
6565	},
6566	easeInCubic: function (x, t, b, c, d) {
6567		return c*(t/=d)*t*t + b;
6568	},
6569	easeOutCubic: function (x, t, b, c, d) {
6570		return c*((t=t/d-1)*t*t + 1) + b;
6571	},
6572	easeInOutCubic: function (x, t, b, c, d) {
6573		if ((t/=d/2) < 1) return c/2*t*t*t + b;
6574		return c/2*((t-=2)*t*t + 2) + b;
6575	},
6576	easeInQuart: function (x, t, b, c, d) {
6577		return c*(t/=d)*t*t*t + b;
6578	},
6579	easeOutQuart: function (x, t, b, c, d) {
6580		return -c * ((t=t/d-1)*t*t*t - 1) + b;
6581	},
6582	easeInOutQuart: function (x, t, b, c, d) {
6583		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
6584		return -c/2 * ((t-=2)*t*t*t - 2) + b;
6585	},
6586	easeInQuint: function (x, t, b, c, d) {
6587		return c*(t/=d)*t*t*t*t + b;
6588	},
6589	easeOutQuint: function (x, t, b, c, d) {
6590		return c*((t=t/d-1)*t*t*t*t + 1) + b;
6591	},
6592	easeInOutQuint: function (x, t, b, c, d) {
6593		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
6594		return c/2*((t-=2)*t*t*t*t + 2) + b;
6595	},
6596	easeInSine: function (x, t, b, c, d) {
6597		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
6598	},
6599	easeOutSine: function (x, t, b, c, d) {
6600		return c * Math.sin(t/d * (Math.PI/2)) + b;
6601	},
6602	easeInOutSine: function (x, t, b, c, d) {
6603		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
6604	},
6605	easeInExpo: function (x, t, b, c, d) {
6606		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
6607	},
6608	easeOutExpo: function (x, t, b, c, d) {
6609		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
6610	},
6611	easeInOutExpo: function (x, t, b, c, d) {
6612		if (t==0) return b;
6613		if (t==d) return b+c;
6614		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
6615		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
6616	},
6617	easeInCirc: function (x, t, b, c, d) {
6618		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
6619	},
6620	easeOutCirc: function (x, t, b, c, d) {
6621		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
6622	},
6623	easeInOutCirc: function (x, t, b, c, d) {
6624		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
6625		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
6626	},
6627	easeInElastic: function (x, t, b, c, d) {
6628		var s=1.70158;var p=0;var a=c;
6629		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
6630		if (a < Math.abs(c)) { a=c; var s=p/4; }
6631		else var s = p/(2*Math.PI) * Math.asin (c/a);
6632		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
6633	},
6634	easeOutElastic: function (x, t, b, c, d) {
6635		var s=1.70158;var p=0;var a=c;
6636		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
6637		if (a < Math.abs(c)) { a=c; var s=p/4; }
6638		else var s = p/(2*Math.PI) * Math.asin (c/a);
6639		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
6640	},
6641	easeInOutElastic: function (x, t, b, c, d) {
6642		var s=1.70158;var p=0;var a=c;
6643		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
6644		if (a < Math.abs(c)) { a=c; var s=p/4; }
6645		else var s = p/(2*Math.PI) * Math.asin (c/a);
6646		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
6647		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
6648	},
6649	easeInBack: function (x, t, b, c, d, s) {
6650		if (s == undefined) s = 1.70158;
6651		return c*(t/=d)*t*((s+1)*t - s) + b;
6652	},
6653	easeOutBack: function (x, t, b, c, d, s) {
6654		if (s == undefined) s = 1.70158;
6655		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
6656	},
6657	easeInOutBack: function (x, t, b, c, d, s) {
6658		if (s == undefined) s = 1.70158;
6659		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
6660		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
6661	},
6662	easeInBounce: function (x, t, b, c, d) {
6663		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
6664	},
6665	easeOutBounce: function (x, t, b, c, d) {
6666		if ((t/=d) < (1/2.75)) {
6667			return c*(7.5625*t*t) + b;
6668		} else if (t < (2/2.75)) {
6669			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
6670		} else if (t < (2.5/2.75)) {
6671			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
6672		} else {
6673			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
6674		}
6675	},
6676	easeInOutBounce: function (x, t, b, c, d) {
6677		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
6678		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
6679	}
6680});
6681
6682/*
6683 *
6684 * TERMS OF USE - EASING EQUATIONS
6685 *
6686 * Open source under the BSD License.
6687 *
6688 * Copyright © 2001 Robert Penner
6689 * All rights reserved.
6690 *
6691 * Redistribution and use in source and binary forms, with or without modification,
6692 * are permitted provided that the following conditions are met:
6693 *
6694 * Redistributions of source code must retain the above copyright notice, this list of
6695 * conditions and the following disclaimer.
6696 * Redistributions in binary form must reproduce the above copyright notice, this list
6697 * of conditions and the following disclaimer in the documentation and/or other materials
6698 * provided with the distribution.
6699 *
6700 * Neither the name of the author nor the names of contributors may be used to endorse
6701 * or promote products derived from this software without specific prior written permission.
6702 *
6703 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
6704 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
6705 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
6706 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
6707 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
6708 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
6709 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6710 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
6711 * OF THE POSSIBILITY OF SUCH DAMAGE.
6712 *
6713 */
6714
6715(function($, window, undefined) {
6716		// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
6717		// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
6718
6719		// requestAnimationFrame polyfill by Erik Möller
6720		// fixes from Paul Irish and Tino Zijdel
6721
6722		var lastTime = 0,
6723				running,
6724				animate = function (elem) {
6725						if (running) {
6726								window.requestAnimationFrame(animate, elem);
6727								jQuery.fx.tick();
6728						}
6729				},
6730				vendors = ['ms', 'moz', 'webkit', 'o'];
6731
6732		for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
6733				window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
6734				window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
6735						|| window[vendors[x]+'CancelRequestAnimationFrame'];
6736		}
6737
6738		if (!window.requestAnimationFrame)
6739				window.requestAnimationFrame = function(fn, element) {
6740						var currTime = new Date().getTime(),
6741								delta = currTime - lastTime,
6742								timeToCall = Math.max(0, 16 - delta);
6743
6744						var id = window.setTimeout(function() {
6745										fn(currTime + timeToCall);
6746								},
6747								timeToCall
6748						);
6749
6750						lastTime = currTime + timeToCall;
6751
6752						return id;
6753				};
6754
6755		if (!window.cancelAnimationFrame) {
6756				window.cancelAnimationFrame = function(id) {
6757						clearTimeout(id);
6758				};
6759		}
6760
6761		jQuery.fx.timer = function (timer) {
6762				if (timer() && jQuery.timers.push(timer) && !running) {
6763						running = true;
6764						animate(timer.elem);
6765				}
6766		};
6767
6768		jQuery.fx.stop = function() {
6769				running = false;
6770		};
6771
6772}(jQuery, this));
6773
6774/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
6775 * Licensed under the MIT License (LICENSE.txt).
6776 *
6777 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
6778 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
6779 * Thanks to: Seamus Leahy for adding deltaX and deltaY
6780 *
6781 * Version: 3.0.6
6782 *
6783 * Requires: 1.2.2+
6784 */
6785(function($) {
6786		var types = ['DOMMouseScroll', 'mousewheel'];
6787		if ($.event.fixHooks) {
6788				for (var i = types.length; i;) {
6789						$.event.fixHooks[types[--i]] = $.event.mouseHooks;
6790				}
6791		}
6792		$.event.special.mousewheel = {
6793				setup: function() {
6794						if (this.addEventListener) {
6795								for (var i = types.length; i;) {
6796										this.addEventListener(types[--i], handler, false);
6797								}
6798						} else {
6799								this.onmousewheel = handler;
6800						}
6801				},
6802				teardown: function() {
6803						if (this.removeEventListener) {
6804								for (var i = types.length; i;) {
6805										this.removeEventListener(types[--i], handler, false);
6806								}
6807						} else {
6808								this.onmousewheel = null;
6809						}
6810				}
6811		};
6812		$.fn.extend({
6813				mousewheel: function(fn) {
6814						return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
6815				},
6816				unmousewheel: function(fn) {
6817						return this.unbind("mousewheel", fn);
6818				}
6819		});
6820
6821		function handler(event) {
6822				var orgEvent = event || window.event,
6823						args = [].slice.call(arguments, 1),
6824						delta = 0,
6825						returnValue = true,
6826						deltaX = 0,
6827						deltaY = 0;
6828				event = $.event.fix(orgEvent);
6829				event.type = "mousewheel";
6830				// Old school scrollwheel delta
6831				if (orgEvent.wheelDelta) {
6832						delta = orgEvent.wheelDelta / 120;
6833				}
6834				if (orgEvent.detail) {
6835						delta = -orgEvent.detail / 3;
6836				}
6837				// New school multidimensional scroll (touchpads) deltas
6838				deltaY = delta;
6839				// Gecko
6840				if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
6841						deltaY = 0;
6842						deltaX = -1 * delta;
6843				}
6844				// Webkit
6845				if (orgEvent.wheelDeltaY !== undefined) {
6846						deltaY = orgEvent.wheelDeltaY / 120;
6847				}
6848				if (orgEvent.wheelDeltaX !== undefined) {
6849						deltaX = -1 * orgEvent.wheelDeltaX / 120;
6850				}
6851				// Add event and delta to the front of the arguments
6852				args.unshift(event, delta, deltaX, deltaY);
6853				return ($.event.dispatch || $.event.handle).apply(this, args);
6854		}
6855})(jQuery);
6856
6857/**
6858 * jQuery iLightBox - Revolutionary Lightbox Plugin
6859 * http://www.ilightbox.net/
6860 *
6861 * @version: 2.2.4 - October 14, 2017
6862 *
6863 * @author: iProDev (Hemn Chawroka)
6864 *          http://www.iprodev.com/
6865 *
6866 */
6867(function($, window, undefined) {
6868
6869	var extensions = {
6870			flash: ['swf'],
6871			image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe'],
6872			iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'],
6873			video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v']
6874		},
6875
6876		// Global DOM elements
6877		$win = $(window),
6878		$doc = $(document),
6879
6880		// Support indicators
6881		browser,
6882		transform,
6883		gpuAcceleration,
6884		fullScreenApi = '',
6885		userAgent = navigator.userAgent || navigator.vendor || window.opera,
6886		supportTouch = !!('ontouchstart' in window) && (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)),
6887		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)),
6888
6889		// Events
6890		clickEvent = supportTouch ? "itap.iLightBox" : "click.iLightBox",
6891		touchStartEvent = supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox",
6892		touchStopEvent = supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox",
6893		touchMoveEvent = supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox",
6894
6895		// Math shorthands
6896		abs = Math.abs,
6897		sqrt = Math.sqrt,
6898		round = Math.round,
6899		max = Math.max,
6900		min = Math.min,
6901		floor = Math.floor,
6902		random = Math.random,
6903
6904		pluginspages = {
6905			quicktime: 'http://www.apple.com/quicktime/download',
6906			flash: 'http://www.adobe.com/go/getflash'
6907		},
6908
6909		iLightBox = function(el, options, items, instant) {
6910			var iL = this;
6911
6912			iL.options = options,
6913				iL.selector = el.selector || el,
6914				iL.context = el.context,
6915				iL.instant = instant;
6916
6917			if (items.length < 1) iL.attachItems();
6918			else iL.items = items;
6919
6920			iL.vars = {
6921				total: iL.items.length,
6922				start: 0,
6923				current: null,
6924				next: null,
6925				prev: null,
6926				BODY: $('body'),
6927				loadRequests: 0,
6928				overlay: $('<div class="ilightbox-overlay"></div>'),
6929				loader: $('<div class="ilightbox-loader"><div></div></div>'),
6930				toolbar: $('<div class="ilightbox-toolbar"></div>'),
6931				innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'),
6932				title: $('<div class="ilightbox-title"></div>'),
6933				closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'),
6934				fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'),
6935				innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'),
6936				innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'),
6937				innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'),
6938				holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6939				nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6940				prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
6941				nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'),
6942				prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
6943				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>'),
6944				thumbs: false,
6945				nextLock: false,
6946				prevLock: false,
6947				hashLock: false,
6948				isMobile: false,
6949				mobileMaxWidth: 980,
6950				isInFullScreen: false,
6951				isSwipe: false,
6952				mouseID: 0,
6953				cycleID: 0,
6954				isPaused: 0,
6955				captionHeight: 39,
6956			};
6957
6958			// Hideable elements with mousemove event
6959			iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton);
6960
6961			iL.normalizeItems();
6962
6963			//Check necessary plugins
6964			iL.availPlugins();
6965
6966			//Set startFrom
6967			iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom;
6968
6969			//If randomStart
6970			iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom;
6971			iL.vars.start = iL.options.startFrom;
6972
6973			if (instant) iL.instantCall();
6974			else iL.patchItemsEvents();
6975
6976			if (iL.options.linkId) {
6977				iL.hashChangeHandler();
6978				$win.iLightBoxHashChange(function() {
6979					iL.hashChangeHandler();
6980				});
6981			}
6982
6983			if (supportTouch) {
6984				var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig,
6985					replace = "itap";
6986				iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace),
6987					iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace),
6988					iL.options.social.show = iL.options.social.show.replace(RegExp, replace),
6989					iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace);
6990			}
6991
6992			if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) {
6993				$.extend(iL.options.styles, {
6994					nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
6995					prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
6996					nextOpacity: 0,
6997					prevOpacity: 0
6998				});
6999			}
7000		};
7001
7002	//iLightBox helpers
7003	iLightBox.prototype = {
7004		showLoader: function() {
7005			var iL = this;
7006			iL.vars.loadRequests += 1;
7007			if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({
7008				//top: '-30px'
7009				opacity: '1'
7010			}, iL.options.show.speed, 'easeOutCirc');
7011			else iL.vars.loader.addClass('ilightbox-show').stop().animate({
7012				//left: '-30px'
7013				opacity: '1'
7014			}, iL.options.show.speed, 'easeOutCirc');
7015		},
7016
7017		hideLoader: function() {
7018			var iL = this;
7019			iL.vars.loadRequests -= 1;
7020			iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests;
7021			if (iL.options.path.toLowerCase() == "horizontal") {
7022				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
7023					//top: '-192px'
7024					opacity: '0'
7025				}, iL.options.show.speed, 'easeInCirc');
7026			} else {
7027				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
7028					//left: '-192px'
7029					opacity: '0'
7030				}, iL.options.show.speed, 'easeInCirc');
7031			}
7032		},
7033
7034		createUI: function() {
7035			var iL = this;
7036
7037			iL.ui = {
7038				currentElement: iL.vars.holder,
7039				nextElement: iL.vars.nextPhoto,
7040				prevElement: iL.vars.prevPhoto,
7041				currentItem: iL.vars.current,
7042				nextItem: iL.vars.next,
7043				prevItem: iL.vars.prev,
7044				hide: function() {
7045					iL.closeAction();
7046				},
7047				refresh: function() {
7048					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
7049				},
7050				fullscreen: function() {
7051					iL.fullScreenAction();
7052				}
7053			};
7054		},
7055
7056		attachItems: function() {
7057			var iL = this,
7058				itemsObject = new Array(),
7059				items = new Array();
7060
7061			$(iL.selector, iL.context).each(function() {
7062				var t = $(this),
7063					URL = t.attr(iL.options.attr) || null,
7064					options = t.data("options") && eval("({" + t.data("options") + "})") || {},
7065					caption = t.data('caption'),
7066					title = t.data('title'),
7067					type = t.data('type') || getTypeByExtension(URL),
7068					clone = t.data('lbox-clone') || false;
7069
7070				if (t.data('lbox-clone') != undefined) return;
7071
7072				//Uncode addition ##START##
7073				if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) {
7074					var ALBUM_URLS = JSON.parse(t.attr('data-album')),
7075						URL_i,
7076						URLS_LENGHT = ALBUM_URLS.length;
7077					for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) {
7078						if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) {
7079							var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\'';
7080							item_opts = item_opts && eval("({" + item_opts + "})") || {},
7081							items.push({
7082								URL: ALBUM_URLS[URL_i].url,
7083								caption: ALBUM_URLS[URL_i].caption,
7084								title: ALBUM_URLS[URL_i].title,
7085								type: getTypeByExtension(ALBUM_URLS[URL_i].url),
7086								options: item_opts,
7087								clone: clone
7088							});
7089							var newT = t;
7090							newT.attr('href',ALBUM_URLS[URL_i].url);
7091							if (!iL.instant) itemsObject.push(newT);
7092						}
7093					}
7094				} else {
7095				//Uncode addition ##END##
7096					items.push({
7097						URL: URL,
7098						caption: caption,
7099						title: title,
7100						type: type,
7101						options: options,
7102						clone: clone
7103					});
7104				}
7105
7106
7107				if (iL.vars != undefined) iL.vars.total = items.length;
7108
7109				if (!iL.instant) itemsObject.push(t);
7110			});
7111
7112			iL.items = items,
7113				iL.itemsObject = itemsObject;
7114
7115		},
7116
7117		normalizeItems: function() {
7118			var iL = this,
7119				newItems = new Array();
7120
7121			$.each(iL.items, function(key, val) {
7122
7123				if (typeof val == "string") val = {
7124					url: val
7125				};
7126
7127				var URL = val.url || val.URL || null,
7128					options = val.options || {},
7129					caption = val.caption || null,
7130					title = val.title || null,
7131					type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL),
7132					ext = (typeof URL != 'object') ? getExtension(URL) : '';
7133
7134				options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
7135				options.videoType = options.videoType || null,
7136				options.skin = options.skin || iL.options.skin,
7137				options.width = options.width || null,
7138				options.height = options.height || null,
7139				options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true,
7140				options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true,
7141				options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons);
7142
7143				if (type == "video") {
7144					options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {};
7145
7146					options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null;
7147					options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls";
7148					options.html5video.preload = options.html5video.preload || "metadata";
7149					options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false;
7150				}
7151
7152				if (!options.width || !options.height) {
7153					if (type == "video") options.width = 1280, options.height = 720;
7154					else if (type == "iframe") options.width = '100%', options.height = '90%';
7155					else if (type == "flash") options.width = 1280, options.height = 720;
7156				}
7157
7158				delete val.url;
7159				val.index = key;
7160				val.URL = URL;
7161				val.caption = caption;
7162				val.title = title;
7163				val.type = type;
7164				val.options = options;
7165				val.ext = ext;
7166
7167				newItems.push(val);
7168			});
7169
7170			iL.items = newItems;
7171		},
7172
7173		instantCall: function() {
7174			var iL = this,
7175				key = iL.vars.start;
7176
7177			iL.vars.current = key;
7178			iL.vars.next = (iL.items[key + 1]) ? key + 1 : null;
7179			iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null;
7180
7181			iL.addContents();
7182			iL.patchEvents();
7183		},
7184
7185		addContents: function() {
7186			var iL = this,
7187				vars = iL.vars,
7188				opts = iL.options,
7189				viewport = getViewport(),
7190				path = opts.path.toLowerCase(),
7191				recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) {
7192					return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition);
7193				}),
7194				needRecognition = recognizingItems.length > 0;
7195
7196			if (opts.mobileOptimizer && !opts.innerToolbar)
7197				vars.isMobile = viewport.width <= vars.mobileMaxWidth;
7198
7199			vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity);
7200
7201			if (opts.linkId)
7202				vars.overlay[0].setAttribute('linkid', opts.linkId);
7203
7204			//Add Toolbar Buttons
7205			if (opts.controls.toolbar) {
7206				vars.toolbar.addClass(opts.skin).append(vars.closeButton);
7207				if (opts.controls.fullscreen)
7208					vars.toolbar.append(vars.fullScreenButton);
7209				if (opts.controls.slideshow)
7210					vars.toolbar.append(vars.innerPlayButton);
7211				if (vars.total > 1)
7212					vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton);
7213			}
7214
7215			//Append elements to body
7216			vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto);
7217
7218			if (!opts.innerToolbar)
7219				vars.BODY.append(vars.toolbar);
7220			if (opts.controls.arrows)
7221				vars.BODY.append(vars.nextButton).append(vars.prevButton);
7222
7223			if (opts.controls.thumbnail && vars.total > 1) {
7224				vars.BODY.append(vars.thumbnails);
7225				vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path);
7226				$('div.ilightbox-thumbnails-grid', vars.thumbnails).empty();
7227				vars.thumbs = true;
7228			}
7229
7230			//Configure loader and arrows
7231			var loaderCss = (opts.path.toLowerCase() == "horizontal") ? {
7232				left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2))
7233			} : {
7234				top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2))
7235			};
7236			vars.loader.addClass(opts.skin).css(loaderCss);
7237			vars.nextButton.add(vars.prevButton).addClass(opts.skin);
7238			if (path == "horizontal")
7239				vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal');
7240
7241			// Configure arrow buttons
7242			vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
7243
7244			if (!opts.infinite) {
7245				vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
7246
7247				if (vars.current == 0)
7248					vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
7249				if (vars.current >= vars.total - 1)
7250					vars.nextButton.add(vars.innerNextButton).addClass('disabled');
7251			}
7252
7253			if (opts.show.effect) {
7254				vars.overlay.stop().fadeIn(opts.show.speed);
7255				vars.toolbar.stop().fadeIn(opts.show.speed);
7256			} else {
7257				vars.overlay.show();
7258				vars.toolbar.show();
7259			}
7260
7261			var length = recognizingItems.length;
7262			if (needRecognition) {
7263				iL.showLoader();
7264
7265				$.each(recognizingItems, function(key, val) {
7266					var resultFnc = function(result) {
7267							var key = -1,
7268								filter = iL.items.filter(function(e, i, arr) {
7269									if (e.URL == result.url)
7270										key = i;
7271
7272									return e.URL == result.url;
7273								}),
7274								self = iL.items[key];
7275
7276							if (result)
7277								$.extend(true, self, {
7278									URL: result.source,
7279									type: result.type,
7280									recognized: true,
7281									options: {
7282										html5video: result.html5video,
7283										width: (result.type == "image") ? 0 : (result.width || self.width),
7284										height: (result.type == "image") ? 0 : (result.height || self.height),
7285										thumbnail: self.options.thumbnail || result.thumbnail
7286									}
7287								});
7288
7289							length--;
7290
7291							if (length == 0) {
7292								iL.hideLoader();
7293
7294								vars.dontGenerateThumbs = false;
7295								iL.generateThumbnails();
7296
7297								if (opts.show.effect)
7298									setTimeout(function() {
7299										iL.generateBoxes();
7300									}, opts.show.speed);
7301								else
7302									iL.generateBoxes();
7303							}
7304						};
7305
7306					iL.ogpRecognition(this, resultFnc);
7307				});
7308			}
7309			else {
7310				if (opts.show.effect)
7311					setTimeout(function() {
7312						iL.generateBoxes();
7313					}, opts.show.speed);
7314				else
7315					iL.generateBoxes();
7316			}
7317
7318			iL.createUI();
7319
7320			window.iLightBox = {
7321				close: function() {
7322					iL.closeAction();
7323				},
7324				fullscreen: function() {
7325					iL.fullScreenAction();
7326				},
7327				moveNext: function() {
7328					iL.moveTo('next');
7329				},
7330				movePrev: function() {
7331					iL.moveTo('prev');
7332				},
7333				goTo: function(index) {
7334					iL.goTo(index);
7335				},
7336				refresh: function() {
7337					iL.refresh();
7338				},
7339				reposition: function() {
7340					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
7341				},
7342				setOption: function(options) {
7343					iL.setOption(options);
7344				},
7345				destroy: function() {
7346					iL.closeAction();
7347					iL.dispatchItemsEvents();
7348				}
7349			};
7350
7351			if (opts.linkId) {
7352				vars.hashLock = true;
7353				window.location.hash = opts.linkId + '/' + vars.current;
7354				setTimeout(function() {
7355					vars.hashLock = false;
7356				}, 55);
7357			}
7358
7359			if (!opts.slideshow.startPaused) {
7360				iL.resume();
7361				vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause');
7362			}
7363
7364			//Trigger the onOpen callback
7365			if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL);
7366		},
7367
7368		loadContent: function(obj, opt, speed) {
7369			var iL = this,
7370				holder, item;
7371
7372			iL.createUI();
7373
7374			obj.speed = speed || iL.options.effects.loadedFadeSpeed;
7375
7376			if (opt == 'current') {
7377				if (!obj.options.mousewheel) iL.vars.lockWheel = true;
7378				else iL.vars.lockWheel = false;
7379
7380				if (!obj.options.swipe) iL.vars.lockSwipe = true;
7381				else iL.vars.lockSwipe = false;
7382			}
7383
7384			switch (opt) {
7385				case 'current':
7386					holder = iL.vars.holder, item = iL.vars.current;
7387					break;
7388				case 'next':
7389					holder = iL.vars.nextPhoto, item = iL.vars.next;
7390					break;
7391				case 'prev':
7392					holder = iL.vars.prevPhoto, item = iL.vars.prev;
7393					break;
7394			}
7395
7396			holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin);
7397			$('div.ilightbox-inner-toolbar', holder).remove();
7398
7399			if (obj.title || iL.options.innerToolbar) {
7400				var innerToolbar = iL.vars.innerToolbar.clone();
7401				if (obj.title && iL.options.show.title) {
7402					var title = iL.vars.title.clone();
7403					title.empty().html(obj.title);
7404					innerToolbar.append(title);
7405				}
7406				if (iL.options.innerToolbar) {
7407					innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar);
7408				}
7409				holder.prepend(innerToolbar);
7410			}
7411
7412			//console.warn('loadContent', arguments);
7413
7414			iL.loadSwitcher(obj, holder, item, opt);
7415		},
7416
7417		loadSwitcher: function(obj, holder, item, opt) {
7418			var iL = this,
7419				opts = iL.options,
7420				api = {
7421					element: holder,
7422					position: item
7423				};
7424
7425			switch (obj.type) {
7426				case 'image':
7427					//Trigger the onBeforeLoad callback
7428					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7429					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7430
7431					iL.loadImage(obj.URL, function(img) {
7432						//Trigger the onAfterLoad callback
7433						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7434						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7435
7436						var width = (img) ? img.width : 400,
7437							height = (img) ? img.height : 200;
7438
7439						holder.data({
7440							naturalWidth: width,
7441							naturalHeight: height
7442						});
7443						$('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>');
7444
7445						//Trigger the onRender callback
7446						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7447						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7448
7449						iL.configureHolder(obj, opt, holder);
7450					});
7451
7452					break;
7453
7454				case 'video':
7455					holder.data({
7456						naturalWidth: obj.options.width,
7457						naturalHeight: obj.options.height
7458					});
7459
7460					if (opt === 'current') {
7461						iL.addContent(holder, obj);
7462
7463						//Trigger the onRender callback
7464						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7465						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7466					} else {
7467						$('div.ilightbox-container', holder).empty();
7468					}
7469
7470					iL.configureHolder(obj, opt, holder);
7471
7472					break;
7473
7474				case 'iframe':
7475					//iL.showLoader();
7476					holder.data({
7477						naturalWidth: obj.options.width,
7478						naturalHeight: obj.options.height
7479					});
7480
7481					iL.configureHolder(obj, opt, holder);
7482
7483					if (opt === 'current') {
7484						var el = iL.addContent(holder, obj);
7485
7486						//Trigger the onRender callback
7487						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7488						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7489
7490						//Trigger the onBeforeLoad callback
7491						if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7492						if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7493
7494						el.bind('load', function() {
7495							//Trigger the onAfterLoad callback
7496							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7497							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7498
7499							//iL.hideLoader();
7500							el.unbind('load');
7501						});
7502					} else {
7503						$('div.ilightbox-container', holder).empty();
7504					}
7505
7506					break;
7507
7508				case 'inline':
7509					var el = $(obj.URL),
7510						content = iL.addContent(holder, obj),
7511						images = findImageInElement(holder);
7512
7513					holder.data({
7514						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
7515						naturalHeight: (iL.items[item].options.height || el.outerHeight())
7516					});
7517					content.children().eq(0).show();
7518
7519					//Trigger the onRender callback
7520					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7521					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7522
7523					//Trigger the onBeforeLoad callback
7524					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7525					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7526
7527					iL.loadImage(images, function() {
7528						//Trigger the onAfterLoad callback
7529						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7530						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7531
7532						iL.configureHolder(obj, opt, holder);
7533					});
7534
7535					break;
7536
7537				case 'flash':
7538					var el = iL.addContent(holder, obj);
7539
7540					holder.data({
7541						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
7542						naturalHeight: (iL.items[item].options.height || el.outerHeight())
7543					});
7544
7545					//Trigger the onRender callback
7546					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7547					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7548
7549					iL.configureHolder(obj, opt, holder);
7550
7551					break;
7552
7553				case 'ajax':
7554					var ajax = obj.options.ajax || {};
7555					//Trigger the onBeforeLoad callback
7556					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7557					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7558
7559					iL.showLoader();
7560					$.ajax({
7561						url: obj.URL || opts.ajaxSetup.url,
7562						data: ajax.data || null,
7563						dataType: ajax.dataType || "html",
7564						type: ajax.type || opts.ajaxSetup.type,
7565						cache: ajax.cache || opts.ajaxSetup.cache,
7566						crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain,
7567						global: ajax.global || opts.ajaxSetup.global,
7568						ifModified: ajax.ifModified || opts.ajaxSetup.ifModified,
7569						username: ajax.username || opts.ajaxSetup.username,
7570						password: ajax.password || opts.ajaxSetup.password,
7571						beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend,
7572						complete: ajax.complete || opts.ajaxSetup.complete,
7573						success: function(data, textStatus, jqXHR) {
7574							iL.hideLoader();
7575
7576							var el = $(data),
7577								container = $('div.ilightbox-container', holder),
7578								elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')),
7579								elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')),
7580								css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? {
7581									'overflow': 'hidden'
7582								} : {};
7583
7584							container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el));
7585							holder.show().data({
7586								naturalWidth: (elWidth || container.outerWidth()),
7587								naturalHeight: (elHeight || container.outerHeight())
7588							}).hide();
7589
7590							//Trigger the onRender callback
7591							if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7592							if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7593
7594							var images = findImageInElement(holder);
7595							iL.loadImage(images, function() {
7596								//Trigger the onAfterLoad callback
7597								if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7598								if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7599
7600								iL.configureHolder(obj, opt, holder);
7601							});
7602
7603							opts.ajaxSetup.success(data, textStatus, jqXHR);
7604							if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR);
7605						},
7606						error: function(jqXHR, textStatus, errorThrown) {
7607							//Trigger the onAfterLoad callback
7608							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7609							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7610
7611							iL.hideLoader();
7612							$('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>');
7613							iL.configureHolder(obj, opt, holder);
7614
7615							opts.ajaxSetup.error(jqXHR, textStatus, errorThrown);
7616							if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown);
7617						}
7618					});
7619
7620					break;
7621
7622				case 'html':
7623					var object = obj.URL,
7624						el
7625					container = $('div.ilightbox-container', holder);
7626
7627					if (object[0].nodeName) el = object.clone();
7628					else {
7629						var dom = $(object);
7630						if (dom.selector) el = $('<div>' + dom + '</div>');
7631						else el = dom;
7632					}
7633
7634					var elWidth = iL.items[item].options.width || parseInt(el.attr('width')),
7635						elHeight = iL.items[item].options.height || parseInt(el.attr('height'));
7636
7637					iL.addContent(holder, obj);
7638
7639					el.appendTo(document.documentElement).hide();
7640
7641					//Trigger the onRender callback
7642					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
7643					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
7644
7645					var images = findImageInElement(holder);
7646
7647					//Trigger the onBeforeLoad callback
7648					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
7649					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
7650
7651					iL.loadImage(images, function() {
7652						//Trigger the onAfterLoad callback
7653						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
7654						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
7655
7656						holder.show().data({
7657							naturalWidth: (elWidth || container.outerWidth()),
7658							naturalHeight: (elHeight || container.outerHeight())
7659						}).hide();
7660						el.remove();
7661
7662						iL.configureHolder(obj, opt, holder);
7663					});
7664
7665					break;
7666			}
7667		},
7668
7669		configureHolder: function(obj, opt, holder) {
7670			var iL = this,
7671				vars = iL.vars,
7672				opts = iL.options;
7673
7674			if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev');
7675
7676			if (opt == "current")
7677				var item = vars.current;
7678			else if (opt == "next")
7679				var opacity = opts.styles.nextOpacity,
7680					item = vars.next;
7681			else
7682				var opacity = opts.styles.prevOpacity,
7683					item = vars.prev;
7684
7685			var api = {
7686				element: holder,
7687				position: item
7688			};
7689
7690			iL.items[item].options.width = iL.items[item].options.width || 0,
7691			iL.items[item].options.height = iL.items[item].options.height || 0;
7692
7693			if (opt == "current") {
7694				if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() {
7695					holder.css(transform, '');
7696					if (obj.caption) {
7697						iL.setCaption(obj, holder);
7698						var caption = $('div.ilightbox-caption', holder),
7699							percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100);
7700						if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
7700Speed);
7701					}
7702
7703					var social = obj.options.social;
7704					if (social) {
7705						iL.setSocial(social, obj.URL, holder);
7706						if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed);
7707					}
7708
7709					//Generate thumbnails
7710					iL.generateThumbnails();
7711
7712					//Trigger the onShow callback
7713					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7714					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7715				});
7716				else {
7717					holder.show();
7718
7719					//Generate thumbnails
7720					iL.generateThumbnails();
7721
7722					//Trigger the onShow callback
7723					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7724					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7725				}
7726			} else {
7727				if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() {
7728					if (opt == "next") vars.nextLock = false;
7729					else vars.prevLock = false;
7730
7731					//Generate thumbnails
7732					iL.generateThumbnails();
7733
7734					//Trigger the onShow callback
7735					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7736					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7737				});
7738				else {
7739					holder.css({
7740						opacity: opacity
7741					}).show();
7742					if (opt == "next") vars.nextLock = false;
7743					else vars.prevLock = false;
7744
7745					//Generate thumbnails
7746					iL.generateThumbnails();
7747
7748					//Trigger the onShow callback
7749					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
7750					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
7751				}
7752			}
7753
7754			setTimeout(function() {
7755				iL.repositionPhoto();
7756			}, 0);
7757		},
7758
7759		generateBoxes: function() {
7760			var iL = this,
7761				vars = iL.vars,
7762				opts = iL.options;
7763
7764			if (opts.infinite && vars.total >= 3) {
7765				if (vars.current == vars.total - 1) vars.next = 0;
7766				if (vars.current == 0) vars.prev = vars.total - 1;
7767			} else opts.infinite = false;
7768
7769			//UNCODE addition
7770			if ( typeof iL.items[vars.current] == 'undefined' )
7771				vars.current = 0;
7772
7773			iL.loadContent(iL.items[vars.current], 'current', opts.show.speed);
7774
7775			if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed);
7776			if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed);
7777		},
7778
7779		generateThumbnails: function() {
7780			var iL = this,
7781				vars = iL.vars,
7782				opts = iL.options,
7783				timeOut = null;
7784
7785			if (vars.thumbs && !iL.vars.dontGenerateThumbs) {
7786				var thumbnails = vars.thumbnails,
7787					container = $('div.ilightbox-thumbnails-container', thumbnails),
7788					grid = $('div.ilightbox-thumbnails-grid', container),
7789					i = 0;
7790
7791				grid.removeAttr('style').empty();
7792
7793				$.each(iL.items, function(key, val) {
7794					var isActive = (vars.current == key) ? 'ilightbox-active' : '',
7795						opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity,
7796						thumb = val.options.thumbnail,
7797						thumbnail = $('<div class="ilightbox-thumbnail"></div>'),
7798						icon = $('<div class="ilightbox-thumbnail-icon"></div>');
7799
7800					thumbnail.css({
7801						opacity: 0
7802					}).addClass(isActive);
7803
7804					if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') {
7805						icon.addClass('ilightbox-thumbnail-video');
7806						thumbnail.append(icon);
7807					} else if (val.options.icon) {
7808						icon.addClass('ilightbox-thumbnail-' + val.options.icon);
7809						thumbnail.append(icon);
7810					}
7811
7812					if (thumb) iL.loadImage(thumb, function(img) {
7813						i++;
7814						if (img) thumbnail.data({
7815							naturalWidth: img.width,
7816							naturalHeight: img.height
7817						}).append('<img src="' + thumb + '" border="0" />');
7818						else thumbnail.data({
7819							naturalWidth: opts.thumbnails.maxWidth,
7820							naturalHeight: opts.thumbnails.maxHeight
7821						});
7822
7823						clearTimeout(timeOut);
7824						timeOut = setTimeout(function() {
7825							iL.positionThumbnails(thumbnails, container, grid);
7826						}, 20);
7827						setTimeout(function() {
7828							thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity);
7829						}, i * 20);
7830					});
7831
7832					grid.append(thumbnail);
7833				});
7834				iL.vars.dontGenerateThumbs = true;
7835			}
7836		},
7837
7838		positionThumbnails: function(thumbnails, container, grid) {
7839			var iL = this,
7840				vars = iL.vars,
7841				opts = iL.options,
7842				viewport = getViewport(),
7843				path = opts.path.toLowerCase();
7844
7845			if (!thumbnails) thumbnails = vars.thumbnails;
7846			if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails);
7847			if (!grid) grid = $('div.ilightbox-thumbnails-grid', container);
7848
7849			var thumbs = $('.ilightbox-thumbnail', grid),
7850				widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX,
7851				heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY,
7852				gridWidth = (path == 'horizontal') ? 0 : widthAvail,
7853				gridHeight = (path == 'horizontal') ? heightAvail : 0,
7854				active = $('.ilightbox-active', grid),
7855				gridCss = {},
7856				css = {};
7857
7858			if (arguments.length < 3) {
7859				thumbs.css({
7860					opacity: opts.thumbnails.normalOpacity
7861				});
7862				active.css({
7863					opacity: opts.thumbnails.activeOpacity
7864				});
7865			}
7866
7867			thumbs.each(function(i) {
7868				var t = $(this),
7869					data = t.data(),
7870					width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth;
7871				height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0;
7872				dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true);
7873
7874				t.css({
7875					width: dims.width,
7876					height: dims.height
7877				});
7878				if (path == 'horizontal') t.css({
7879					'float': 'left'
7880				});
7881
7882				(path == 'horizontal') ? (
7883					gridWidth += t.outerWidth()
7884				) : (
7885					gridHeight += t.outerHeight()
7886				);
7887			});
7888
7889			gridCss = {
7890				width: gridWidth,
7891				height: gridHeight
7892			};
7893
7894			grid.css(gridCss);
7895
7896			gridCss = {};
7897
7898			var gridOffset = grid.offset(),
7899				activeOffset = (active.length) ? active.offset() : {
7900					top: parseInt(heightAvail / 2),
7901					left: parseInt(widthAvail / 2)
7902				};
7903
7904			gridOffset.top = (gridOffset.top - $doc.scrollTop()),
7905				gridOffset.left = (gridOffset.left - $doc.scrollLeft()),
7906				activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()),
7907				activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft());
7908
7909			(path == 'horizontal') ? (
7910				gridCss.top = 0,
7911				gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2))
7912			) : (
7913				gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))),
7914				gridCss.left = 0
7915			);
7916
7917			if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc');
7918			else grid.css(gridCss);
7919		},
7920
7921		loadImage: function(image, callback) {
7922			if (!$.isArray(image)) image = [image];
7923
7924			var iL = this,
7925				length = image.length;
7926
7927			if (length > 0) {
7928				iL.showLoader();
7929				$.each(image, function(index, value) {
7930					var img = new Image();
7931					img.onload = function() {
7932						length -= 1;
7933						if (length == 0) {
7934							iL.hideLoader();
7935							callback(img);
7936						}
7937					};
7938					img.onerror = img.onabort = function() {
7939						length -= 1;
7940						if (length == 0) {
7941							iL.hideLoader();
7942							callback(false);
7943						}
7944					};
7945					img.src = image[index];
7946				});
7947			} else callback(false);
7948		},
7949
7950		patchItemsEvents: function() {
7951			var iL = this,
7952				vars = iL.vars,
7953				clickEvent = supportTouch ? "itap.iL" : "click.iL",
7954				vEvent = supportTouch ? "click.iL" : "itap.iL";
7955
7956			if (iL.context && iL.selector) {
7957				var $items = $(iL.selector, iL.context);
7958
7959				$(iL.context).on(clickEvent, iL.selector, function() {
7960					var $this = $(this),
7961						//UNCODE addition
7962						key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this);
7963					if (UNCODE.isMobile) {
7964						var isCarousel = $this.closest('.owl-carousel');
7965						if (isCarousel.length) {
7966							if (isCarousel.hasClass('owl-translating')) return false;
7967						}
7968					}
7969
7970					vars.current = key;
7971					vars.next = iL.items[key + 1] ? key + 1 : null;
7972					vars.prev = iL.items[key - 1] ? key - 1 : null;
7973
7974					//UNCODE addition
7975					if ( vars.BODY.hasClass('fp-slide-scrolling') )
7976						return false;
7977
7978					iL.addContents();
7979					iL.patchEvents();
7980
7981					return false;
7982				}).on(vEvent, iL.selector, function() {
7983					return false;
7984				});
7985			} else
7986				$.each(iL.itemsObject, function(key, val) {
7987					val.on(clickEvent, function() {
7988						vars.current = key;
7989						vars.next = iL.items[key + 1] ? key + 1 : null;
7990						vars.prev = iL.items[key - 1] ? key - 1 : null;
7991
7992						iL.addContents();
7993						iL.patchEvents();
7994
7995						return false;
7996					}).on(vEvent, function() {
7997						return false;
7998					});
7999				});
8000		},
8001
8002		dispatchItemsEvents: function() {
8003			var iL = this,
8004				vars = iL.vars,
8005				opts = iL.options;
8006
8007			if (iL.context && iL.selector)
8008				$(iL.context).off('.iL', iL.selector);
8009			else
8010				$.each(iL.itemsObject, function(key, val) {
8011					val.off('.iL');
8012				});
8013		},
8014
8015		refresh: function() {
8016			var iL = this;
8017
8018			iL.dispatchItemsEvents();
8019			iL.attachItems();
8020			iL.normalizeItems();
8021			iL.patchItemsEvents();
8022		},
8023
8024		patchEvents: function() {
8025			var iL = this,
8026				vars = iL.vars,
8027				opts = iL.options,
8028				path = opts.path.toLowerCase(),
8029				holders = $('.ilightbox-holder'),
8030				fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox',
8031				durationThreshold = 1000,
8032				horizontalDistanceThreshold =
8033				verticalDistanceThreshold = 100,
8034				buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild];
8035
8036			$win.bind('resize.iLightBox', function() {
8037				var viewport = getViewport();
8038
8039				if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth;
8040				vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
8041
8042				iL.repositionPhoto(null);
8043				if (supportTouch) {
8044					clearTimeout(vars.setTime);
8045					vars.setTime = setTimeout(function() {
8046						var scrollTop = getScrollXY().y;
8047						window.scrollTo(0, scrollTop - 30);
8048						window.scrollTo(0, scrollTop + 30);
8049						window.scrollTo(0, scrollTop);
8050					}, 2000);
8051				}
8052				if (vars.thumbs) iL.positionThumbnails();
8053			}).bind('keydown.iLightBox', function(event) {
8054				if (opts.controls.keyboard) {
8055					switch (event.keyCode) {
8056						case 13:
8057							if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction();
8058							break;
8059						case 27:
8060							if (opts.keyboard.esc) iL.closeAction();
8061							break;
8062						case 37:
8063							if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev');
8064							break;
8065						case 38:
8066							if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev');
8067							break;
8068						case 39:
8069							if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next');
8070							break;
8071						case 40:
8072							if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next');
8073							break;
8074					}
8075				}
8076			});
8077
8078			if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() {
8079				iL.doFullscreen();
8080			});
8081
8082			var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) {
8083					return arr.lastIndexOf(e) === i;
8084				}),
8085				holderEvents = "";
8086
8087			$.each(holderEventsArr, function(key, val) {
8088				if (key != 0) holderEvents += ' ';
8089				holderEvents += val;
8090			});
8091
8092			$doc.on(clickEvent, '.ilightbox-overlay', function() {
8093				if (opts.overlay.blur) iL.closeAction();
8094			}).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() {
8095				iL.moveTo('next');
8096			}).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() {
8097				iL.moveTo('prev');
8098			}).on(clickEvent, '.ilightbox-thumbnail', function() {
8099				var t = $(this),
8100					thumbs = $('.ilightbox-thumbnail', vars.thumbnails),
8101					index = thumbs.index(t);
8102
8103				if (index != vars.current) iL.goTo(index);
8104			}).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
8105				var caption = $('div.ilightbox-caption', vars.holder),
8106					social = $('div.ilightbox-social', vars.holder),
8107					fadeSpeed = opts.effects.fadeSpeed;
8108
8109				if (vars.nextLock || vars.prevLock) {
8110					if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed);
8111					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed);
8112
8113					if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed);
8114					else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed);
8115				} else {
8116					if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed);
8117					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed);
8118
8119					if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed);
8120					else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed);
8121				}
8122			}).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) {
8123				if (e.type == 'mouseenter') vars.lockWheel = true;
8124				else vars.lockWheel = false;
8125			}).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() {
8126				var t = $(this);
8127
8128				if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction();
8129				else if (t.hasClass('ilightbox-play')) {
8130					iL.resume();
8131					t.addClass('ilightbox-pause').removeClass('ilightbox-play');
8132				} else if (t.hasClass('ilightbox-pause')) {
8133					iL.pause();
8134					t.addClass('ilightbox-play').removeClass('ilightbox-pause');
8135				} else iL.closeAction();
8136			}).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) {
8137				// prevent scrolling
8138				e.preventDefault();
8139			});
8140
8141			function mouseMoveHandler(e) {
8142				if (!vars.isMobile) {
8143					if (!vars.mouseID) {
8144						vars.hideableElements.show();
8145					}
8146
8147					vars.mouseID = clearTimeout(vars.mouseID);
8148
8149					if (buttonsArray.indexOf(e.target) === -1)
8150						vars.mouseID = setTimeout(function() {
8151							vars.hideableElements.hide();
8152							vars.mouseID = clearTimeout(vars.mouseID);
8153						}, 3000);
8154				}
8155			}
8156
8157			if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler);
8158
8159			if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
8160				if (e.type == 'mouseenter' && vars.cycleID) iL.pause();
8161				else if (e.type == 'mouseleave' && vars.isPaused) iL.resume();
8162			});
8163
8164			var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails');
8165
8166			if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) {
8167				if (!vars.lockWheel) {
8168					event.preventDefault();
8169					if (delta < 0) iL.moveTo('next');
8170					else if (delta > 0) iL.moveTo('prev');
8171				}
8172			});
8173
8174			if (opts.controls.swipe) holders.on(touchStartEvent, function(event) {
8175				if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return;
8176
8177				vars.BODY.addClass('ilightbox-closedhand');
8178
8179				var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event,
8180					scrollTop = $doc.scrollTop(),
8181					scrollLeft = $doc.scrollLeft(),
8182					offsets = [
8183						holders.eq(0).offset(),
8184						holders.eq(1).offset(),
8185						holders.eq(2).offset()
8186					],
8187					offSet = [{
8188						top: offsets[0].top - scrollTop,
8189						left: offsets[0].left - scrollLeft
8190					}, {
8191						top: offsets[1].top - scrollTop,
8192						left: offsets[1].left - scrollLeft
8193					}, {
8194						top: offsets[2].top - scrollTop,
8195						left: offsets[2].left - scrollLeft
8196					}],
8197					start = {
8198						time: (new Date()).getTime(),
8199						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
8200					},
8201					stop;
8202
8203				function moveEachHandler(i) {
8204					var t = $(this),
8205						offset = offSet[i],
8206						scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])];
8207
8208					t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px';
8209				}
8210
8211				function moveHandler(event) {
8212
8213					if (!start) return;
8214
8215					var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event;
8216
8217					stop = {
8218						time: (new Date()).getTime(),
8219						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
8220					};
8221
8222					holders.each(moveEachHandler);
8223
8224					// prevent scrolling
8225					event.preventDefault();
8226				}
8227
8228				function repositionHolders() {
8229					holders.each(function() {
8230						var t = $(this),
8231							offset = t.data('offset') || {
8232								top: t.offset().top - scrollTop,
8233								left: t.offset().left - scrollLeft
8234							},
8235							top = offset.top,
8236							left = offset.left;
8237
8238						t.css(transform, gpuAcceleration).stop().animate({
8239							top: top,
8240							left: left
8241						}, 500, 'easeOutCirc', function() {
8242							t.css(transform, '');
8243						});
8244					});
8245				}
8246
8247				holders.bind(touchMoveEvent, moveHandler);
8248				$doc.one(touchStopEvent, function(event) {
8249					holders.unbind(touchMoveEvent, moveHandler);
8250
8251					vars.BODY.removeClass('ilightbox-closedhand');
8252
8253					if (start && stop) {
8254						if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) {
8255							if (start.coords[0] > stop.coords[0]) {
8256								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
8257								else {
8258									vars.isSwipe = true;
8259									iL.moveTo('next');
8260								}
8261							} else {
8262								if (vars.current == 0 && !opts.infinite) repositionHolders();
8263								else {
8264									vars.isSwipe = true;
8265									iL.moveTo('prev');
8266								}
8267							}
8268						} 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) {
8269							if (start.coords[1] > stop.coords[1]) {
8270								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
8271								else {
8272									vars.isSwipe = true;
8273									iL.moveTo('next');
8274								}
8275							} else {
8276								if (vars.current == 0 && !opts.infinite) repositionHolders();
8277								else {
8278									vars.isSwipe = true;
8279									iL.moveTo('prev');
8280								}
8281							}
8282						} else repositionHolders();
8283					}
8284					start = stop = undefined;
8285				});
8286			});
8287
8288		},
8289
8290		goTo: function(index) {
8291			var iL = this,
8292				vars = iL.vars,
8293				opts = iL.options,
8294				diff = (index - vars.current);
8295
8296			if (opts.infinite) {
8297				if (index == vars.total - 1 && vars.current == 0) diff = -1;
8298				if (vars.current == vars.total - 1 && index == 0) diff = 1;
8299			}
8300
8301			if (diff == 1) iL.moveTo('next');
8302			else if (diff == -1) iL.moveTo('prev');
8303			else {
8304
8305				if (vars.nextLock || vars.prevLock) return false;
8306
8307				//Trigger the onBeforeChange callback
8308				if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui);
8309
8310				if (opts.linkId) {
8311					vars.hashLock = true;
8312					window.location.hash = opts.linkId + '/' + index;
8313				}
8314
8315				if (iL.items[index]) {
8316					if (!iL.items[index].options.mousewheel) vars.lockWheel = true;
8317					else iL.vars.lockWheel = false;
8318
8319					if (!iL.items[index].options.swipe) vars.lockSwipe = true;
8320					else vars.lockSwipe = false;
8321				}
8322
8323				$.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) {
8324					val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed);
8325				});
8326
8327				vars.current = index;
8328				vars.next = index + 1;
8329				vars.prev = index - 1;
8330
8331				iL.createUI();
8332
8333				setTimeout(function() {
8334					iL.generateBoxes();
8335				}, opts.effects.loadedFadeSpeed + 50);
8336
8337				$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active');
8338				iL.positionThumbnails();
8339
8340				if (opts.linkId) setTimeout(function() {
8341					vars.hashLock = false;
8342				}, 55);
8343
8344				// Configure arrow buttons
8345				if (!opts.infinite) {
8346					vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8347
8348					if (vars.current == 0) {
8349						vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8350					}
8351					if (vars.current >= vars.total - 1) {
8352						vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8353					}
8354				}
8355
8356				// Reset next cycle timeout
8357				iL.resetCycle();
8358
8359				//Trigger the onAfterChange callback
8360				if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui);
8361			}
8362		},
8363
8364		moveTo: function(side) {
8365			var iL = this,
8366				vars = iL.vars,
8367				opts = iL.options,
8368				path = opts.path.toLowerCase(),
8369				viewport = getViewport(),
8370				switchSpeed = opts.effects.switchSpeed;
8371
8372			if (vars.nextLock || vars.prevLock) return false;
8373			else {
8374
8375				var item = (side == "next") ? vars.next : vars.prev;
8376
8377				if (opts.linkId) {
8378					vars.hashLock = true;
8379					window.location.hash = opts.linkId + '/' + item;
8380				}
8381
8382				if (side == "next") {
8383					if (!iL.items[item]) return false;
8384					var firstHolder = vars.nextPhoto,
8385						secondHolder = vars.holder,
8386						lastHolder = vars.prevPhoto,
8387						firstClass = 'ilightbox-prev',
8388						secondClass = 'ilightbox-next';
8389				} else if (side == "prev") {
8390					if (!iL.items[item]) return false;
8391					var firstHolder = vars.prevPhoto,
8392						secondHolder = vars.holder,
8393						lastHolder = vars.nextPhoto,
8394						firstClass = 'ilightbox-next',
8395						secondClass = 'ilightbox-prev';
8396				}
8397
8398				//Trigger the onBeforeChange callback
8399				if (typeof opts.callback.onBeforeChange == 'function')
8400					opts.callback.onBeforeChange.call(iL, iL.ui);
8401
8402				(side == "next") ? vars.nextLock = true: vars.prevLock = true;
8403
8404				var captionFirst = $('div.ilightbox-caption', secondHolder),
8405					socialFirst = $('div.ilightbox-social', secondHolder);
8406
8407				if (captionFirst.length)
8408					captionFirst.stop().fadeOut(switchSpeed, function() {
8409						$(this).remove();
8410					});
8411				if (socialFirst.length)
8412					socialFirst.stop().fadeOut(switchSpeed, function() {
8413						$(this).remove();
8414					});
8415
8416				if (iL.items[item].caption) {
8417					iL.setCaption(iL.items[item], firstHolder);
8418					var caption = $('div.ilightbox-caption', firstHolder),
8419						percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100);
8420					if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed);
8421				}
8422
8423				var social = iL.items[item].options.social;
8424				if (social) {
8425					iL.setSocial(social, iL.items[item].URL, firstHolder);
8426					if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed);
8427				}
8428
8429				$.each([firstHolder, secondHolder, lastHolder], function(key, val) {
8430					val.removeClass('ilightbox-next ilightbox-prev');
8431				});
8432
8433				var firstOffset = firstHolder.data('offset'),
8434					winW = (viewport.width - (opts.styles.pageOffsetX)),
8435					winH = (viewport.height - (opts.styles.pageOffsetY)),
8436					width = firstOffset.newDims.width,
8437					height = firstOffset.newDims.height,
8438					thumbsOffset = firstOffset.thumbsOffset,
8439					diff = firstOffset.diff,
8440					top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)),
8441					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
8442
8443				var secondOffset = secondHolder.data('offset'),
8444					object = secondOffset.object;
8445
8446				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
8447					var objRatio = width / height;
8448					height = height - vars.captionHeight;
8449					width = height * objRatio;
8450					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top,
8451					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
8452				}*/
8453
8454				firstHolder.show().css(transform, gpuAcceleration).animate({
8455					top: top,
8456					left: left,
8457					opacity: 1
8458				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8459					firstHolder.css(transform, '');
8460				});
8461
8462				$('div.ilightbox-container', firstHolder).animate({
8463					width: width,
8464					height: height
8465				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
8466
8467				diff = secondOffset.diff;
8468
8469				width = secondOffset.newDims.width,
8470					height = secondOffset.newDims.height;
8471
8472				width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
8473					height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
8474					top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2));
8475
8476				if (side == 'prev')
8477					left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2));
8478				else {
8479					top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)),
8480					left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2));
8481				}
8482
8483				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
8484					var objRatio = width / height;
8485					height = height - vars.captionHeight;
8486					width = height * objRatio;
8487					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top;
8488				}*/
8489
8490				$('div.ilightbox-container', secondHolder).animate({
8491					width: width,
8492					height: height
8493				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
8494
8495				secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({
8496					top: top,
8497					left: left,
8498					opacity: opts.styles.prevOpacity,
8499				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8500					secondHolder.css(transform, '');
8501
8502					$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active');
8503					iL.positionThumbnails();
8504
8505					if (iL.items[item]) {
8506						if (!iL.items[item].options.mousewheel) vars.lockWheel = true;
8507						else vars.lockWheel = false;
8508
8509						if (!iL.items[item].options.swipe) vars.lockSwipe = true;
8510						else vars.lockSwipe = false;
8511					}
8512
8513					vars.isSwipe = false;
8514
8515					// Remove iframe & video from previous slide
8516					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
8517						$('div.ilightbox-container', secondHolder).empty();
8518					}
8519
8520					if (side == "next") {
8521						vars.nextPhoto = lastHolder,
8522							vars.prevPhoto = secondHolder,
8523							vars.holder = firstHolder;
8524
8525						vars.nextPhoto.hide();
8526
8527						vars.next = vars.next + 1,
8528							vars.prev = vars.current,
8529							vars.current = vars.current + 1;
8530
8531						if (opts.infinite) {
8532							if (vars.current > vars.total - 1) vars.current = 0;
8533							if (vars.current == vars.total - 1) vars.next = 0;
8534							if (vars.current == 0) vars.prev = vars.total - 1;
8535						}
8536
8537						iL.createUI();
8538
8539						if (!iL.items[vars.next])
8540							vars.nextLock = false;
8541						else
8542							iL.loadContent(iL.items[vars.next], 'next');
8543					} else {
8544						vars.prevPhoto = lastHolder;
8545						vars.nextPhoto = secondHolder;
8546						vars.holder = firstHolder;
8547
8548						vars.prevPhoto.hide();
8549
8550						vars.next = vars.current;
8551						vars.current = vars.prev;
8552						vars.prev = vars.current - 1;
8553
8554						if (opts.infinite) {
8555							if (vars.current == vars.total - 1) vars.next = 0;
8556							if (vars.current == 0) vars.prev = vars.total - 1;
8557						}
8558
8559						iL.createUI();
8560
8561						if (!iL.items[vars.prev])
8562							vars.prevLock = false;
8563						else
8564							iL.loadContent(iL.items[vars.prev], 'prev');
8565					}
8566
8567					// Add iframe & video content for current slide
8568					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
8569						iL.loadContent(iL.items[vars.current], 'current');
8570					}
8571
8572					if (opts.linkId) setTimeout(function() {
8573						vars.hashLock = false;
8574					}, 55);
8575
8576					// Configure arrow buttons
8577					if (!opts.infinite) {
8578						vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
8579
8580						if (vars.current == 0)
8581							vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
8582						if (vars.current >= vars.total - 1)
8583							vars.nextButton.add(vars.innerNextButton).addClass('disabled');
8584					}
8585
8586					iL.repositionPhoto();
8587
8588					// Reset next cycle timeout
8589					iL.resetCycle();
8590
8591					//Trigger the onAfterChange callback
8592					if (typeof opts.callback.onAfterChange == 'function')
8593						opts.callback.onAfterChange.call(iL, iL.ui);
8594				});
8595
8596				top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)),
8597					left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left');
8598
8599				lastHolder.css(transform, gpuAcceleration).animate({
8600					top: top,
8601					left: left,
8602					opacity: opts.styles.nextOpacity
8603				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
8604					lastHolder.css(transform, '');
8605				}).addClass(secondClass);
8606			}
8607		},
8608
8609		setCaption: function(obj, target) {
8610			var iL = this,
8611				caption = $('<div class="ilightbox-caption"></div>');
8612
8613			if (obj.caption) {
8614				caption.html(obj.caption);
8615				$('div.ilightbox-container', target).append(caption);
8616			}
8617		},
8618
8619		normalizeSocial: function(obj, url) {
8620			var iL = this,
8621				vars = iL.vars,
8622				opts = iL.options,
8623				baseURL = window.location.href;
8624
8625			$.each(obj, function(key, value) {
8626				if (!value)
8627					return true;
8628
8629				var item = key.toLowerCase(),
8630					source, text;
8631
8632				switch (item) {
8633					case 'facebook':
8634						source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}",
8635							text = "Share on Facebook";
8636						break;
8637					case 'twitter':
8638						source = "http://twitter.com/home?status={URL}",
8639							text = "Share on Twitter";
8640						break;
8641					case 'googleplus':
8642						source = "https://plus.google.com/share?url={URL}",
8643							text = "Share on Google+";
8644						break;
8645					case 'delicious':
8646						source = "http://delicious.com/post?url={URL}",
8647							text = "Share on Delicious";
8648						break;
8649					case 'digg':
8650						source = "http://digg.com/submit?phase=2&url={URL}",
8651							text = "Share on Digg";
8652						break;
8653					case 'reddit':
8654						source = "http://reddit.com/submit?url={URL}",
8655							text = "Share on reddit";
8656						break;
8657				}
8658
8659				obj[key] = {
8660					URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL,
8661					source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url),
8662					text: value.text || text || "Share on " + key,
8663					width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640,
8664					height: value.height || 360
8665				};
8666
8667			});
8668
8669			return obj;
8670		},
8671
8672		setSocial: function(obj, url, target) {
8673			var iL = this,
8674				socialBar = $('<div class="ilightbox-social"></div>'),
8675				buttons = '<ul>';
8676
8677			obj = iL.normalizeSocial(obj, url);
8678
8679			$.each(obj, function(key, value) {
8680				var item = key.toLowerCase(),
8681					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, '+'));
8682				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>';
8683			});
8684
8685			buttons += '</ul>';
8686
8687			socialBar.html(buttons);
8688			$('div.ilightbox-container', target).append(socialBar);
8689		},
8690
8691		fullScreenAction: function() {
8692			var iL = this,
8693				vars = iL.vars;
8694
8695			if (fullScreenApi.supportsFullScreen) {
8696				if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement);
8697				else fullScreenApi.requestFullScreen(document.documentElement);
8698			} else {
8699				iL.doFullscreen();
8700			}
8701		},
8702
8703		doFullscreen: function() {
8704			var iL = this,
8705				vars = iL.vars,
8706				viewport = getViewport(),
8707				opts = iL.options;
8708
8709			if (opts.fullAlone) {
8710				var currentHolder = vars.holder,
8711					current = iL.items[vars.current],
8712					windowWidth = viewport.width,
8713					windowHeight = viewport.height,
8714					elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader],
8715					hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
8716
8717				if (!vars.isInFullScreen) {
8718					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true;
8719					vars.overlay.css({
8720						opacity: 1
8721					});
8722
8723					$.each(hideElements, function(i, element) {
8724						element.hide();
8725					});
8726
8727					vars.fullScreenButton.attr('title', opts.text.exitFullscreen);
8728
8729					if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
8730						naturalWidthOld: currentHolder.data('naturalWidth'),
8731						naturalHeightOld: currentHolder.data('naturalHeight'),
8732						naturalWidth: windowWidth,
8733						naturalHeight: windowHeight
8734					});
8735					else {
8736						var viewport = current.options.fullViewPort || opts.fullViewPort || '',
8737							newWidth = windowWidth,
8738							newHeight = windowHeight,
8739							width = currentHolder.data('naturalWidth'),
8740							height = currentHolder.data('naturalHeight');
8741
8742						if (viewport.toLowerCase() == 'fill') {
8743							newHeight = (newWidth / width) * height;
8744
8745							if (newHeight < windowHeight) {
8746								newWidth = (windowHeight / height) * width,
8747									newHeight = windowHeight;
8748							}
8749						} else if (viewport.toLowerCase() == 'fit') {
8750							var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true);
8751
8752							newWidth = dims.width,
8753								newHeight = dims.height;
8754						} else if (viewport.toLowerCase() == 'stretch') {
8755							newWidth = newWidth,
8756								newHeight = newHeight;
8757						} else {
8758							var scale = (width > newWidth || height > newHeight) ? true : false,
8759								dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale);
8760							newWidth = dims.width,
8761								newHeight = dims.height;
8762						}
8763
8764						currentHolder.data({
8765							naturalWidthOld: currentHolder.data('naturalWidth'),
8766							naturalHeightOld: currentHolder.data('naturalHeight'),
8767							naturalWidth: newWidth,
8768							naturalHeight: newHeight
8769						});
8770					}
8771
8772					$.each(elements, function(key, val) {
8773						val.addClass('ilightbox-fullscreen');
8774					});
8775
8776					//Trigger the onEnterFullScreen callback
8777					if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui);
8778				} else {
8779					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false;
8780					vars.overlay.css({
8781						opacity: iL.options.overlay.opacity
8782					});
8783
8784					$.each(hideElements, function(i, element) {
8785						element.show();
8786					});
8787
8788					vars.fullScreenButton.attr('title', opts.text.enterFullscreen);
8789
8790					currentHolder.data({
8791						naturalWidth: currentHolder.data('naturalWidthOld'),
8792						naturalHeight: currentHolder.data('naturalHeightOld'),
8793						naturalWidthOld: null,
8794						naturalHeightOld: null
8795					});
8796
8797					$.each(elements, function(key, val) {
8798						val.removeClass('ilightbox-fullscreen');
8799					});
8800
8801					//Trigger the onExitFullScreen callback
8802					if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui);
8803				}
8804			} else {
8805				if (!vars.isInFullScreen) vars.isInFullScreen = true;
8806				else vars.isInFullScreen = false;
8807			}
8808			iL.repositionPhoto(true);
8809		},
8810
8811		closeAction: function() {
8812			var iL = this,
8813				vars = iL.vars,
8814				opts = iL.options;
8815
8816			$win.unbind('.iLightBox');
8817			$doc.off('.iLightBox');
8818
8819			if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement);
8820
8821			$('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox');
8822
8823			if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() {
8824				vars.overlay.remove();
8825				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
8826			});
8827			else {
8828				vars.overlay.remove();
8829				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
8830			}
8831
8832			var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
8833
8834			$.each(fadeOuts, function(i, element) {
8835				element.removeAttr('style').remove();
8836			});
8837
8838			vars.dontGenerateThumbs = vars.isInFullScreen = false;
8839
8840			window.iLightBox = null;
8841
8842			if (opts.linkId) {
8843				vars.hashLock = true;
8844				removeHash();
8845				setTimeout(function() {
8846					vars.hashLock = false;
8847				}, 55);
8848			}
8849
8850			//Trigger the onHide callback
8851			if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui);
8852		},
8853
8854		repositionPhoto: function() {
8855			var iL = this,
8856				vars = iL.vars,
8857				opts = iL.options,
8858				path = opts.path.toLowerCase(),
8859				viewport = getViewport(),
8860				winWidth = viewport.width,
8861				winHeight = viewport.height;
8862
8863			if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0;
8864
8865			var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()),
8866				thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)),
8867				width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)),
8868				height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)),
8869				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,
8870				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)));
8871
8872			var elObject = {
8873				type: 'current',
8874				width: width,
8875				height: height,
8876				item: iL.items[vars.current],
8877				offsetW: offsetW,
8878				offsetH: offsetH,
8879				thumbsOffsetW: thumbsOffsetW,
8880				thumbsOffsetH: thumbsOffsetH,
8881				animate: arguments.length,
8882				holder: vars.holder
8883			};
8884
8885			iL.repositionEl(elObject);
8886
8887			if (iL.items[vars.next]) {
8888				elObject = $.extend(elObject, {
8889					type: 'next',
8890					item: iL.items[vars.next],
8891					offsetX: opts.styles.nextOffsetX,
8892					offsetY: opts.styles.nextOffsetY,
8893					holder: vars.nextPhoto
8894				});
8895
8896				iL.repositionEl(elObject);
8897			}
8898
8899			if (iL.items[vars.prev]) {
8900				elObject = $.extend(elObject, {
8901					type: 'prev',
8902					item: iL.items[vars.prev],
8903					offsetX: opts.styles.nextOffsetX,
8904					offsetY: opts.styles.prevOffsetY,
8905					holder: vars.prevPhoto
8906				});
8907
8908				iL.repositionEl(elObject);
8909			}
8910
8911			var loaderCss = (path == "horizontal") ? {
8912				left: parseInt((width / 2) - (vars.loader.outerWidth() / 2))
8913			} : {
8914				top: parseInt((height / 2) - (vars.loader.outerHeight() / 2))
8915			};
8916			vars.loader.css(loaderCss);
8917		},
8918
8919		repositionEl: function(obj) {
8920			var iL = this,
8921				vars = iL.vars,
8922				opts = iL.options,
8923				path = opts.path.toLowerCase(),
8924				widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW),
8925				heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH),
8926				itemParent = obj.item,
8927				item = obj.item.options,
8928				holder = obj.holder,
8929				offsetX = obj.offsetX || 0,
8930				offsetY = obj.offsetY || 0,
8931				thumbsOffsetW = obj.thumbsOffsetW,
8932				thumbsOffsetH = obj.thumbsOffsetH;
8933
8934			if (obj.type == 'current') {
8935				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);
8936				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);
8937			} else {
8938				if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width;
8939				if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height;
8940			}
8941
8942			heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight());
8943
8944			var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'),
8945				height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight');
8946
8947			var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? {
8948					width: width,
8949					height: height
8950				} : iL.getNewDimenstions(widthAvail, heightAvail, width, height)),
8951				newDims = $.extend({}, dims, {});
8952
8953			if (obj.type == 'prev' || obj.type == 'next')
8954				width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)),
8955				height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale));
8956			else
8957				width = dims.width,
8958				height = dims.height;
8959
8960			var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2),
8961				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);
8962
8963			switch (obj.type) {
8964				case 'current':
8965					var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)),
8966						left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2));
8967					break;
8968
8969				case 'next':
8970					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)),
8971						left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2));
8972					break;
8973
8974				case 'prev':
8975					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)),
8976						left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2));
8977					break;
8978			}
8979
8980			holder.data('offset', {
8981				top: top,
8982				left: left,
8983				newDims: newDims,
8984				diff: {
8985					W: widthDiff,
8986					H: heightDiff
8987				},
8988				thumbsOffset: {
8989					W: thumbsOffsetW,
8990					H: thumbsOffsetH
8991				},
8992				object: obj
8993			});
8994
8995			var opacityMobile;
8996			if ( isMobile ) {
8997				opacityMobile = {
8998					opacity: 1,
8999					top: top,
9000					left: left
9001				};
9002			} else {
9003				opacityMobile = {
9004					top: top,
9005					left: left
9006				};
9007			}
9008
9009			if (obj.animate > 0 && opts.effects.reposition) {
9010				holder.css(transform, gpuAcceleration).stop().animate(
9011					opacityMobile,
9012					opts.effects.repositionSpeed, 'easeOutCirc', function() {
9013					holder.css(transform, '');
9014				});
9015				$('div.ilightbox-container', holder).stop().animate({
9016					width: width,
9017					height: height
9018				}, opts.effects.repositionSpeed, 'easeOutCirc');
9019				$('div.ilightbox-inner-toolbar', holder).stop().animate({
9020					width: width
9021				}, opts.effects.repositionSpeed, 'easeOutCirc', function() {
9022					$(this).css('overflow', 'visible');
9023				});
9024			} else {
9025				holder.css(opacityMobile);
9026				$('div.ilightbox-container', holder).css({
9027					width: width,
9028					height: height
9029				});
9030				$('div.ilightbox-inner-toolbar', holder).css({
9031					width: width
9032				});
9033			}
9034		},
9035
9036
9037		resume: function(priority) {
9038			var iL = this,
9039				vars = iL.vars,
9040				opts = iL.options;
9041
9042			if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) {
9043				return;
9044			}
9045
9046			vars.isPaused = 0;
9047
9048			if (vars.cycleID) {
9049				vars.cycleID = clearTimeout(vars.cycleID);
9050			}
9051
9052			vars.cycleID = setTimeout(function() {
9053				if (vars.current == vars.total - 1) iL.goTo(0);
9054				else iL.moveTo('next');
9055			}, opts.slideshow.pauseTime);
9056		},
9057
9058		pause: function(priority) {
9059			var iL = this,
9060				vars = iL.vars,
9061				opts = iL.options;
9062
9063			if (priority < vars.isPaused) {
9064				return;
9065			}
9066
9067			vars.isPaused = priority || 100;
9068
9069			if (vars.cycleID) {
9070				vars.cycleID = clearTimeout(vars.cycleID);
9071			}
9072		},
9073
9074		resetCycle: function() {
9075			var iL = this,
9076				vars = iL.vars,
9077				opts = iL.options;
9078
9079			if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) {
9080				iL.resume();
9081			}
9082		},
9083
9084		getNewDimenstions: function(width, height, width_old, height_old, thumb) {
9085			var iL = this;
9086
9087			if (!width) factor = height / height_old;
9088			else if (!height) factor = width / width_old;
9089			else factor = min(width / width_old, height / height_old);
9090
9091			if (!thumb) {
9092				if (factor > iL.options.maxScale) factor = iL.options.maxScale;
9093				else if (factor < iL.options.minScale) factor = iL.options.minScale;
9094			}
9095
9096			var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width,
9097				final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height;
9098
9099			return {
9100				width: final_width,
9101				height: final_height,
9102				ratio: factor
9103			};
9104		},
9105
9106		setOption: function(options) {
9107			var iL = this;
9108
9109			iL.options = $.extend(true, iL.options, options || {});
9110			iL.refresh();
9111		},
9112
9113		availPlugins: function() {
9114			var iL = this,
9115				testEl = document.createElement("video");
9116
9117			iL.plugins = {
9118				flash: !isMobile,
9119				quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false,
9120				html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')),
9121				html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')),
9122				html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')),
9123				html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, ''))
9124			};
9125		},
9126
9127		addContent: function(element, obj) {
9128			var iL = this,
9129				el;
9130
9131			switch (obj.type) {
9132				case 'video':
9133					var HTML5 = false,
9134						videoType = obj.videoType,
9135						html5video = obj.options.html5video;
9136
9137					if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264)
9138						obj.ext = 'mp4',
9139						obj.URL = html5video.h264 || obj.URL;
9140					else if (html5video.webm && iL.plugins.html5WebM)
9141						obj.ext = 'webm',
9142						obj.URL = html5video.webm || obj.URL;
9143					else if (html5video.ogg && iL.plugins.html5Vorbis)
9144						obj.ext = 'ogv',
9145						obj.URL = html5video.ogg || obj.URL;
9146
9147					if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4";
9148					else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm";
9149					else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg";
9150					else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime";
9151
9152					if (HTML5) {
9153						el = $('<video />
9153', {
9154							"width": "100%",
9155							"height": "100%",
9156							"preload": html5video.preload,
9157							"autoplay": html5video.autoplay,
9158							"poster": html5video.poster,
9159							"controls": html5video.controls
9160						}).append($('<source />', {
9161							"src": obj.URL,
9162							"type": videoType
9163						}));
9164					} else {
9165						if (!iL.plugins.quicktime) el = $('<span />', {
9166							"class": "ilightbox-alert",
9167							html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime')
9168						});
9169						else {
9170
9171							el = $('<object />', {
9172								"type": "video/quicktime",
9173								"pluginspage": pluginspages.quicktime
9174							}).attr({
9175								"data": obj.URL,
9176								"width": "100%",
9177								"height": "100%"
9178							}).append($('<param />', {
9179								"name": "src",
9180								"value": obj.URL
9181							})).append($('<param />', {
9182								"name": "autoplay",
9183								"value": "false"
9184							})).append($('<param />', {
9185								"name": "loop",
9186								"value": "false"
9187							})).append($('<param />', {
9188								"name": "scale",
9189								"value": "tofit"
9190							}));
9191
9192							if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false');
9193						}
9194					}
9195
9196					break;
9197
9198				case 'flash':
9199					if (!iL.plugins.flash) el = $('<span />', {
9200						"class": "ilightbox-alert",
9201						html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player')
9202					});
9203					else {
9204						var flashvars = "",
9205							i = 0;
9206
9207						if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) {
9208							if (i != 0) flashvars += "&";
9209							flashvars += k + "=" + encodeURIComponent(v);
9210							i++;
9211						});
9212						else flashvars = null;
9213
9214						el = $('<embed />').attr({
9215							"type": "application/x-shockwave-flash",
9216							"src": obj.URL,
9217							"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
9218							"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
9219							"quality": "high",
9220							"bgcolor": "#000000",
9221							"play": "true",
9222							"loop": "true",
9223							"menu": "true",
9224							"wmode": "transparent",
9225							"scale": "showall",
9226							"allowScriptAccess": "always",
9227							"allowFullScreen": "true",
9228							"flashvars": flashvars,
9229							"fullscreen": "yes"
9230						});
9231					}
9232
9233					break;
9234
9235				case 'iframe':
9236					el = $('<iframe />').attr({
9237						"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
9238						"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
9239						src: obj.URL,
9240						frameborder: 0,
9241						'hspace': 0,
9242						'vspace': 0,
9243						'scrolling': supportTouch ? 'auto' : 'scroll',
9244						'webkitAllowFullScreen': '',
9245						'mozallowfullscreen': '',
9246						'allowFullScreen': ''
9247					});
9248
9249					break;
9250
9251				case 'inline':
9252					el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true));
9253
9254					break;
9255
9256				case 'html':
9257					var object = obj.URL,
9258						el;
9259
9260					if (object[0].nodeName) {
9261						el = $('<div class="ilightbox-wrapper"></div>').html(object);
9262					} else {
9263						var dom = $(obj.URL),
9264							html = (dom.selector) ? $('<div>' + dom + '</div>') : dom;
9265						el = $('<div class="ilightbox-wrapper"></div>').html(html);
9266					}
9267
9268					break;
9269			}
9270
9271			$('div.ilightbox-container', element).empty().html(el);
9272
9273			// For fixing Chrome about just playing the video for first time
9274			if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() {
9275				var src = el[0].currentSrc + '?' + floor(random() * 30000);
9276				el[0].currentSrc = src;
9277				el[0].src = src;
9278			});
9279
9280			return el;
9281		},
9282
9283		ogpRecognition: function(obj, callback) {
9284			var iL = this,
9285				url = obj.URL;
9286
9287			iL.showLoader();
9288			doAjax(url, function(data) {
9289				iL.hideLoader();
9290				if (data) {
9291					var object = new Object();
9292
9293					object.length = false,
9294					object.url = data.url;
9295
9296					if (data.status == 200) {
9297						var result = data.results,
9298							type = result.type,
9299							source = result.source;
9300
9301						object.source = source.src,
9302						object.width = source.width && parseInt(source.width) || 0,
9303						object.height = source.height && parseInt(source.height) || 0,
9304						object.type = type,
9305						object.thumbnail = source.thumbnail || result.images && result.images[0],
9306						object.html5video = result.html5video || {},
9307						object.length = true;
9308
9309						if (source.type == 'application/x-shockwave-flash') object.type = "flash";
9310						else if (source.type.indexOf("video/") != -1) object.type = "video";
9311						else if (source.type.indexOf("/html") != -1) object.type = "iframe";
9312						else if (source.type.indexOf("image/") != -1) object.type = "image";
9313
9314					} else if (typeof data.response != 'undefined')
9315						throw data.response;
9316
9317					callback.call(this, object.length ? object : false);
9318				}
9319			});
9320		},
9321
9322		hashChangeHandler: function(url) {
9323			var iL = this,
9324				vars = iL.vars,
9325				opts = iL.options,
9326				URL = url || window.location.href,
9327				hash = parseURI(URL).hash,
9328				split = hash.split('/'),
9329				index = split[1];
9330
9331			if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return;
9332
9333			if (index) {
9334				var target = split[1] || 0;
9335				if (iL.items[target]) {
9336					var overlay = $('.ilightbox-overlay');
9337					if (overlay.length && overlay.attr('linkid') == opts.linkId) {
9338						iL.goTo(target);
9339					} else {
9340						iL.itemsObject[target].trigger(supportTouch ? 'itap' : 'click');
9341						//iL.goTo(target);
9342					}
9343				} else {
9344					var overlay = $('.ilightbox-overlay');
9345					if (overlay.length) iL.closeAction();
9346				}
9347			} else {
9348				var overlay = $('.ilightbox-overlay');
9349				if (overlay.length) iL.closeAction();
9350			}
9351		}
9352	};
9353
9354	/**
9355	 * Parse style to pixels.
9356	 *
9357	 * @param {Object}   $element   jQuery object with element.
9358	 * @param {Property} property   CSS property to get the pixels from.
9359	 *
9360	 * @return {Int}
9361	 */
9362	function getPixel($element, property) {
9363		return parseInt($element.css(property), 10) || 0;
9364	}
9365
9366	/**
9367	 * Make sure that number is within the limits.
9368	 *
9369	 * @param {Number} number
9370	 * @param {Number} min
9371	 * @param {Number} max
9372	 *
9373	 * @return {Number}
9374	 */
9375	function within(number, min, max) {
9376		return number < min ? min : number > max ? max : number;
9377	}
9378
9379	/**
9380	 * Get viewport/window size (width and height).
9381	 *
9382	 * @return {Object}
9383	 */
9384	function getViewport() {
9385		var e = window,
9386			a = 'inner';
9387		if (!('innerWidth' in window)) {
9388			a = 'client';
9389			e = document.documentElement || document.body;
9390		}
9391		return {
9392			width: e[a + 'Width'],
9393			height: e[a + 'Height']
9394		}
9395	}
9396
9397	/**
9398	 * Remove hash tag from the URL
9399	 *
9400	 * @return {Void}
9401	 */
9402	function removeHash() {
9403		var scroll = getScrollXY();
9404
9405		//UNCODE change
9406		//window.location.hash = "";
9407		history.pushState("", document.title, window.location.pathname + window.location.search);
9408
9409		// Restore the scroll offset, should be flicker free
9410		window.scrollTo(scroll.x, scroll.y);
9411	}
9412
9413	/**
9414	 * Do the ajax requests with callback.
9415	 *
9416	 * @param {String}   url
9417	 * @param {Function} callback
9418	 *
9419	 * @return {Void}
9420	 */
9421	function doAjax(url, callback) {
9422		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');
9423		$.ajax({
9424			url: url,
9425			dataType: 'jsonp'
9426		});
9427
9428		iLCallback = function(data) {
9429			callback.call(this, data);
9430		};
9431	}
9432
9433	/**
9434	 * Find image from DOM elements
9435	 *
9436	 * @param {Element} element
9437	 *
9438	 * @return {Void}
9439	 */
9440	function findImageInElement(element) {
9441		var elements = $('*', element),
9442			imagesArr = new Array();
9443
9444		elements.each(function() {
9445			var url = "",
9446				element = this;
9447
9448			if ($(element).css("background-image") != "none") {
9449				url = $(element).css("background-image");
9450			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
9451				url = $(element).attr("src");
9452			}
9453
9454			if (url.indexOf("gradient") == -1) {
9455				url = url.replace(/url\(\"/g, "");
9456				url = url.replace(/url\(/g, "");
9457				url = url.replace(/\"\)/g, "");
9458				url = url.replace(/\)/g, "");
9459
9460				var urls = url.split(",");
9461
9462				for (var i = 0; i < urls.length; i++) {
9463					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
9464						var extra = "";
9465						if (browser.msie && browser.version < 9) {
9466							extra = "?" + floor(random() * 3000);
9467						}
9468						imagesArr.push(urls[i] + extra);
9469					}
9470				}
9471			}
9472		});
9473
9474		return imagesArr;
9475	}
9476
9477	/**
9478	 * Get file extension.
9479	 *
9480	 * @param {String} URL
9481	 *
9482	 * @return {String}
9483	 */
9484	function getExtension(URL) {
9485		if (URL !== null) {
9486			var ext = URL.split('.').pop().toLowerCase(),
9487				extra = ext.indexOf('?') !== -1 ? ext.split('?').pop() : '';
9488
9489			//UNCODE: fix issue to detect media type with query strings
9490			ext = ext.replace('?'+extra, '');
9491
9492			return ext.replace(extra, '');
9493		}
9494	}
9495
9496	/**
9497	 * Get type via extension.
9498	 *
9499	 * @param {String} URL
9500	 *
9501	 * @return {String}
9502	 */
9503	function getTypeByExtension(URL) {
9504		var type,
9505			ext = getExtension(URL);
9506
9507		if (extensions.image.indexOf(ext) !== -1) type = 'image';
9508		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
9509		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
9510		else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition
9511		else type = 'iframe';
9512
9513		return type;
9514	}
9515
9516	/**
9517	 * Return value from percent of a number.
9518	 *
9519	 * @param {Number} percent
9520	 * @param {Number} total
9521	 *
9522	 * @return {Number}
9523	 */
9524	function percentToValue(percent, total) {
9525		return parseInt((total / 100) * percent);
9526	}
9527
9528	/**
9529	 * A JavaScript equivalent of PHP’s parse_url.
9530	 *
9531	 * @param {String} url           The URL to parse.
9532	 *
9533	 * @return {Mixed}
9534	 */
9535	function parseURI(url) {
9536		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
9537		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
9538		return (m ? {
9539			href: m[0] || '',
9540			protocol: m[1] || '',
9541			authority: m[2] || '',
9542			host: m[3] || '',
9543			hostname: m[4] || '',
9544			port: m[5] || '',
9545			pathname: m[6] || '',
9546			search: m[7] || '',
9547			hash: m[8] || ''
9548		} : null);
9549	}
9550
9551	/**
9552	 * Gets the absolute URI.
9553	 *
9554	 * @param {String} href     The relative URL.
9555	 * @param {String} base     The base URL.
9556	 *
9557	 * @return {String}         The absolute URL.
9558	 */
9559	function absolutizeURI(base, href) { // RFC 3986
9560		var iL = this;
9561
9562		function removeDotSegments(input) {
9563			var output = [];
9564			input.replace(/^(\.\.?(\/|$))+/, '')
9565				.replace(/\/(\.(\/|$))+/g, '/')
9566				.replace(/\/\.\.$/, '/../')
9567				.replace(/\/?[^\/]*/g, function(p) {
9568					if (p === '/..') {
9569						output.pop();
9570					} else {
9571						output.push(p);
9572					}
9573				});
9574			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
9575		}
9576
9577		href = parseURI(href || '');
9578		base = parseURI(base || '');
9579
9580		return !href || !base ? null : (href.protocol || base.protocol) +
9581			(href.protocol || href.authority ? href.authority : base.authority) +
9582			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)) +
9583			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
9584			href.hash;
9585	}
9586
9587	/**
9588	 * A JavaScript equivalent of PHP’s version_compare.
9589	 *
9590	 * @param {String} v1
9591	 * @param {String} v2
9592	 * @param {String} operator
9593	 *
9594	 * @return {Boolean}
9595	 */
9596	function version_compare(v1, v2, operator) {
9597		this.php_js = this.php_js || {};
9598		this.php_js.ENV = this.php_js.ENV || {};
9599		var i = 0,
9600			x = 0,
9601			compare = 0,
9602			vm = {
9603				'dev': -6,
9604				'alpha': -5,
9605				'a': -5,
9606				'beta': -4,
9607				'b': -4,
9608				'RC': -3,
9609				'rc': -3,
9610				'#': -2,
9611				'p': 1,
9612				'pl': 1
9613			},
9614			prepVersion = function(v) {
9615				v = ('' + v).replace(/[_\-+]/g, '.');
9616				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
9617				return (!v.length ? [-8] : v.split('.'));
9618			},
9619			numVersion = function(v) {
9620				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
9621			};
9622		v1 = prepVersion(v1);
9623		v2 = prepVersion(v2);
9624		x = max(v1.length, v2.length);
9625		for (i = 0; i < x; i++) {
9626			if (v1[i] == v2[i]) {
9627				continue;
9628			}
9629			v1[i] = numVersion(v1[i]);
9630			v2[i] = numVersion(v2[i]);
9631			if (v1[i] < v2[i]) {
9632				compare = -1;
9633				break;
9634			} else if (v1[i] > v2[i]) {
9635				compare = 1;
9636				break;
9637			}
9638		}
9639		if (!operator) {
9640			return compare;
9641		}
9642
9643		switch (operator) {
9644			case '>':
9645			case 'gt':
9646				return (compare > 0);
9647			case '>=':
9648			case 'ge':
9649				return (compare >= 0);
9650			case '<=':
9651			case 'le':
9652				return (compare <= 0);
9653			case '==':
9654			case '=':
9655			case 'eq':
9656				return (compare === 0);
9657			case '<>':
9658			case '!=':
9659			case 'ne':
9660				return (compare !== 0);
9661			case '':
9662			case '<':
9663			case 'lt':
9664				return (compare < 0);
9665			default:
9666				return null;
9667		}
9668	}
9669
9670
9671	// Begin the iLightBox plugin
9672	$.fn.iLightBox = function() {
9673
9674		var args = arguments,
9675			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
9676			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
9677
9678		if (!opt) opt = {};
9679
9680		// Default options. Play carefully.
9681		var options = $.extend(true, {
9682			attr: 'href',
9683			path: 'vertical',
9684			skin: 'dark',
9685			linkId: false,
9686			infinite: false,
9687			startFrom: 0,
9688			randomStart: false,
9689			keepAspectRatio: true,
9690			maxScale: 1,
9691			minScale: .2,
9692			innerToolbar: false,
9693			smartRecognition: false,
9694			mobileOptimizer: true,
9695			fullAlone: true,
9696			fullViewPort: null,
9697			fullStretchTypes: 'flash, video',
9698			overlay: {
9699				blur: true,
9700				opacity: .85
9701			},
9702			controls: {
9703				arrows: false,
9704				slideshow: false,
9705				toolbar: true,
9706				fullscreen: true,
9707				thumbnail: true,
9708				keyboard: true,
9709				mousewheel: true,
9710				swipe: true
9711			},
9712			keyboard: {
9713				left: true, // previous
9714				right: true, // next
9715				up: true, // previous
9716				down: true, // next
9717				esc: true, // close
9718				shift_enter: true // fullscreen
9719			},
9720			show: {
9721				effect: true,
9722				speed: 300,
9723				title: true
9724			},
9725			hide: {
9726				effect: true,
9727				speed: 300
9728			},
9729			caption: {
9730				start: true,
9731				show: 'mouseenter',
9732				hide: 'mouseleave'
9733			},
9734			social: {
9735				start: true,
9736				show: 'mouseenter',
9737				hide: 'mouseleave',
9738				buttons: false
9739			},
9740			styles: {
9741				pageOffsetX: 0,
9742				pageOffsetY: 0,
9743				nextOffsetX: 45,
9744				nextOffsetY: 0,
9745				nextOpacity: 1,
9746				nextScale: 1,
9747				prevOffsetX: 45,
9748				prevOffsetY: 0,
9749				prevOpacity: 1,
9750				prevScale: 1
9751			},
9752			thumbnails: {
9753				maxWidth: 120,
9754				maxHeight: 80,
9755				normalOpacity: 1,
9756				activeOpacity: .6
9757			},
9758			effects: {
9759				reposition: true,
9760				repositionSpeed: 200,
9761				switchSpeed: 500,
9762				loadedFadeSpeed: 180,
9763				fadeSpeed: 200
9764			},
9765			slideshow: {
9766				pauseTime: 5000,
9767				pauseOnHover: false,
9768				startPaused: true
9769			},
9770			text: {
9771				close: "Press Esc to close",
9772				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
9773				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
9774				slideShow: "Slideshow",
9775				next: "Next",
9776				previous: "Previous"
9777			},
9778			errors: {
9779				loadImage: "An error occurred when trying to load photo.",
9780				loadContents: "An error occurred when trying to load contents.",
9781				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
9782			},
9783			ajaxSetup: {
9784				url: '',
9785				beforeSend: function(jqXHR, settings) {},
9786				cache: false,
9787				complete: function(jqXHR, textStatus) {},
9788				crossDomain: false,
9789				error: function(jqXHR, textStatus, errorThrown) {},
9790				success: function(data, textStatus, jqXHR) {},
9791				global: true,
9792				ifModified: false,
9793				username: null,
9794				password: null,
9795				type: 'GET'
9796			},
9797			callback: {}
9798		}, opt);
9799
9800		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
9801
9802		items = $.isArray(items) ? items : new Array();
9803
9804		if (typeof args[0] == 'string') items[0] = args[0];
9805
9806		if (version_compare($.fn.jquery, '1.8', '>=')) {
9807			var iLB = new iLightBox($(this), options, items, instant);
9808			return {
9809				close: function() {
9810					iLB.closeAction();
9811				},
9812				fullscreen: function() {
9813					iLB.fullScreenAction();
9814				},
9815				moveNext: function() {
9816					iLB.moveTo('next');
9817				},
9818				movePrev: function() {
9819					iLB.moveTo('prev');
9820				},
9821				goTo: function(index) {
9822					iLB.goTo(index);
9823				},
9824				refresh: function() {
9825					iLB.refresh();
9826				},
9827				reposition: function() {
9828					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
9829				},
9830				setOption: function(options) {
9831					iLB.setOption(options);
9832				},
9833				destroy: function() {
9834					iLB.closeAction();
9835					iLB.dispatchItemsEvents();
9836				}
9837			};
9838		} else {
9839			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
9840		}
9841
9842	};
9843
9844
9845	$.iLightBox = function() {
9846		return $.fn.iLightBox(arguments[0], arguments[1]);
9847	};
9848
9849
9850	$.extend($.easing, {
9851		easeInCirc: function(x, t, b, c, d) {
9852			return -c * (sqrt(1 - (t /= d) * t) - 1) + b;
9853		},
9854		easeOutCirc: function(x, t, b, c, d) {
9855			return c * sqrt(1 - (t = t / d - 1) * t) + b;
9856		},
9857		easeInOutCirc: function(x, t, b, c, d) {
9858			if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b;
9859			return c / 2 * (sqrt(1 - (t -= 2) * t) + 1) + b;
9860		}
9861	});
9862
9863	function getScrollXY() {
9864		var scrOfX = 0,
9865			scrOfY = 0;
9866		if (typeof(window.pageYOffset) == 'number') {
9867			//Netscape compliant
9868			scrOfY = window.pageYOffset;
9869			scrOfX = window.pageXOffset;
9870		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
9871			//DOM compliant
9872			scrOfY = document.body.scrollTop;
9873			scrOfX = document.body.scrollLeft;
9874		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
9875			//IE6 standards compliant mode
9876			scrOfY = document.documentElement.scrollTop;
9877			scrOfX = document.documentElement.scrollLeft;
9878		}
9879		return {
9880			x: scrOfX,
9881			y: scrOfY
9882		};
9883	}
9884
9885	(function() {
9886		// add new event shortcuts
9887		$.each(("touchstart touchmove touchend " +
9888			"tap taphold " +
9889			"swipe swipeleft swiperight " +
9890			"scrollstart scrollstop").split(" "), function(i, name) {
9891
9892			$.fn[name] = function(fn) {
9893				return fn ? this.bind(name, fn) : this.trigger(name);
9894			};
9895
9896			// jQuery < 1.8
9897			// if ($.attrFn) {
9898			// 	$.attrFn[name] = true;
9899			// }
9900		});
9901
9902		var tapSettings = {
9903			startEvent: 'touchstart.iTap',
9904			endEvent: 'touchend.iTap'
9905		};
9906
9907		// tap Event:
9908		$.event.special.itap = {
9909			setup: function() {
9910
9911				var self = this,
9912					$self = $(this),
9913					start, stop;
9914
9915				$self.bind(tapSettings.startEvent, function(event) {
9916					start = getScrollXY();
9917
9918					$self.one(tapSettings.endEvent, function(event) {
9919						stop = getScrollXY();
9920
9921						var orgEvent = event || window.event;
9922						event = $.event.fix(orgEvent);
9923						event.type = "itap";
9924
9925						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
9926
9927						start = stop = undefined;
9928					});
9929				});
9930			},
9931
9932			teardown: function() {
9933				$(this).unbind(tapSettings.startEvent);
9934			}
9935		};
9936	}());
9937
9938
9939	//Fullscreen API
9940	(function() {
9941		fullScreenApi = {
9942				supportsFullScreen: false,
9943				isFullScreen: function() {
9944					return false;
9945				},
9946				requestFullScreen: function() {},
9947				cancelFullScreen: function() {},
9948				fullScreenEventName: '',
9949				prefix: ''
9950			},
9951			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
9952
9953		// check for native support
9954		if (typeof document.cancelFullScreen != 'undefined') {
9955			fullScreenApi.supportsFullScreen = true;
9956		} else {
9957			// check for fullscreen support by vendor prefix
9958			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
9959				fullScreenApi.prefix = browserPrefixes[i];
9960
9961				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
9962					fullScreenApi.supportsFullScreen = true;
9963
9964					break;
9965				}
9966			}
9967		}
9968
9969		// update methods to do something useful
9970		if (fullScreenApi.supportsFullScreen) {
9971			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
9972
9973			fullScreenApi.isFullScreen = function() {
9974				switch (this.prefix) {
9975					case '':
9976						return document.fullScreen;
9977					case 'webkit':
9978						return document.webkitIsFullScreen;
9979					default:
9980						return document[this.prefix + 'FullScreen'];
9981				}
9982			}
9983			fullScreenApi.requestFullScreen = function(el) {
9984				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
9985			}
9986			fullScreenApi.cancelFullScreen = function(el) {
9987				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
9988			}
9989		}
9990	}());
9991
9992	// Browser detect
9993	(function() {
9994		function uaMatch(ua) {
9995			ua = ua.toLowerCase();
9996
9997			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
9998				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
9999				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
10000				/(msie) ([\w.]+)/.exec(ua) ||
10001				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
10002
10003			return {
10004				browser: match[1] || "",
10005				version: match[2] || "0"
10006			};
10007		}
10008
10009		var matched = uaMatch(navigator.userAgent);
10010		browser = {};
10011
10012		if (matched.browser) {
10013			browser[matched.browser] = true;
10014			browser.version = matched.version;
10015		}
10016
10017		// Chrome is Webkit, but Webkit is also Safari.
10018		if (browser.chrome) {
10019			browser.webkit = true;
10020		} else if (browser.webkit) {
10021			browser.safari = true;
10022		}
10023	}());
10024
10025	// Feature detects
10026	(function() {
10027		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
10028		var el = document.createElement('div');
10029
10030		function testProp(prop) {
10031			for (var p = 0, pl = prefixes.length; p < pl; p++) {
10032				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
10033				if (el.style[prefixedProp] !== undefined) {
10034					return prefixedProp;
10035				}
10036			}
10037		}
10038
10039		// Global support indicators
10040		transform = testProp('transform') || '';
10041		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
10042	}());
10043
10044
10045	/*
10046		PluginDetect v0.7.9
10047		www.pinlady.net/PluginDetect/license/
10048		[ getVersion onWindowLoaded BetterIE ]
10049		[ Flash QuickTime Shockwave ]
10050	*/
10051	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;
10051d++){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);
10051d.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)}
10051c.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;
10051if(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();
10052
10053	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)};
10054
10055
10056	/*
10057		jQuery hashchange event v1.3
10058		https://github.com/cowboy/jquery-hashchange
10059		Copyright (c) 2010 "Cowboy" Ben Alman
10060		Dual licensed under the MIT and GPL licenses.
10061	*/
10062	(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=
10063	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||
10064	"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;
10064a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
10065
10066	if (!Array.prototype.filter) {
10067		Array.prototype.filter = function(fun /*, thisp */ ) {
10068			"use strict";
10069
10070			if (this == null)
10071				throw new TypeError();
10072
10073			var t = Object(this);
10074			var len = t.length >>> 0;
10075			if (typeof fun != "function")
10076				throw new TypeError();
10077
10078			var res = [];
10079			var thisp = arguments[1];
10080			for (var i = 0; i < len; i++) {
10081				if (i in t) {
10082					var val = t[i]; // in case fun mutates this
10083					if (fun.call(thisp, val, i, t))
10084						res.push(val);
10085				}
10086			}
10087
10088			return res;
10089		};
10090	}
10091
10092	if (!Array.prototype.indexOf) {
10093		Array.prototype.indexOf = function(searchElement, fromIndex) {
10094			var k;
10095
10096			if (this == null) {
10097				throw new TypeError('"this" is null or not defined');
10098			}
10099
10100			var O = Object(this);
10101
10102			var len = O.length >>> 0;
10103
10104			if (len === 0) {
10105				return -1;
10106			}
10107
10108			var n = +fromIndex || 0;
10109
10110			if (abs(n) === Infinity) {
10111				n = 0;
10112			}
10113
10114			if (n >= len) {
10115				return -1;
10116			}
10117
10118			k = max(n >= 0 ? n : len - abs(n), 0);
10119
10120			while (k < len) {
10121				var kValue;
10122				if (k in O && O[k] === searchElement) {
10123					return k;
10124				}
10125				k++;
10126			}
10127			return -1;
10128		};
10129	}
10130
10131	if (!Array.prototype.lastIndexOf) {
10132		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
10133			"use strict";
10134
10135			if (this == null)
10136				throw new TypeError();
10137
10138			var t = Object(this);
10139			var len = t.length >>> 0;
10140			if (len === 0)
10141				return -1;
10142
10143			var n = len;
10144			if (arguments.length > 1) {
10145				n = Number(arguments[1]);
10146				if (n != n)
10147					n = 0;
10148				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
10149					n = (n > 0 || -1) * floor(abs(n));
10150			}
10151
10152			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
10153
10154			for (; k >= 0; k--) {
10155				if (k in t && t[k] === searchElement)
10156					return k;
10157			}
10158			return -1;
10159		};
10160	}
10161})(jQuery, this);
10162
10163/**
10164 * Owl carousel
vendor: 12,045 bytes, lines 10165-10670
10165 * @version 2.0.0-beta.3
10166 * @author Bartosz Wojciechowski
10167 * @license The MIT License (MIT)
10168 * @todo Lazy Load Icon
10169 * @todo prevent animationend bubling
10170 * @todo itemsScaleUp
10171 * @todo Test Zepto
10172 * @todo stagePadding calculate wrong active classes
10173 */
10174;(function($, window, document, undefined) {
10175
10176	/**
10177	 * Creates a carousel.
10178	 * @class The Owl Carousel.
10179	 * @public
10180	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
10181	 * @param {Object} [options] - The options
10182	 */
10183	function Owl(element, options) {
10184
10185		/**
10186		 * Current settings for the carousel.
10187		 * @public
10188		 */
10189		this.settings = null;
10190
10191		/**
10192		 * Current options set by the caller including defaults.
10193		 * @public
10194		 */
10195		this.options = $.extend({}, Owl.Defaults, options);
10196
10197		/**
10198		 * Plugin element.
10199		 * @public
10200		 */
10201		this.$element = $(element);
10202
10203		/**
10204		 * Proxied event handlers.
10205		 * @protected
10206		 */
10207		this._handlers = {};
10208
10209		/**
10210		 * References to the running plugins of this carousel.
10211		 * @protected
10212		 */
10213		this._plugins = {};
10214
10215		/**
10216		 * Currently suppressed events to prevent them from beeing retriggered.
10217		 * @protected
10218		 */
10219		this._supress = {};
10220
10221		/**
10222		 * Absolute current position.
10223		 * @protected
10224		 */
10225		this._current = null;
10226
10227		/**
10228		 * Animation speed in milliseconds.
10229		 * @protected
10230		 */
10231		this._speed = null;
10232
10233		/**
10234		 * Coordinates of all items in pixel.
10235		 * @todo The name of this member is missleading.
10236		 * @protected
10237		 */
10238		this._coordinates = [];
10239
10240		/**
10241		 * Current breakpoint.
10242		 * @todo Real media queries would be nice.
10243		 * @protected
10244		 */
10245		this._breakpoint = null;
10246
10247		/**
10248		 * Current width of the plugin element.
10249		 */
10250		this._width = null;
10251
10252		/**
10253		 * All real items.
10254		 * @protected
10255		 */
10256		this._items = [];
10257
10258		/**
10259		 * All cloned items.
10260		 * @protected
10261		 */
10262		this._clones = [];
10263
10264		/**
10265		 * Merge values of all items.
10266		 * @todo Maybe this could be part of a plugin.
10267		 * @protected
10268		 */
10269		this._mergers = [];
10270
10271		/**
10272		 * Widths of all items.
10273		 */
10274		this._widths = [];
10275
10276		/**
10277		 * Invalidated parts within the update process.
10278		 * @protected
10279		 */
10280		this._invalidated = {};
10281
10282		/**
10283		 * Ordered list of workers for the update process.
10284		 * @protected
10285		 */
10286		this._pipe = [];
10287
10288		/**
10289		 * Current state information for the drag operation.
10290		 * @todo #261
10291		 * @protected
10292		 */
10293		this._drag = {
10294			time: null,
10295			target: null,
10296			pointer: null,
10297			stage: {
10298				start: null,
10299				current: null
10300			},
10301			direction: null
10302		};
10303
10304		/**
10305		 * Current state information and their tags.
10306		 * @type {Object}
10307		 * @protected
10308		 */
10309		this._states = {
10310			current: {},
10311			tags: {
10312				'initializing': [ 'busy' ],
10313				'animating': [ 'busy' ],
10314				'dragging': [ 'interacting' ]
10315			}
10316		};
10317
10318		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
10319			this._handlers[handler] = $.proxy(this[handler], this);
10320		}, this));
10321
10322		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
10323			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
10324				= new plugin(this);
10325		}, this));
10326
10327		$.each(Owl.Workers, $.proxy(function(priority, worker) {
10328			this._pipe.push({
10329				'filter': worker.filter,
10330				'run': $.proxy(worker.run, this)
10331			});
10332		}, this));
10333
10334		this.setup();
10335		this.initialize();
10336	}
10337
10338	/**
10339	 * Default options for the carousel.
10340	 * @public
10341	 */
10342	Owl.Defaults = {
10343		items: 3,
10344		loop: false,
10345		center: false,
10346		rewind: false,
10347
10348		mouseDrag: true,
10349		touchDrag: true,
10350		pullDrag: true,
10351		freeDrag: false,
10352
10353		margin: 0,
10354		stagePadding: 0,
10355
10356		merge: false,
10357		mergeFit: true,
10358		autoWidth: false,
10359
10360		startPosition: 0,
10361		rtl: false,
10362
10363		smartSpeed: 250,
10364		fluidSpeed: false,
10365		dragEndSpeed: false,
10366
10367		responsive: {},
10368		responsiveRefreshRate: 200,
10369		responsiveBaseElement: window,
10370
10371		fallbackEasing: 'swing',
10372
10373		info: false,
10374
10375		nestedItemSelector: false,
10376		itemElement: 'div',
10377		stageElement: 'div',
10378
10379		refreshClass: 'owl-refresh',
10380		loadedClass: 'owl-loaded',
10381		loadingClass: 'owl-loading',
10382		rtlClass: 'owl-rtl',
10383		responsiveClass: 'owl-responsive',
10384		dragClass: 'owl-drag',
10385		itemClass: 'owl-item',
10386		stageClass: 'owl-stage',
10387		stageOuterClass: 'owl-stage-outer',
10388		grabClass: 'owl-grab'
10389	};
10390
10391	/**
10392	 * Enumeration for width.
10393	 * @public
10394	 * @readonly
10395	 * @enum {String}
10396	 */
10397	Owl.Width = {
10398		Default: 'default',
10399		Inner: 'inner',
10400		Outer: 'outer'
10401	};
10402
10403	/**
10404	 * Enumeration for types.
10405	 * @public
10406	 * @readonly
10407	 * @enum {String}
10408	 */
10409	Owl.Type = {
10410		Event: 'event',
10411		State: 'state'
10412	};
10413
10414	/**
10415	 * Contains all registered plugins.
10416	 * @public
10417	 */
10418	Owl.Plugins = {};
10419
10420	/**
10421	 * List of workers involved in the update process.
10422	 */
10423	Owl.Workers = [ {
10424		filter: [ 'width', 'settings' ],
10425		run: function() {
10426			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
10427			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
10428		}
10429	}, {
10430		filter: [ 'width', 'items', 'settings' ],
10431		run: function(cache) {
10432			cache.current = this._items && this._items[this.relative(this._current)];
10433		}
10434	}, {
10435		filter: [ 'items', 'settings' ],
10436		run: function() {
10437			this.$stage.children('.cloned').remove();
10438		}
10439	}, {
10440		filter: [ 'width', 'items', 'settings' ],
10441		run: function(cache) {
10442			var margin = this.settings.margin || '',
10443				grid = !this.settings.autoWidth,
10444				rtl = this.settings.rtl,
10445				css = {
10446					'width': 'auto',
10447					'margin-left': rtl ? margin : '',
10448					'margin-right': rtl ? '' : margin
10449				};
10450
10451			!grid && this.$stage.children().css(css);
10452
10453			cache.css = css;
10454		}
10455	}, {
10456		filter: [ 'width', 'items', 'settings' ],
10457		run: function(cache) {
10458			var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
10459				merge = null,
10460				iterator = this._items.length,
10461				grid = !this.settings.autoWidth,
10462				widths = [];
10463
10464			cache.items = {
10465				merge: false,
10466				width: width
10467			};
10468
10469			while (iterator--) {
10470				merge = this._mergers[iterator];
10471				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
10472
10473				cache.items.merge = merge > 1 || cache.items.merge;
10474
10475				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
10476			}
10477
10478			this._widths = widths;
10479		}
10480	}, {
10481		filter: [ 'items', 'settings' ],
10482		run: function() {
10483			var clones = [],
10484				items = this._items,
10485				settings = this.settings,
10486				view = Math.max(settings.items * 2, 4),
10487				size = Math.ceil(items.length / 2) * 2,
10488				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
10489				append = '',
10490				prepend = '';
10491
10492			repeat /= 2;
10493
10494			while (repeat--) {
10495				clones.push(this.normalize(clones.length / 2, true));
10496				append = append + items[clones[clones.length - 1]][0].outerHTML;
10497				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
10498				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
10499			}
10500
10501			this._clones = clones;
10502
10503			// var appendVideo = $(append).find('.uncode-video-container');
10504			// if (appendVideo.length) {
10505			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
10506			// }
10507			// var prependVideo = $(prepend).find('.uncode-video-container');
10508			// if (prependVideo.length) {
10509			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
10510			// }
10511			$(append).addClass('cloned').appendTo(this.$stage);
10512			$(prepend).addClass('cloned').prependTo(this.$stage);
10513		}
10514	}, {
10515		filter: [ 'width', 'items', 'settings' ],
10516		run: function() {
10517			var rtl = this.settings.rtl ? 1 : -1,
10518				size = this._clones.length + this._items.length,
10519				iterator = -1,
10520				previous = 0,
10521				current = 0,
10522				coordinates = [];
10523
10524			while (++iterator < size) {
10525				previous = coordinates[iterator - 1] || 0;
10526				current = this._widths[this.relative(iterator)] + this.settings.margin;
10527				coordinates.push(previous + current * rtl);
10528			}
10529
10530			this._coordinates = coordinates;
10531		}
10532	}, {
10533		filter: [ 'width', 'items', 'settings' ],
10534		run: function() {
10535			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
10536				padding = stagePadding,
10537				coordinates = this._coordinates,
10538				css = {
10539					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
10540					'padding-left': padding || '',
10541					'padding-right': padding || ''
10542				};
10543
10544			this.$stage.css(css);
10545		}
10546	}, {
10547		filter: [ 'width', 'items', 'settings' ],
10548		run: function(cache) {
10549			var iterator = this._coordinates.length,
10550				grid = !this.settings.autoWidth,
10551				items = this.$stage.children();
10552
10553			if (grid && cache.items.merge) {
10554				while (iterator--) {
10555					cache.css.width = this._widths[this.relative(iterator)];
10556					items.eq(iterator).css(cache.css);
10557				}
10558			} else if (grid) {
10559				cache.css.width = cache.items.width;
10560				items.css(cache.css);
10561			}
10562		}
10563	}, {
10564		filter: [ 'items' ],
10565		run: function() {
10566			this._coordinates.length < 1 && this.$stage.removeAttr('style');
10567		}
10568	}, {
10569		filter: [ 'width', 'items', 'settings' ],
10570		run: function(cache) {
10571			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
10572			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
10573			this.reset(cache.current);
10574		}
10575	}, {
10576		filter: [ 'position' ],
10577		run: function() {
10578			this.animate(this.coordinates(this._current));
10579		}
10580	}, {
10581		filter: [ 'width', 'position', 'items', 'settings' ],
10582		run: function() {
10583			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
10584				rtl = this.settings.rtl ? 1 : -1,
10585				padding = this.settings.stagePadding * 2,
10586				begin = this.coordinates(this.current()) + padding,
10587				end = begin + this.width() * rtl,
10588				inner, outer, matches = [], i, n;
10589
10590			for (i = 0, n = this._coordinates.length; i < n; i++) {
10591				inner = this._coordinates[i - 1] || 0;
10592				outer = Math.abs(this._coordinates[i]) + padding * rtl;
10593
10594				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
10595					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
10596					matches.push(i);
10597				}
10598			}
10599
10600			this.$stage.children('.active').removeClass('active');
10601			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
10602
10603			if (this.settings.center) {
10604				this.$stage.children('.center').removeClass('center');
10605				this.$stage.children().eq(this.current()).addClass('center');
10606			}
10607		}
10608	} ];
10609
10610	/**
10611	 * Initializes the carousel.
10612	 * @protected
10613	 */
10614	Owl.prototype.initialize = function() {
10615		this.enter('initializing');
10616		this.trigger('initialize');
10617
10618		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
10619
10620		if (this.settings.autoWidth && !this.is('pre-loading')) {
10621			var imgs, nestedSelector, width;
10622			imgs = this.$element.find('img');
10623			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
10624			width = this.$element.children(nestedSelector).width();
10625
10626			if (imgs.length && width <= 0) {
10627				this.preloadAutoWidthImages(imgs);
10628			}
10629		}
10630
10631		this.$element.addClass(this.options.loadingClass);
10632
10633		// create stage
10634		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
10635			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
10636
10637		// append stage
10638		this.$element.append(this.$stage.parent());
10639
10640		// append content
10641		this.replace(this.$element.children().not(this.$stage.parent()));
10642
10643		// check visibility
10644		if (this.$element.is(':visible')) {
10645			// update view
10646			this.refresh();
10647		} else {
10648			// invalidate width
10649			this.invalidate('width');
10650		}
10651
10652		this.$element
10653			.removeClass(this.options.loadingClass)
10654			.addClass(this.options.loadedClass);
10655
10656		// register event handlers
10657		this.registerEventHandlers();
10658
10659		this.leave('initializing');
10660		this.trigger('initialized');
10661	};
10662
10663	/**
10664	 * Setups the current settings.
10665	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
10666	 * @todo Support for media queries by using `matchMedia` would be nice.
10667	 * @public
10668	 */
10669	Owl.prototype.setup = function() {
10670		var viewport = this.viewport(),
10671			overwrites = this.options.responsive,
10672			match = -1,
10673			settings = null;
10674
10675		if (!overwrites) {
10676			settings = $.extend({}, this.options);
10677		} else {
10678			$.each(overwrites, function(breakpoint) {
10679				if (breakpoint <= viewport && breakpoint > match) {
10680					match = Number(breakpoint);
10681				}
10682			});
10683
10684			settings = $.extend({}, this.options, overwrites[match]);
10685			delete settings.responsive;
10686
10687			// responsive class
10688			if (settings.responsiveClass) {
10689				this.$element.attr('class',
10690					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
10691				);
10692			}
10693		}
10694
10695		if (this.settings === null || this._breakpoint !== match) {
10696			this.trigger('change', { property: { name: 'settings', value: settings } });
10697			this._breakpoint = match;
10698			this.settings = settings;
10699			this.invalidate('settings');
10700			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
10701		}
10702	};
10703
10704	/**
10705	 * Updates option logic if necessery.
10706	 * @protected
10707	 */
10708	Owl.prototype.optionsLogic = function() {
10709		if (this.settings.autoWidth) {
10710			this.settings.stagePadding = false;
10711			this.settings.merge = false;
10712		}
10713	};
10714
10715	/**
10716	 * Prepares an item before add.
10717	 * @todo Rename event parameter `content` to `item`.
10718	 * @protected
10719	 * @returns {jQuery|HTMLElement} - The item container.
10720	 */
10721	Owl.prototype.prepare = function(item, index) {
10722		var event = this.trigger('prepare', { content: item });
10723		if (!event.data) {
10724			event.data = $('<' + this.settings.itemElement + '/>')
10725				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
10726		}
10727
10728		this.trigger('prepared', { content: event.data });
10729
10730		return event.data;
10731	};
10732
10733	/**
10734	 * Updates the view.
10735	 * @public
10736	 */
10737	Owl.prototype.update = function() {
10738		var i = 0,
10739			n = this._pipe.length,
10740			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
10741			cache = {};
10742
10743		while (i < n) {
10744			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
10745				this._pipe[i].run(cache);
10746			}
10747			i++;
10748		}
10749
10750		this._invalidated = {};
10751
10752		!this.is('valid') && this.enter('valid');
10753	};
10754
10755	/**
10756	 * Gets the width of the view.
10757	 * @public
10758	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
10759	 * @returns {Number} - The width of the view in pixel.
10760	 */
10761	Owl.prototype.width = function(dimension) {
10762		dimension = dimension || Owl.Width.Default;
10763		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
10764		switch (dimension) {
10765			case Owl.Width.Inner:
10766			case Owl.Width.Outer:
10767				return this._width;
10768			default:
10769				return this._width - stagePadding * 2 + this.settings.margin;
10770		}
10771	};
10772
10773	/**
10774	 * Refreshes the carousel primarily for adaptive purposes.
10775	 * @public
10776	 */
10777	Owl.prototype.refresh = function() {
10778		this.enter('refreshing');
10779		this.trigger('refresh');
10780
10781		this.setup();
10782
10783		this.optionsLogic();
10784
10785		this.$element.addClass(this.options.refreshClass);
10786
10787		this.update();
10788
10789		this.$element.removeClass(this.options.refreshClass);
10790
10791		this.leave('refreshing');
10792		this.trigger('refreshed');
10793	};
10794
10795	/**
10796	 * Checks window `resize` event.
10797	 * @protected
10798	 */
10799	Owl.prototype.onThrottledResize = function() {
10800		window.clearTimeout(this.resizeTimer);
10801		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
10802	};
10803
10804	/**
10805	 * Checks window `resize` event.
10806	 * @protected
10807	 */
10808	Owl.prototype.onResize = function() {
10809		if (!this._items.length) {
10810			return false;
10811		}
10812
10813		if (this._width === this.$element.width()) {
10814			return false;
10815		}
10816
10817		if (!this.$element.is(':visible')) {
10818			return false;
10819		}
10820
10821		this.enter('resizing');
10822
10823		if (this.trigger('resize').isDefaultPrevented()) {
10824			this.leave('resizing');
10825			return false;
10826		}
10827
10828		this.invalidate('width');
10829
10830		this.refresh();
10831
10832		this.leave('resizing');
10833		this.trigger('resized');
10834	};
10835
10836	/**
10837	 * Registers event handlers.
10838	 * @todo Check `msPointerEnabled`
10839	 * @todo #261
10840	 * @protected
10841	 */
10842	Owl.prototype.registerEventHandlers = function() {
10843		if ($.support.transition) {
10844			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
10845		}
10846
10847		if (this.settings.responsive !== false) {
10848			this.on(window, 'resize', this._handlers.onThrottledResize);
10849		}
10850
10851		if (this.settings.mouseDrag) {
10852			this.$element.addClass(this.options.dragClass);
10853			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
10854			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
10855		}
10856
10857		if (this.settings.touchDrag){
10858			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
10859			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
10860		}
10861	};
10862
10863	/**
10864	 * Handles `touchstart` and `mousedown` events.
10865	 * @todo Horizontal swipe threshold as option
10866	 * @todo #261
10867	 * @protected
10868	 * @param {Event} event - The event arguments.
10869	 */
10870	Owl.prototype.onDragStart = function(event) {
10871		var stage = null;
10872
10873		if (event.which === 3) {
10874			return;
10875		}
10876
vendor: 14,340 bytes, lines 10877-11367
10877		if ($.support.transform) {
10878			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
10879			stage = {
10880				x: stage[stage.length === 16 ? 12 : 4],
10881				y: stage[stage.length === 16 ? 13 : 5]
10882			};
10883		} else {
10884			stage = this.$stage.position();
10885			stage = {
10886				x: this.settings.rtl ?
10887					stage.left + this.$stage.width() - this.width() + this.settings.margin :
10888					stage.left,
10889				y: stage.top
10890			};
10891		}
10892
10893		if (this.is('animating')) {
10894			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
10895			this.invalidate('position');
10896		}
10897
10898		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
10899
10900		this.speed(0);
10901
10902		this._drag.time = new Date().getTime();
10903		this._drag.target = $(event.target);
10904		this._drag.stage.start = stage;
10905		this._drag.stage.current = stage;
10906		this._drag.pointer = this.pointer(event);
10907
10908		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
10909
10910		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
10911			var delta = this.difference(this._drag.pointer, this.pointer(event));
10912
10913			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
10914
10915			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
10916				return;
10917			}
10918
10919			event.preventDefault();
10920
10921			this.enter('dragging');
10922			this.trigger('drag');
10923		}, this));
10924	};
10925
10926	/**
10927	 * Handles the `touchmove` and `mousemove` events.
10928	 * @todo #261
10929	 * @protected
10930	 * @param {Event} event - The event arguments.
10931	 */
10932	Owl.prototype.onDragMove = function(event) {
10933		var minimum = null,
10934			maximum = null,
10935			pull = null,
10936			delta = this.difference(this._drag.pointer, this.pointer(event)),
10937			stage = this.difference(this._drag.stage.start, delta);
10938
10939		if (!this.is('dragging')) {
10940			return;
10941		}
10942
10943		event.preventDefault();
10944
10945		if (this.settings.loop) {
10946			minimum = this.coordinates(this.minimum());
10947			maximum = this.coordinates(this.maximum() + 1) - minimum;
10948			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
10949		} else {
10950			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
10951			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
10952			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
10953			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
10954		}
10955
10956		this._drag.stage.current = stage;
10957
10958		this.animate(stage.x);
10959	};
10960
10961	/**
10962	 * Handles the `touchend` and `mouseup` events.
10963	 * @todo #261
10964	 * @todo Threshold for click event
10965	 * @protected
10966	 * @param {Event} event - The event arguments.
10967	 */
10968	Owl.prototype.onDragEnd = function(event) {
10969		var delta = this.difference(this._drag.pointer, this.pointer(event)),
10970			stage = this._drag.stage.current,
10971			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
10972
10973		$(document).off('.owl.core');
10974
10975		this.$element.removeClass(this.options.grabClass);
10976
10977		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
10978			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
10979			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
10980			this.invalidate('position');
10981			this.update();
10982
10983			this._drag.direction = direction;
10984
10985			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
10986				this._drag.target.one('click.owl.core', function() { return false; });
10987			}
10988		}
10989
10990		if (!this.is('dragging')) {
10991			return;
10992		}
10993
10994		this.leave('dragging');
10995		this.trigger('dragged');
10996	};
10997
10998	/**
10999	 * Gets absolute position of the closest item for a coordinate.
11000	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
11001	 * @protected
11002	 * @param {Number} coordinate - The coordinate in pixel.
11003	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
11004	 * @return {Number} - The absolute position of the closest item.
11005	 */
11006	Owl.prototype.closest = function(coordinate, direction) {
11007		var position = -1,
11008			pull = 30,
11009			width = this.width(),
11010			coordinates = this.coordinates();
11011
11012		if (!this.settings.freeDrag) {
11013			// check closest item
11014			$.each(coordinates, $.proxy(function(index, value) {
11015				if (coordinate > value - pull && coordinate < value + pull) {
11016					position = index;
11017				} else if (this.op(coordinate, '<', value)
11018					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
11019					position = direction === 'left' ? index + 1 : index;
11020				}
11021				return position === -1;
11022			}, this));
11023		}
11024
11025		if (!this.settings.loop) {
11026			// non loop boundries
11027			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
11028				position = coordinate = this.minimum();
11029			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
11030				position = coordinate = this.maximum();
11031			}
11032		}
11033
11034		return position;
11035	};
11036
11037	/**
11038	 * Animates the stage.
11039	 * @todo #270
11040	 * @public
11041	 * @param {Number} coordinate - The coordinate in pixels.
11042	 */
11043	Owl.prototype.animate = function(coordinate) {
11044		var animate = this.speed() > 0;
11045
11046		this.is('animating') && this.onTransitionEnd();
11047
11048		if (animate) {
11049			this.enter('animating');
11050			this.trigger('translate');
11051		}
11052
11053		if ($.support.transform3d && $.support.transition) {
11054			this.$stage.css({
11055				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
11056				transition: (this.speed() / 1000) + 's'
11057			});
11058		} else if (animate) {
11059			this.$stage.animate({
11060				left: coordinate + 'px'
11061			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
11062		} else {
11063			this.$stage.css({
11064				left: coordinate + 'px'
11065			});
11066		}
11067	};
11068
11069	/**
11070	 * Checks whether the carousel is in a specific state or not.
11071	 * @param {String} state - The state to check.
11072	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
11073	 */
11074	Owl.prototype.is = function(state) {
11075		return this._states.current[state] && this._states.current[state] > 0;
11076	};
11077
11078	/**
11079	 * Sets the absolute position of the current item.
11080	 * @public
11081	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
11082	 * @returns {Number} - The absolute position of the current item.
11083	 */
11084	Owl.prototype.current = function(position) {
11085		if (position === undefined) {
11086			return this._current;
11087		}
11088
11089		if (this._items.length === 0) {
11090			return undefined;
11091		}
11092
11093		position = this.normalize(position);
11094
11095		if (this._current !== position) {
11096			var event = this.trigger('change', { property: { name: 'position', value: position } });
11097
11098			if (event.data !== undefined) {
11099				position = this.normalize(event.data);
11100			}
11101
11102			this._current = position;
11103
11104			this.invalidate('position');
11105
11106			this.trigger('changed', { property: { name: 'position', value: this._current } });
11107		}
11108
11109		return this._current;
11110	};
11111
11112	/**
11113	 * Invalidates the given part of the update routine.
11114	 * @param {String} [part] - The part to invalidate.
11115	 * @returns {Array.<String>} - The invalidated parts.
11116	 */
11117	Owl.prototype.invalidate = function(part) {
11118		if ($.type(part) === 'string') {
11119			this._invalidated[part] = true;
11120			this.is('valid') && this.leave('valid');
11121		}
11122		return $.map(this._invalidated, function(v, i) { return i });
11123	};
11124
11125	/**
11126	 * Resets the absolute position of the current item.
11127	 * @public
11128	 * @param {Number} position - The absolute position of the new item.
11129	 */
11130	Owl.prototype.reset = function(position) {
11131		position = this.normalize(position);
11132
11133		if (position === undefined) {
11134			return;
11135		}
11136
11137		this._speed = 0;
11138		this._current = position;
11139
11140		this.suppress([ 'translate', 'translated' ]);
11141
11142		this.animate(this.coordinates(position));
11143
11144		this.release([ 'translate', 'translated' ]);
11145	};
11146
11147	/**
11148	 * Normalizes an absolute or a relative position of an item.
11149	 * @public
11150	 * @param {Number} position - The absolute or relative position to normalize.
11151	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
11152	 * @returns {Number} - The normalized position.
11153	 */
11154	Owl.prototype.normalize = function(position, relative) {
11155		var n = this._items.length,
11156			m = relative ? 0 : this._clones.length;
11157
11158		if (!$.isNumeric(position) || n < 1) {
11159			position = undefined;
11160		} else if (position < 0 || position >= n + m) {
11161			position = ((position - m / 2) % n + n) % n + m / 2;
11162		}
11163
11164		return position;
11165	};
11166
11167	/**
11168	 * Converts an absolute position of an item into a relative one.
11169	 * @public
11170	 * @param {Number} position - The absolute position to convert.
11171	 * @returns {Number} - The converted position.
11172	 */
11173	Owl.prototype.relative = function(position) {
11174		position -= this._clones.length / 2;
11175		return this.normalize(position, true);
11176	};
11177
11178	/**
11179	 * Gets the maximum position for the current item.
11180	 * @public
11181	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
11182	 * @returns {Number}
11183	 */
11184	Owl.prototype.maximum = function(relative) {
11185		var settings = this.settings,
11186			maximum = this._coordinates.length,
11187			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
11188			i = -1, j;
11189
11190		if (settings.loop) {
11191			maximum = this._clones.length / 2 + this._items.length - 1;
11192		} else if (settings.autoWidth || settings.merge) {
11193			// binary search
11194			while (maximum - i > 1) {
11195				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
11196					? i = j : maximum = j;
11197			}
11198		} else if (settings.center) {
11199			maximum = this._items.length - 1;
11200		} else {
11201			maximum = this._items.length - settings.items;
11202		}
11203
11204		if (relative) {
11205			maximum -= this._clones.length / 2;
11206		}
11207
11208		return Math.max(maximum, 0);
11209	};
11210
11211	/**
11212	 * Gets the minimum position for the current item.
11213	 * @public
11214	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
11215	 * @returns {Number}
11216	 */
11217	Owl.prototype.minimum = function(relative) {
11218		return relative ? 0 : this._clones.length / 2;
11219	};
11220
11221	/**
11222	 * Gets an item at the specified relative position.
11223	 * @public
11224	 * @param {Number} [position] - The relative position of the item.
11225	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
11226	 */
11227	Owl.prototype.items = function(position) {
11228		if (position === undefined) {
11229			return this._items.slice();
11230		}
11231
11232		position = this.normalize(position, true);
11233		return this._items[position];
11234	};
11235
11236	/**
11237	 * Gets an item at the specified relative position.
11238	 * @public
11239	 * @param {Number} [position] - The relative position of the item.
11240	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
11241	 */
11242	Owl.prototype.mergers = function(position) {
11243		if (position === undefined) {
11244			return this._mergers.slice();
11245		}
11246
11247		position = this.normalize(position, true);
11248		return this._mergers[position];
11249	};
11250
11251	/**
11252	 * Gets the absolute positions of clones for an item.
11253	 * @public
11254	 * @param {Number} [position] - The relative position of the item.
11255	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
11256	 */
11257	Owl.prototype.clones = function(position) {
11258		var odd = this._clones.length / 2,
11259			even = odd + this._items.length,
11260			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
11261
11262		if (position === undefined) {
11263			return $.map(this._clones, function(v, i) { return map(i) });
11264		}
11265
11266		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
11267	};
11268
11269	/**
11270	 * Sets the current animation speed.
11271	 * @public
11272	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
11273	 * @returns {Number} - The current animation speed in milliseconds.
11274	 */
11275	Owl.prototype.speed = function(speed) {
11276		if (speed !== undefined) {
11277			this._speed = speed;
11278		}
11279
11280		return this._speed;
11281	};
11282
11283	/**
11284	 * Gets the coordinate of an item.
11285	 * @todo The name of this method is missleanding.
11286	 * @public
11287	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
11288	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
11289	 */
11290	Owl.prototype.coordinates = function(position) {
11291		var coordinate = null;
11292
11293		if (position === undefined) {
11294			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
11295				return this.coordinates(index);
11296			}, this));
11297		}
11298
11299		if (this.settings.center) {
11300			coordinate = this._coordinates[position];
11301			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
11302		} else {
11303			coordinate = this._coordinates[position - 1] || 0;
11304		}
11305
11306		return coordinate;
11307	};
11308
11309	/**
11310	 * Calculates the speed for a translation.
11311	 * @protected
11312	 * @param {Number} from - The absolute position of the start item.
11313	 * @param {Number} to - The absolute position of the target item.
11314	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
11315	 * @returns {Number} - The time in milliseconds for the translation.
11316	 */
11317	Owl.prototype.duration = function(from, to, factor) {
11318		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
11319	};
11320
11321	/**
11322	 * Slides to the specified item.
11323	 * @public
11324	 * @param {Number} position - The position of the item.
11325	 * @param {Number} [speed] - The time in milliseconds for the transition.
11326	 */
11327	Owl.prototype.to = function(position, speed) {
11328		var current = this.current(),
11329			revert = null,
11330			distance = position - this.relative(current),
11331			direction = (distance > 0) - (distance < 0),
11332			items = this._items.length,
11333			minimum = this.minimum(),
11334			maximum = this.maximum();
11335
11336		if (this.settings.loop) {
11337			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
11338				distance += direction * -1 * items;
11339			}
11340
11341			position = current + distance;
11342			revert = ((position - minimum) % items + items) % items + minimum;
11343
11344			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
11345				current = revert - distance;
11346				position = revert;
11347				this.reset(current);
11348			}
11349		} else if (this.settings.rewind) {
11350			maximum += 1;
11351			position = (position % maximum + maximum) % maximum;
11352		} else {
11353			position = Math.max(minimum, Math.min(maximum, position));
11354		}
11355
11356		this.speed(this.duration(current, position, speed));
11357		this.current(position);
11358
11359		if (this.$element.is(':visible')) {
11360			this.update();
11361		}
11362	};
11363
11364	/**
11365	 * Slides to the next item.
11366	 * @public
11367	 * @param {Number}
vendor: 4,086 bytes, lines 11367-11503
11367 [speed] - The time in milliseconds for the transition.
11368	 */
11369	Owl.prototype.next = function(speed) {
11370		speed = speed || false;
11371		this.to(this.relative(this.current()) + 1, speed);
11372	};
11373
11374	/**
11375	 * Slides to the previous item.
11376	 * @public
11377	 * @param {Number} [speed] - The time in milliseconds for the transition.
11378	 */
11379	Owl.prototype.prev = function(speed) {
11380		speed = speed || false;
11381		this.to(this.relative(this.current()) - 1, speed);
11382	};
11383
11384	/**
11385	 * Handles the end of an animation.
11386	 * @protected
11387	 * @param {Event} event - The event arguments.
11388	 */
11389	Owl.prototype.onTransitionEnd = function(event) {
11390
11391		// if css2 animation then event object is undefined
11392		if (event !== undefined) {
11393			event.stopPropagation();
11394
11395			// Catch only owl-stage transitionEnd event
11396			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
11397				return false;
11398			}
11399		}
11400
11401		this.leave('animating');
11402		this.trigger('translated');
11403	};
11404
11405	/**
11406	 * Gets viewport width.
11407	 * @protected
11408	 * @return {Number} - The width in pixel.
11409	 */
11410	Owl.prototype.viewport = function() {
11411		var width;
11412		if (this.options.responsiveBaseElement !== window) {
11413			width = $(this.options.responsiveBaseElement).width();
11414		} else if (window.innerWidth) {
11415			width = window.innerWidth;
11416		} else if (document.documentElement && document.documentElement.clientWidth) {
11417			width = document.documentElement.clientWidth;
11418		} else {
11419			throw 'Can not detect viewport width.';
11420		}
11421
11422		return width;
11423	};
11424
11425	/**
11426	 * Replaces the current content.
11427	 * @public
11428	 * @param {HTMLElement|jQuery|String} content - The new content.
11429	 */
11430	Owl.prototype.replace = function(content) {
11431		this.$stage.empty();
11432		this._items = [];
11433
11434		if (content) {
11435			content = (content instanceof jQuery) ? content : $(content);
11436		}
11437
11438		if (this.settings.nestedItemSelector) {
11439			content = content.find('.' + this.settings.nestedItemSelector);
11440		}
11441
11442		content.filter(function() {
11443			return this.nodeType === 1;
11444		}).each($.proxy(function(index, item) {
11445			item = this.prepare(item, index);
11446			this.$stage.append(item);
11447			this._items.push(item);
11448			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
11449		}, this));
11450
11451		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
11452
11453		this.invalidate('items');
11454	};
11455
11456	/**
11457	 * Adds an item.
11458	 * @todo Use `item` instead of `content` for the event arguments.
11459	 * @public
11460	 * @param {HTMLElement|jQuery|String} content - The item content to add.
11461	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
11462	 */
11463	Owl.prototype.add = function(content, position) {
11464		var current = this.relative(this._current);
11465
11466		position = position === undefined ? this._items.length : this.normalize(position, true);
11467		content = content instanceof jQuery ? content : $(content);
11468
11469		this.trigger('add', { content: content, position: position });
11470
11471		content = this.prepare(content, this._items[current].index());
11472
11473		if (this._items.length === 0 || position === this._items.length) {
11474			this._items.length === 0 && this.$stage.append(content);
11475			this._items.length !== 0 && this._items[position - 1].after(content);
11476			this._items.push(content);
11477			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
11478		} else {
11479			this._items[position].before(content);
11480			this._items.splice(position, 0, content);
11481			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
11482		}
11483
11484		this._items[current] && this.reset(this._items[current].index());
11485
11486		this.invalidate('items');
11487
11488		this.trigger('added', { content: content, position: position });
11489	};
11490
11491	/**
11492	 * Removes an item by its position.
11493	 * @todo Use `item` instead of `content` for the event arguments.
11494	 * @public
11495	 * @param {Number} position - The relative position of the item to remove.
11496	 */
11497	Owl.prototype.remove = function(position) {
11498		position = this.normalize(position, true);
11499
11500		if (position === undefined) {
11501			return;
11502		}
11503
vendor: 40,414 bytes, lines 11504-13070
11504		this.trigger('remove', { content: this._items[position], position: position });
11505
11506		this._items[position].remove();
11507		this._items.splice(position, 1);
11508		this._mergers.splice(position, 1);
11509
11510		this.invalidate('items');
11511
11512		this.trigger('removed', { content: null, position: position });
11513	};
11514
11515	/**
11516	 * Preloads images with auto width.
11517	 * @todo Replace by a more generic approach
11518	 * @protected
11519	 */
11520	Owl.prototype.preloadAutoWidthImages = function(images) {
11521		images.each($.proxy(function(i, element) {
11522			this.enter('pre-loading');
11523			element = $(element);
11524			$(new Image()).one('load', $.proxy(function(e) {
11525				element.attr('src', e.target.src);
11526				element.css('opacity', 1);
11527				this.leave('pre-loading');
11528				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
11529			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
11530		}, this));
11531	};
11532
11533	/**
11534	 * Destroys the carousel.
11535	 * @public
11536	 */
11537	Owl.prototype.destroy = function() {
11538
11539		this.$element.off('.owl.core');
11540		this.$stage.off('.owl.core');
11541		$(document).off('.owl.core');
11542
11543		if (this.settings.responsive !== false) {
11544			window.clearTimeout(this.resizeTimer);
11545			this.off(window, 'resize', this._handlers.onThrottledResize);
11546		}
11547
11548		for (var i in this._plugins) {
11549			this._plugins[i].destroy();
11550		}
11551
11552		this.$stage.children('.cloned').remove();
11553
11554		this.$stage.unwrap();
11555		this.$stage.children().contents().unwrap();
11556		this.$stage.children().unwrap();
11557
11558		this.$element
11559			.removeClass(this.options.refreshClass)
11560			.removeClass(this.options.loadingClass)
11561			.removeClass(this.options.loadedClass)
11562			.removeClass(this.options.rtlClass)
11563			.removeClass(this.options.dragClass)
11564			.removeClass(this.options.grabClass)
11565			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
11566			.removeData('owl.carousel');
11567	};
11568
11569	/**
11570	 * Operators to calculate right-to-left and left-to-right.
11571	 * @protected
11572	 * @param {Number} [a] - The left side operand.
11573	 * @param {String} [o] - The operator.
11574	 * @param {Number} [b] - The right side operand.
11575	 */
11576	Owl.prototype.op = function(a, o, b) {
11577		var rtl = this.settings.rtl;
11578		switch (o) {
11579			case '<':
11580				return rtl ? a > b : a < b;
11581			case '>':
11582				return rtl ? a < b : a > b;
11583			case '>=':
11584				return rtl ? a <= b : a >= b;
11585			case '<=':
11586				return rtl ? a >= b : a <= b;
11587			default:
11588				break;
11589		}
11590	};
11591
11592	/**
11593	 * Attaches to an internal event.
11594	 * @protected
11595	 * @param {HTMLElement} element - The event source.
11596	 * @param {String} event - The event name.
11597	 * @param {Function} listener - The event handler to attach.
11598	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
11599	 */
11600	Owl.prototype.on = function(element, event, listener, capture) {
11601		if (element.addEventListener) {
11602			element.addEventListener(event, listener, capture);
11603		} else if (element.attachEvent) {
11604			element.attachEvent('on' + event, listener);
11605		}
11606	};
11607
11608	/**
11609	 * Detaches from an internal event.
11610	 * @protected
11611	 * @param {HTMLElement} element - The event source.
11612	 * @param {String} event - The event name.
11613	 * @param {Function} listener - The attached event handler to detach.
11614	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
11615	 */
11616	Owl.prototype.off = function(element, event, listener, capture) {
11617		if (element.removeEventListener) {
11618			element.removeEventListener(event, listener, capture);
11619		} else if (element.detachEvent) {
11620			element.detachEvent('on' + event, listener);
11621		}
11622	};
11623
11624	/**
11625	 * Triggers a public event.
11626	 * @todo Remove `status`, `relatedTarget` should be used instead.
11627	 * @protected
11628	 * @param {String} name - The event name.
11629	 * @param {*} [data=null] - The event data.
11630	 * @param {String} [namespace=carousel] - The event namespace.
11631	 * @param {String} [state] - The state which is associated with the event.
11632	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
11633	 * @returns {Event} - The event arguments.
11634	 */
11635	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
11636		var status = {
11637			item: { count: this._items.length, index: this.current() }
11638		}, handler = $.camelCase(
11639			$.grep([ 'on', name, namespace ], function(v) { return v })
11640				.join('-').toLowerCase()
11641		), event = $.Event(
11642			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
11643			$.extend({ relatedTarget: this }, status, data)
11644		);
11645
11646		if (!this._supress[name]) {
11647			$.each(this._plugins, function(name, plugin) {
11648				if (plugin.onTrigger) {
11649					plugin.onTrigger(event);
11650				}
11651			});
11652
11653			this.register({ type: Owl.Type.Event, name: name });
11654			this.$element.trigger(event);
11655
11656			if (this.settings && typeof this.settings[handler] === 'function') {
11657				this.settings[handler].call(this, event);
11658			}
11659		}
11660
11661		return event;
11662	};
11663
11664	/**
11665	 * Enters a state.
11666	 * @param name - The state name.
11667	 */
11668	Owl.prototype.enter = function(name) {
11669		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
11670			if (this._states.current[name] === undefined) {
11671				this._states.current[name] = 0;
11672			}
11673
11674			this._states.current[name]++;
11675		}, this));
11676	};
11677
11678	/**
11679	 * Leaves a state.
11680	 * @param name - The state name.
11681	 */
11682	Owl.prototype.leave = function(name) {
11683		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
11684			this._states.current[name]--;
11685		}, this));
11686	};
11687
11688	/**
11689	 * Registers an event or state.
11690	 * @public
11691	 * @param {Object} object - The event or state to register.
11692	 */
11693	Owl.prototype.register = function(object) {
11694		if (object.type === Owl.Type.Event) {
11695			if (!$.event.special[object.name]) {
11696				$.event.special[object.name] = {};
11697			}
11698
11699			if (!$.event.special[object.name].owl) {
11700				var _default = $.event.special[object.name]._default;
11701				$.event.special[object.name]._default = function(e) {
11702					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
11703						return _default.apply(this, arguments);
11704					}
11705					return e.namespace && e.namespace.indexOf('owl') > -1;
11706				};
11707				$.event.special[object.name].owl = true;
11708			}
11709		} else if (object.type === Owl.Type.State) {
11710			if (!this._states.tags[object.name]) {
11711				this._states.tags[object.name] = object.tags;
11712			} else {
11713				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
11714			}
11715
11716			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
11717				return $.inArray(tag, this._states.tags[object.name]) === i;
11718			}, this));
11719		}
11720	};
11721
11722	/**
11723	 * Suppresses events.
11724	 * @protected
11725	 * @param {Array.<String>} events - The events to suppress.
11726	 */
11727	Owl.prototype.suppress = function(events) {
11728		$.each(events, $.proxy(function(index, event) {
11729			this._supress[event] = true;
11730		}, this));
11731	};
11732
11733	/**
11734	 * Releases suppressed events.
11735	 * @protected
11736	 * @param {Array.<String>} events - The events to release.
11737	 */
11738	Owl.prototype.release = function(events) {
11739		$.each(events, $.proxy(function(index, event) {
11740			delete this._supress[event];
11741		}, this));
11742	};
11743
11744	/**
11745	 * Gets unified pointer coordinates from event.
11746	 * @todo #261
11747	 * @protected
11748	 * @param {Event} - The `mousedown` or `touchstart` event.
11749	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
11750	 */
11751	Owl.prototype.pointer = function(event) {
11752		var result = { x: null, y: null };
11753
11754		event = event.originalEvent || event || window.event;
11755
11756		event = event.touches && event.touches.length ?
11757			event.touches[0] : event.changedTouches && event.changedTouches.length ?
11758				event.changedTouches[0] : event;
11759
11760		if (event.pageX) {
11761			result.x = event.pageX;
11762			result.y = event.pageY;
11763		} else {
11764			result.x = event.clientX;
11765			result.y = event.clientY;
11766		}
11767
11768		return result;
11769	};
11770
11771	/**
11772	 * Gets the difference of two vectors.
11773	 * @todo #261
11774	 * @protected
11775	 * @param {Object} - The first vector.
11776	 * @param {Object} - The second vector.
11777	 * @returns {Object} - The difference.
11778	 */
11779	Owl.prototype.difference = function(first, second) {
11780		return {
11781			x: first.x - second.x,
11782			y: first.y - second.y
11783		};
11784	};
11785
11786	/**
11787	 * The jQuery Plugin for the Owl Carousel
11788	 * @todo Navigation plugin `next` and `prev`
11789	 * @public
11790	 */
11791	$.fn.owlCarousel = function(option) {
11792		var args = Array.prototype.slice.call(arguments, 1);
11793
11794		return this.each(function() {
11795			var $this = $(this),
11796				data = $this.data('owl.carousel');
11797
11798			if (!data) {
11799				data = new Owl(this, typeof option == 'object' && option);
11800				$this.data('owl.carousel', data);
11801
11802				$.each([
11803					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
11804				], function(i, event) {
11805					data.register({ type: Owl.Type.Event, name: event });
11806					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
11807						if (e.namespace && e.relatedTarget !== this) {
11808							this.suppress([ event ]);
11809							data[event].apply(this, [].slice.call(arguments, 1));
11810							this.release([ event ]);
11811						}
11812					}, data));
11813				});
11814			}
11815
11816			if (typeof option == 'string' && option.charAt(0) !== '_') {
11817				data[option].apply(data, args);
11818			}
11819		});
11820	};
11821
11822	/**
11823	 * The constructor for the jQuery Plugin
11824	 * @public
11825	 */
11826	$.fn.owlCarousel.Constructor = Owl;
11827
11828})(window.Zepto || window.jQuery, window, document);
11829
11830/**
11831 * AutoRefresh Plugin
11832 * @version 2.0.0-beta.3
11833 * @author Artus Kolanowski
11834 * @license The MIT License (MIT)
11835 */
11836;(function($, window, document, undefined) {
11837
11838	/**
11839	 * Creates the auto refresh plugin.
11840	 * @class The Auto Refresh Plugin
11841	 * @param {Owl} carousel - The Owl Carousel
11842	 */
11843	var AutoRefresh = function(carousel) {
11844		/**
11845		 * Reference to the core.
11846		 * @protected
11847		 * @type {Owl}
11848		 */
11849		this._core = carousel;
11850
11851		/**
11852		 * Refresh interval.
11853		 * @protected
11854		 * @type {number}
11855		 */
11856		this._interval = null;
11857
11858		/**
11859		 * Whether the element is currently visible or not.
11860		 * @protected
11861		 * @type {Boolean}
11862		 */
11863		this._visible = null;
11864
11865		/**
11866		 * All event handlers.
11867		 * @protected
11868		 * @type {Object}
11869		 */
11870		this._handlers = {
11871			'initialized.owl.carousel': $.proxy(function(e) {
11872				if (e.namespace && this._core.settings.autoRefresh) {
11873					this.watch();
11874				}
11875			}, this)
11876		};
11877
11878		// set default options
11879		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
11880
11881		// register event handlers
11882		this._core.$element.on(this._handlers);
11883	};
11884
11885	/**
11886	 * Default options.
11887	 * @public
11888	 */
11889	AutoRefresh.Defaults = {
11890		autoRefresh: true,
11891		autoRefreshInterval: 500
11892	};
11893
11894	/**
11895	 * Watches the element.
11896	 */
11897	AutoRefresh.prototype.watch = function() {
11898		if (this._interval) {
11899			return;
11900		}
11901
11902		this._visible = this._core.$element.is(':visible');
11903		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
11904	};
11905
11906	/**
11907	 * Refreshes the element.
11908	 */
11909	AutoRefresh.prototype.refresh = function() {
11910		if (this._core.$element.is(':visible') === this._visible) {
11911			return;
11912		}
11913
11914		this._visible = !this._visible;
11915
11916		this._core.$element.toggleClass('owl-hidden', !this._visible);
11917
11918		this._visible && (this._core.invalidate('width') && this._core.refresh());
11919	};
11920
11921	/**
11922	 * Destroys the plugin.
11923	 */
11924	AutoRefresh.prototype.destroy = function() {
11925		var handler, property;
11926
11927		window.clearInterval(this._interval);
11928
11929		for (handler in this._handlers) {
11930			this._core.$element.off(handler, this._handlers[handler]);
11931		}
11932		for (property in Object.getOwnPropertyNames(this)) {
11933			typeof this[property] != 'function' && (this[property] = null);
11934		}
11935	};
11936
11937	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
11938
11939})(window.Zepto || window.jQuery, window, document);
11940
11941/**
11942 * Lazy Plugin
11943 * @version 2.0.0-beta.3
11944 * @author Bartosz Wojciechowski
11945 * @license The MIT License (MIT)
11946 */
11947;(function($, window, document, undefined) {
11948
11949	/**
11950	 * Creates the lazy plugin.
11951	 * @class The Lazy Plugin
11952	 * @param {Owl} carousel - The Owl Carousel
11953	 */
11954	var Lazy = function(carousel) {
11955
11956		/**
11957		 * Reference to the core.
11958		 * @protected
11959		 * @type {Owl}
11960		 */
11961		this._core = carousel;
11962
11963		/**
11964		 * Already loaded items.
11965		 * @protected
11966		 * @type {Array.<jQuery>}
11967		 */
11968		this._loaded = [];
11969
11970		/**
11971		 * Event handlers.
11972		 * @protected
11973		 * @type {Object}
11974		 */
11975		this._handlers = {
11976			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
11977				if (!e.namespace) {
11978					return;
11979				}
11980
11981				if (!this._core.settings || !this._core.settings.lazyLoad) {
11982					return;
11983				}
11984
11985				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
11986					var settings = this._core.settings,
11987						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
11988						i = ((settings.center && n * -1) || 0),
11989						position = ((e.property && e.property.value) || this._core.current()) + i,
11990						clones = this._core.clones().length,
11991						load = $.proxy(function(i, v) { this.load(v) }, this);
11992
11993					while (i++ < n) {
11994						this.load(clones / 2 + this._core.relative(position));
11995						clones && $.each(this._core.clones(this._core.relative(position)), load);
11996						position++;
11997					}
11998				}
11999			}, this)
12000		};
12001
12002		// set the default options
12003		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
12004
12005		// register event handler
12006		this._core.$element.on(this._handlers);
12007	}
12008
12009	/**
12010	 * Default options.
12011	 * @public
12012	 */
12013	Lazy.Defaults = {
12014		lazyLoad: false
12015	}
12016
12017	/**
12018	 * Loads all resources of an item at the specified position.
12019	 * @param {Number} position - The absolute position of the item.
12020	 * @protected
12021	 */
12022	Lazy.prototype.load = function(position) {
12023		var $item = this._core.$stage.children().eq(position),
12024			$elements = $item && $item.find('.owl-lazy');
12025
12026		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
12027			return;
12028		}
12029
12030		$elements.each($.proxy(function(index, element) {
12031			var $element = $(element), image,
12032				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
12033
12034			this._core.trigger('load', { element: $element, url: url }, 'lazy');
12035
12036			if ($element.is('img')) {
12037				$element.one('load.owl.lazy', $.proxy(function() {
12038					$element.css('opacity', 1);
12039					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
12040				}, this)).attr('src', url);
12041			} else {
12042				image = new Image();
12043				image.onload = $.proxy(function() {
12044					$element.css({
12045						'background-image': 'url(' + url + ')',
12046						'opacity': '1'
12047					});
12048					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
12049				}, this);
12050				image.src = url;
12051			}
12052		}, this));
12053
12054		this._loaded.push($item.get(0));
12055	}
12056
12057	/**
12058	 * Destroys the plugin.
12059	 * @public
12060	 */
12061	Lazy.prototype.destroy = function() {
12062		var handler, property;
12063
12064		for (handler in this.handlers) {
12065			this._core.$element.off(handler, this.handlers[handler]);
12066		}
12067		for (property in Object.getOwnPropertyNames(this)) {
12068			typeof this[property] != 'function' && (this[property] = null);
12069		}
12070	};
12071
12072	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
12073
12074})(window.Zepto || window.jQuery, window, document);
12075
12076/**
12077 * AutoHeight Plugin
12078 * @version 2.0.0-beta.3
12079 * @author Bartosz Wojciechowski
12080 * @license The MIT License (MIT)
12081 */
12082;(function($, window, document, undefined) {
12083
12084	/**
12085	 * Creates the auto height plugin.
12086	 * @class The Auto Height Plugin
12087	 * @param {Owl} carousel - The Owl Carousel
12088	 */
12089	var AutoHeight = function(carousel) {
12090		/**
12091		 * Reference to the core.
12092		 * @protected
12093		 * @type {Owl}
12094		 */
12095		this._core = carousel;
12096
12097		/**
12098		 * All event handlers.
12099		 * @protected
12100		 * @type {Object}
12101		 */
12102		this._handlers = {
12103			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
12104				if (e.namespace && this._core.settings.autoHeight) {
12105					this.update();
12106				}
12107			}, this),
12108			'changed.owl.carousel': $.proxy(function(e) {
12109				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
12110					this.update();
12111				}
12112			}, this),
12113			'loaded.owl.lazy': $.proxy(function(e) {
12114				if (e.namespace && this._core.settings.autoHeight
12115					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
12116					this.update();
12117				}
12118			}, this)
12119		};
12120
12121		// set default options
12122		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
12123
12124		// register event handlers
12125		this._core.$element.on(this._handlers);
12126	};
12127
12128	/**
12129	 * Default options.
12130	 * @public
12131	 */
12132	AutoHeight.Defaults = {
12133		autoHeight: false,
12134		autoHeightClass: 'owl-height'
12135	};
12136
12137	/**
12138	 * Updates the view.
12139	 */
12140	AutoHeight.prototype.update = function() {
12141		var start = this._core._current,
12142			end = start + this._core.settings.items,
12143			visible = this._core.$stage.children().toArray().slice(start, end);
12144			heights = [],
12145			maxheight = 0;
12146
12147		$.each(visible, function(index, item) {
12148			heights.push($(item).height());
12149		});
12150
12151		maxheight = Math.max.apply(null, heights);
12152
12153		this._core.$stage.parent()
12154			.height(maxheight)
12155			.addClass(this._core.settings.autoHeightClass);
12156	};
12157
12158	AutoHeight.prototype.destroy = function() {
12159		var handler, property;
12160
12161		for (handler in this._handlers) {
12162			this._core.$element.off(handler, this._handlers[handler]);
12163		}
12164		for (property in Object.getOwnPropertyNames(this)) {
12165			typeof this[property] != 'function' && (this[property] = null);
12166		}
12167	};
12168
12169	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
12170
12171})(window.Zepto || window.jQuery, window, document);
12172
12173/**
12174 * Video Plugin
12175 * @version 2.0.0-beta.3
12176 * @author Bartosz Wojciechowski
12177 * @license The MIT License (MIT)
12178 */
12179;(function($, window, document, undefined) {
12180
12181	/**
12182	 * Creates the video plugin.
12183	 * @class The Video Plugin
12184	 * @param {Owl} carousel - The Owl Carousel
12185	 */
12186	var Video = function(carousel) {
12187		/**
12188		 * Reference to the core.
12189		 * @protected
12190		 * @type {Owl}
12191		 */
12192		this._core = carousel;
12193
12194		/**
12195		 * Cache all video URLs.
12196		 * @protected
12197		 * @type {Object}
12198		 */
12199		this._videos = {};
12200
12201		/**
12202		 * Current playing item.
12203		 * @protected
12204		 * @type {jQuery}
12205		 */
12206		this._playing = null;
12207
12208		/**
12209		 * All event handlers.
12210		 * @todo The cloned content removale is too late
12211		 * @protected
12212		 * @type {Object}
12213		 */
12214		this._handlers = {
12215			'initialized.owl.carousel': $.proxy(function(e) {
12216				if (e.namespace) {
12217					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
12218				}
12219			}, this),
12220			'resize.owl.carousel': $.proxy(function(e) {
12221				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
12222					e.preventDefault();
12223				}
12224			}, this),
12225			'refreshed.owl.carousel': $.proxy(function(e) {
12226				if (e.namespace && this._core.is('resizing')) {
12227					this._core.$stage.find('.cloned .owl-video-frame').remove();
12228				}
12229			}, this),
12230			'changed.owl.carousel': $.proxy(function(e) {
12231				if (e.namespace && e.property.name === 'position' && this._playing) {
12232					this.stop();
12233				}
12234			}, this),
12235			'prepared.owl.carousel': $.proxy(function(e) {
12236				if (!e.namespace) {
12237					return;
12238				}
12239
12240				var $element = $(e.content).find('.owl-video');
12241
12242				if ($element.length) {
12243					$element.css('display', 'none');
12244					this.fetch($element, $(e.content));
12245				}
12246			}, this)
12247		};
12248
12249		// set default options
12250		this._core.options = $.extend({}, Video.Defaults, this._core.options);
12251
12252		// register event handlers
12253		this._core.$element.on(this._handlers);
12254
12255		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
12256			this.play(e);
12257		}, this));
12258	};
12259
12260	/**
12261	 * Default options.
12262	 * @public
12263	 */
12264	Video.Defaults = {
12265		video: false,
12266		videoHeight: false,
12267		videoWidth: false
12268	};
12269
12270	/**
12271	 * Gets the video ID and the type (YouTube/Vimeo only).
12272	 * @protected
12273	 * @param {jQuery} target - The target containing the video data.
12274	 * @param {jQuery} item - The item containing the video.
12275	 */
12276	Video.prototype.fetch = function(target, item) {
12277		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
12278			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
12279			width = target.attr('data-width') || this._core.settings.videoWidth,
12280			height = target.attr('data-height') || this._core.settings.videoHeight,
12281			url = target.attr('href');
12282
12283		if (url) {
12284			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+)?/);
12285
12286			if (id[3].indexOf('youtu') > -1) {
12287				type = 'youtube';
12288			} else if (id[3].indexOf('vimeo') > -1) {
12289				type = 'vimeo';
12290			} else {
12291				throw new Error('Video URL not supported.');
12292			}
12293			id = id[6];
12294		} else {
12295			throw new Error('Missing video URL.');
12296		}
12297
12298		this._videos[url] = {
12299			type: type,
12300			id: id,
12301			width: width,
12302			height: height
12303		};
12304
12305		item.attr('data-video', url);
12306
12307		this.thumbnail(target, this._videos[url]);
12308	};
12309
12310	/**
12311	 * Creates video thumbnail.
12312	 * @protected
12313	 * @param {jQuery} target - The target containing the video data.
12314	 * @param {Object} info - The video info object.
12315	 * @see `fetch`
12316	 */
12317	Video.prototype.thumbnail = function(target, video) {
12318		var tnLink,
12319			icon,
12320			path,
12321			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
12322			customTn = target.find('img'),
12323			srcType = 'src',
12324			lazyClass = '',
12325			settings = this._core.settings,
12326			create = function(path) {
12327				icon = '<div class="owl-video-play-icon"></div>';
12328
12329				if (settings.lazyLoad) {
12330					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
12331				} else {
12332					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
12333				}
12334				target.after(tnLink);
12335				target.after(icon);
12336			};
12337
12338		// wrap video content into owl-video-wrapper div
12339		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
12340
12341		if (this._core.settings.lazyLoad) {
12342			srcType = 'data-src';
12343			lazyClass = 'owl-lazy';
12344		}
12345
12346		// custom thumbnail
12347		if (customTn.length) {
12348			create(customTn.attr(srcType));
12349			customTn.remove();
12350			return false;
12351		}
12352
12353		if (video.type === 'youtube') {
12354			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
12355			create(path);
12356		} else if (video.type === 'vimeo') {
12357			$.ajax({
12358				type: 'GET',
12359				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
12360				jsonp: 'callback',
12361				dataType: 'jsonp',
12362				success: function(data) {
12363					path = data[0].thumbnail_large;
12364					create(path);
12365				}
12366			});
12367		}
12368	};
12369
12370	/**
12371	 * Stops the current video.
12372	 * @public
12373	 */
12374	Video.prototype.stop = function() {
12375		this._core.trigger('stop', null, 'video');
12376		this._playing.find('.owl-video-frame').remove();
12377		this._playing.removeClass('owl-video-playing');
12378		this._playing = null;
12379		this._core.leave('playing');
12380		this._core.trigger('stopped', null, 'video');
12381	};
12382
12383	/**
12384	 * Starts the current video.
12385	 * @public
12386	 * @param {Event} event - The event arguments.
12387	 */
12388	Video.prototype.play = function(event) {
12389		var target = $(event.target),
12390			item = target.closest('.' + this._core.settings.itemClass),
12391			video = this._videos[item.attr('data-video')],
12392			width = video.width || '100%',
12393			height = video.height || this._core.$stage.height(),
12394			html;
12395
12396		if (this._playing) {
12397			return;
12398		}
12399
12400		this._core.enter('playing');
12401		this._core.trigger('play', null, 'video');
12402
12403		item = this._core.items(this._core.relative(item.index()));
12404
12405		this._core.reset(item.index());
12406
12407		if (video.type === 'youtube') {
12408			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
12409				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
12410		} else if (video.type === 'vimeo') {
12411			html = '<iframe src="//player.vimeo.com/video/' + video.id +
12412				'?autoplay=1" width="' + width + '" height="' + height +
12413				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
12414		}
12415
12416		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
12417
12418		this._playing = item.addClass('owl-video-playing');
12419	};
12420
12421	/**
12422	 * Checks whether an video is currently in full screen mode or not.
12423	 * @todo Bad style because looks like a readonly method but changes members.
12424	 * @protected
12425	 * @returns {Boolean}
12426	 */
12427	Video.prototype.isInFullScreen = function() {
12428		var element = document.fullscreenElement || document.mozFullScreenElement ||
12429				document.webkitFullscreenElement;
12430
12431		return element && $(element).parent().hasClass('owl-video-frame');
12432	};
12433
12434	/**
12435	 * Destroys the plugin.
12436	 */
12437	Video.prototype.destroy = function() {
12438		var handler, property;
12439
12440		this._core.$element.off('click.owl.video');
12441
12442		for (handler in this._handlers) {
12443			this._core.$element.off(handler, this._handlers[handler]);
12444		}
12445		for (property in Object.getOwnPropertyNames(this)) {
12446			typeof this[property] != 'function' && (this[property] = null);
12447		}
12448	};
12449
12450	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
12451
12452})(window.Zepto || window.jQuery, window, document);
12453
12454/**
12455 * Animate Plugin
12456 * @version 2.0.0-beta.3
12457 * @author Bartosz Wojciechowski
12458 * @license The MIT License (MIT)
12459 */
12460;(function($, window, document, undefined) {
12461
12462	/**
12463	 * Creates the animate plugin.
12464	 * @class The Navigation Plugin
12465	 * @param {Owl} scope - The Owl Carousel
12466	 */
12467	var Animate = function(scope) {
12468		this.core = scope;
12469		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
12470		this.swapping = true;
12471		this.previous = undefined;
12472		this.next = undefined;
12473
12474		this.handlers = {
12475			'change.owl.carousel': $.proxy(function(e) {
12476				if (e.namespace && e.property.name == 'position') {
12477					this.previous = this.core.current();
12478					this.next = e.property.value;
12479				}
12480			}, this),
12481			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
12482				if (e.namespace) {
12483					this.swapping = e.type == 'translated';
12484				}
12485			}, this),
12486			'translate.owl.carousel': $.proxy(function(e) {
12487				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
12488					this.swap();
12489				}
12490			}, this)
12491		};
12492
12493		this.core.$element.on(this.handlers);
12494	};
12495
12496	/**
12497	 * Default options.
12498	 * @public
12499	 */
12500	Animate.Defaults = {
12501		animateOut: false,
12502		animateIn: false
12503	};
12504
12505	/**
12506	 * Toggles the animation classes whenever an translations starts.
12507	 * @protected
12508	 * @returns {Boolean|undefined}
12509	 */
12510	Animate.prototype.swap = function() {
12511
12512		if (this.core.settings.items !== 1) {
12513			return;
12514		}
12515
12516		if (!$.support.animation || !$.support.transition) {
12517			return;
12518		}
12519
12520		this.core.speed(0);
12521
12522		var left,
12523			clear = $.proxy(this.clear, this),
12524			previous = this.core.$stage.children().eq(this.previous),
12525			next = this.core.$stage.children().eq(this.next),
12526			incoming = this.core.settings.animateIn,
12527			outgoing = this.core.settings.animateOut;
12528
12529		if (this.core.current() === this.previous) {
12530			return;
12531		}
12532
12533		if (outgoing) {
12534			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
12535			previous.css( { 'left': left + 'px' } )
12536				.addClass('animated owl-animated-out')
12537				.addClass(outgoing)
12538				.on($.support.animation.end, clear);
12539		}
12540
12541		if (incoming) {
12542			next.addClass('animated owl-animated-in')
12543				.addClass(incoming)
12544				.on($.support.animation.end, clear);
12545		}
12546	};
12547
12548	Animate.prototype.clear = function(e) {
12549		if ($(e.target).hasClass('animated')) {
12550			$(e.target).css( { 'left': '' } )
12551				.removeClass('animated owl-animated-out owl-animated-in')
12552				.removeClass(this.core.settings.animateIn)
12553				.removeClass(this.core.settings.animateOut);
12554			this.core.onTransitionEnd();
12555		}
12556	};
12557
12558	/**
12559	 * Destroys the plugin.
12560	 * @public
12561	 */
12562	Animate.prototype.destroy = function() {
12563		var handler, property;
12564
12565		for (handler in this.handlers) {
12566			this.core.$element.off(handler, this.handlers[handler]);
12567		}
12568		for (property in Object.getOwnPropertyNames(this)) {
12569			typeof this[property] != 'function' && (this[property] = null);
12570		}
12571	};
12572
12573	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
12574
12575})(window.Zepto || window.jQuery, window, document);
12576
12577/**
12578 * Autoplay Plugin
12579 * @version 2.0.0-beta.3
12580 * @author Bartosz Wojciechowski
12581 * @author Artus Kolanowski
12582 * @license The MIT License (MIT)
12583 */
12584;(function($, window, document, undefined) {
12585
12586	/**
12587	 * Creates the autoplay plugin.
12588	 * @class The Autoplay Plugin
12589	 * @param {Owl} scope - The Owl Carousel
12590	 */
12591	var Autoplay = function(carousel) {
12592		/**
12593		 * Reference to the core.
12594		 * @protected
12595		 * @type {Owl}
12596		 */
12597		this._core = carousel;
12598
12599		/**
12600		 * The autoplay interval.
12601		 * @type {Number}
12602		 */
12603		this._interval = null;
12604
12605		/**
12606		 * Indicates whenever the autoplay is paused.
12607		 * @type {Boolean}
12608		 */
12609		this._paused = false;
12610
12611		/**
12612		 * All event handlers.
12613		 * @protected
12614		 * @type {Object}
12615		 */
12616		this._handlers = {
12617			'changed.owl.carousel': $.proxy(function(e) {
12618				if (e.namespace && e.property.name === 'settings') {
12619					if (this._core.settings.autoplay) {
12620						this.play();
12621					} else {
12622						this.stop();
12623					}
12624				}
12625			}, this),
12626			'initialized.owl.carousel': $.proxy(function(e) {
12627				if (e.namespace && this._core.settings.autoplay) {
12628					this.play();
12629				}
12630			}, this),
12631			'play.owl.autoplay': $.proxy(function(e, t, s) {
12632				if (e.namespace) {
12633					this.play(t, s);
12634				}
12635			}, this),
12636			'stop.owl.autoplay': $.proxy(function(e) {
12637				if (e.namespace) {
12638					this.stop();
12639				}
12640			}, this),
12641			'mouseover.owl.autoplay': $.proxy(function() {
12642				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
12643					this.pause();
12644				}
12645			}, this),
12646			'mouseleave.owl.autoplay': $.proxy(function() {
12647				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
12648					this.play();
12649				}
12650			}, this)
12651		};
12652
12653		// register event handlers
12654		this._core.$element.on(this._handlers);
12655
12656		// set default options
12657		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
12658	};
12659
12660	/**
12661	 * Default options.
12662	 * @public
12663	 */
12664	Autoplay.Defaults = {
12665		autoplay: false,
12666		autoplayTimeout: 5000,
12667		autoplayHoverPause: false,
12668		autoplaySpeed: false
12669	};
12670
12671	/**
12672	 * Starts the autoplay.
12673	 * @public
12674	 * @param {Number} [timeout] - The interval before the next animation starts.
12675	 * @param {Number} [speed] - The animation speed for the animations.
12676	 */
12677	Autoplay.prototype.play = function(timeout, speed) {
12678		this._paused = false;
12679
12680		if (this._core.is('rotating')) {
12681			return;
12682		}
12683
12684		this._core.enter('rotating');
12685
12686		this._interval = window.setInterval($.proxy(function() {
12687			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
12688				return;
12689			}
12690			this._core.next(speed || this._core.settings.autoplaySpeed);
12691		}, this), timeout || this._core.settings.autoplayTimeout);
12692	};
12693
12694	/**
12695	 * Stops the autoplay.
12696	 * @public
12697	 */
12698	Autoplay.prototype.stop = function() {
12699		if (!this._core.is('rotating')) {
12700			return;
12701		}
12702
12703		window.clearInterval(this._interval);
12704		this._core.leave('rotating');
12705	};
12706
12707	/**
12708	 * Stops the autoplay.
12709	 * @public
12710	 */
12711	Autoplay.prototype.pause = function() {
12712		if (!this._core.is('rotating')) {
12713			return;
12714		}
12715
12716		this._paused = true;
12717	};
12718
12719	/**
12720	 * Destroys the plugin.
12721	 */
12722	Autoplay.prototype.destroy = function() {
12723		var handler, property;
12724
12725		this.stop();
12726
12727		for (handler in this._handlers) {
12728			this._core.$element.off(handler, this._handlers[handler]);
12729		}
12730		for (property in Object.getOwnPropertyNames(this)) {
12731			typeof this[property] != 'function' && (this[property] = null);
12732		}
12733	};
12734
12735	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
12736
12737})(window.Zepto || window.jQuery, window, document);
12738
12739/**
12740 * Navigation Plugin
12741 * @version 2.0.0-beta.3
12742 * @author Artus Kolanowski
12743 * @license The MIT License (MIT)
12744 */
12745;(function($, window, document, undefined) {
12746	'use strict';
12747
12748	/**
12749	 * Creates the navigation plugin.
12750	 * @class The Navigation Plugin
12751	 * @param {Owl} carousel - The Owl Carousel.
12752	 */
12753	var Navigation = function(carousel) {
12754		/**
12755		 * Reference to the core.
12756		 * @protected
12757		 * @type {Owl}
12758		 */
12759		this._core = carousel;
12760
12761		/**
12762		 * Indicates whether the plugin is initialized or not.
12763		 * @protected
12764		 * @type {Boolean}
12765		 */
12766		this._initialized = false;
12767
12768		/**
12769		 * The current paging indexes.
12770		 * @protected
12771		 * @type {Array}
12772		 */
12773		this._pages = [];
12774
12775		/**
12776		 * All DOM elements of the user interface.
12777		 * @protected
12778		 * @type {Object}
12779		 */
12780		this._controls = {};
12781
12782		/**
12783		 * Markup for an indicator.
12784		 * @protected
12785		 * @type {Array.<String>}
12786		 */
12787		this._templates = [];
12788
12789		/**
12790		 * The carousel element.
12791		 * @type {jQuery}
12792		 */
12793		this.$element = this._core.$element;
12794
12795		/**
12796		 * Overridden methods of the carousel.
12797		 * @protected
12798		 * @type {Object}
12799		 */
12800		this._overrides = {
12801			next: this._core.next,
12802			prev: this._core.prev,
12803			to: this._core.to
12804		};
12805
12806		/**
12807		 * All event handlers.
12808		 * @protected
12809		 * @type {Object}
12810		 */
12811		this._handlers = {
12812			'prepared.owl.carousel': $.proxy(function(e) {
12813				if (e.namespace && this._core.settings.dotsData) {
12814					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
12815						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
12816				}
12817			}, this),
12818			'added.owl.carousel': $.proxy(function(e) {
12819				if (e.namespace && this._core.settings.dotsData) {
12820					this._templates.splice(e.position, 0, this._templates.pop());
12821				}
12822			}, this),
12823			'remove.owl.carousel': $.proxy(function(e) {
12824				if (e.namespace && this._core.settings.dotsData) {
12825					this._templates.splice(e.position, 1);
12826				}
12827			}, this),
12828			'changed.owl.carousel': $.proxy(function(e) {
12829				if (e.namespace && e.property.name == 'position') {
12830					this.draw();
12831				}
12832			}, this),
12833			'initialized.owl.carousel': $.proxy(function(e) {
12834				if (e.namespace && !this._initialized) {
12835					this._core.trigger('initialize', null, 'navigation');
12836					this.initialize();
12837					this.update();
12838					this.draw();
12839					this._initialized = true;
12840					this._core.trigger('initialized', null, 'navigation');
12841				}
12842			}, this),
12843			'refreshed.owl.carousel': $.proxy(function(e) {
12844				if (e.namespace && this._initialized) {
12845					this._core.trigger('refresh', null, 'navigation');
12846					this.update();
12847					this.draw();
12848					this._core.trigger('refreshed', null, 'navigation');
12849				}
12850			}, this)
12851		};
12852
12853		// set default options
12854		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
12855
12856		// register event handlers
12857		this.$element.on(this._handlers);
12858	};
12859
12860	/**
12861	 * Default options.
12862	 * @public
12863	 * @todo Rename `slideBy` to `navBy`
12864	 */
12865	Navigation.Defaults = {
12866		nav: false,
12867		navText: [ 'prev', 'next' ],
12868		navSpeed: false,
12869		navElement: 'div',
12870		navContainer: false,
12871		navContainerClass: 'owl-nav',
12872		navClass: [ 'owl-prev', 'owl-next' ],
12873		slideBy: 1,
12874		dotClass: 'owl-dot',
12875		dotsClass: 'owl-dots',
12876		dots: true,
12877		dotsEach: false,
12878		dotsData: false,
12879		dotsSpeed: false,
12880		dotsContainer: false
12881	};
12882
12883	/**
12884	 * Initializes the layout of the plugin and extends the carousel.
12885	 * @protected
12886	 */
12887	Navigation.prototype.initialize = function() {
12888		var override,
12889			settings = this._core.settings;
12890
12891		// create DOM structure for relative navigation
12892		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
12893			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
12894
12895		this._controls.$previous = $('<' + settings.navElement + '>')
12896			.addClass(settings.navClass[0])
12897			.html(settings.navText[0])
12898			.prependTo(this._controls.$relative)
12899			.on('click', $.proxy(function(e) {
12900				this.prev(settings.navSpeed);
12901			}, this));
12902		this._controls.$next = $('<' + settings.navElement + '>')
12903			.addClass(settings.navClass[1])
12904			.html(settings.navText[1])
12905			.appendTo(this._controls.$relative)
12906			.on('click', $.proxy(function(e) {
12907				this.next(settings.navSpeed);
12908			}, this));
12909
12910		// create DOM structure for absolute navigation
12911		if (!settings.dotsData) {
12912			this._templates = [ $('<div>')
12913				.addClass(settings.dotClass)
12914				.append($('<span>'))
12915				.prop('outerHTML') ];
12916		}
12917
12918		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
12919			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
12920
12921		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
12922			var index = $(e.target).parent().is(this._controls.$absolute)
12923				? $(e.target).index() : $(e.target).parent().index();
12924
12925			e.preventDefault();
12926
12927			this.to(index, settings.dotsSpeed);
12928		}, this));
12929
12930		// override public methods of the carousel
12931		for (override in this._overrides) {
12932			this._core[override] = $.proxy(this[override], this);
12933		}
12934	};
12935
12936	/**
12937	 * Destroys the plugin.
12938	 * @protected
12939	 */
12940	Navigation.prototype.destroy = function() {
12941		var handler, control, property, override;
12942
12943		for (handler in this._handlers) {
12944			this.$element.off(handler, this._handlers[handler]);
12945		}
12946		for (control in this._controls) {
12947			this._controls[control].remove();
12948		}
12949		for (override in this.overides) {
12950			this._core[override] = this._overrides[override];
12951		}
12952		for (property in Object.getOwnPropertyNames(this)) {
12953			typeof this[property] != 'function' && (this[property] = null);
12954		}
12955	};
12956
12957	/**
12958	 * Updates the internal state.
12959	 * @protected
12960	 */
12961	Navigation.prototype.update = function() {
12962		var i, j, k,
12963			lower = this._core.clones().length / 2,
12964			upper = lower + this._core.items().length,
12965			maximum = this._core.maximum(true),
12966			settings = this._core.settings,
12967			size = settings.center || settings.autoWidth || settings.dotsData
12968				? 1 : settings.dotsEach || settings.items;
12969
12970		if (settings.slideBy !== 'page') {
12971			settings.slideBy = Math.min(settings.slideBy, settings.items);
12972		}
12973
12974		if (settings.dots || settings.slideBy == 'page') {
12975			this._pages = [];
12976
12977			for (i = lower, j = 0, k = 0; i < upper; i++) {
12978				if (j >= size || j === 0) {
12979					this._pages.push({
12980						start: Math.min(maximum, i - lower),
12981						end: i - lower + size - 1
12982					});
12983					if (Math.min(maximum, i - lower) === maximum) {
12984						break;
12985					}
12986					j = 0, ++k;
12987				}
12988				j += this._core.mergers(this._core.relative(i));
12989			}
12990		}
12991	};
12992
12993	/**
12994	 * Draws the user interface.
12995	 * @todo The option `dotsData` wont work.
12996	 * @protected
12997	 */
12998	Navigation.prototype.draw = function() {
12999		var difference,
13000			settings = this._core.settings,
13001			disabled = this._core.items().length <= settings.items,
13002			index = this._core.relative(this._core.current()),
13003			loop = settings.loop || settings.rewind;
13004
13005		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
13006
13007		if (settings.nav) {
13008			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
13009			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
13010		}
13011
13012		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
13013
13014		if (settings.dots) {
13015			difference = this._pages.length - this._controls.$absolute.children().length;
13016
13017			if (settings.dotsData && difference !== 0) {
13018				this._controls.$absolute.html(this._templates.join(''));
13019			} else if (difference > 0) {
13020				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
13021			} else if (difference < 0) {
13022				this._controls.$absolute.children().slice(difference).remove();
13023			}
13024
13025			this._controls.$absolute.find('.active').removeClass('active');
13026			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
13027		}
13028	};
13029
13030	/**
13031	 * Extends event data.
13032	 * @protected
13033	 * @param {Event} event - The event object which gets thrown.
13034	 */
13035	Navigation.prototype.onTrigger = function(event) {
13036		var settings = this._core.settings;
13037
13038		event.page = {
13039			index: $.inArray(this.current(), this._pages),
13040			count: this._pages.length,
13041			size: settings && (settings.center || settings.autoWidth || settings.dotsData
13042				? 1 : settings.dotsEach || settings.items)
13043		};
13044	};
13045
13046	/**
13047	 * Gets the current page position of the carousel.
13048	 * @protected
13049	 * @returns {Number}
13050	 */
13051	Navigation.prototype.current = function() {
13052		var current = this._core.relative(this._core.current());
13053		return $.grep(this._pages, $.proxy(function(page, index) {
13054			return page.start <= current && page.end >= current;
13055		}, this)).pop();
13056	};
13057
13058	/**
13059	 * Gets the current succesor/predecessor position.
13060	 * @protected
13061	 * @returns {Number}
13062	 */
13063	Navigation.prototype.getPosition = function(successor) {
13064		var position, length,
13065			settings = this._core.settings;
13066
13067		if (settings.slideBy == 'page') {
13068			position = $.inArray(this.current(), this._pages);
13069			length = this._pages.length;
13070			successor ? ++position : --position;
vendor: 5,678 bytes, lines 13071-13295
13071			position = this._pages[((position % length) + length) % length].start;
13072		} else {
13073			position = this._core.relative(this._core.current());
13074			length = this._core.items().length;
13075			successor ? position += settings.slideBy : position -= settings.slideBy;
13076		}
13077
13078		return position;
13079	};
13080
13081	/**
13082	 * Slides to the next item or page.
13083	 * @public
13084	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
13085	 */
13086	Navigation.prototype.next = function(speed) {
13087		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
13088	};
13089
13090	/**
13091	 * Slides to the previous item or page.
13092	 * @public
13093	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
13094	 */
13095	Navigation.prototype.prev = function(speed) {
13096		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
13097	};
13098
13099	/**
13100	 * Slides to the specified item or page.
13101	 * @public
13102	 * @param {Number} position - The position of the item or page.
13103	 * @param {Number} [speed] - The time in milliseconds for the transition.
13104	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
13105	 */
13106	Navigation.prototype.to = function(position, speed, standard) {
13107		var length;
13108
13109		if (!standard) {
13110			length = this._pages.length;
13111			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
13112		} else {
13113			$.proxy(this._overrides.to, this._core)(position, speed);
13114		}
13115	};
13116
13117	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
13118
13119})(window.Zepto || window.jQuery, window, document);
13120
13121/**
13122 * Hash Plugin
13123 * @version 2.0.0-beta.3
13124 * @author Artus Kolanowski
13125 * @license The MIT License (MIT)
13126 */
13127;(function($, window, document, undefined) {
13128	'use strict';
13129
13130	/**
13131	 * Creates the hash plugin.
13132	 * @class The Hash Plugin
13133	 * @param {Owl} carousel - The Owl Carousel
13134	 */
13135	var Hash = function(carousel) {
13136		/**
13137		 * Reference to the core.
13138		 * @protected
13139		 * @type {Owl}
13140		 */
13141		this._core = carousel;
13142
13143		/**
13144		 * Hash index for the items.
13145		 * @protected
13146		 * @type {Object}
13147		 */
13148		this._hashes = {};
13149
13150		/**
13151		 * The carousel element.
13152		 * @type {jQuery}
13153		 */
13154		this.$element = this._core.$element;
13155
13156		/**
13157		 * All event handlers.
13158		 * @protected
13159		 * @type {Object}
13160		 */
13161		this._handlers = {
13162			/*'initialized.owl.carousel': $.proxy(function(e) {
13163				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
13164					$(window).trigger('hashchange.owl.navigation');
13165				}
13166			}, this),*/
13167			'prepared.owl.carousel': $.proxy(function(e) {
13168				if (e.namespace) {
13169					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
13170
13171					if (!hash) {
13172						return;
13173					}
13174
13175					this._hashes[hash] = e.content;
13176				}
13177			}, this),
13178			'changed.owl.carousel': $.proxy(function(e) {
13179				if (e.namespace && e.property.name === 'position') {
13180					var current = this._core.items(this._core.relative(this._core.current())),
13181						hash = $.map(this._hashes, function(item, hash) {
13182							return item === current ? hash : null;
13183						}).join();
13184
13185					if (!hash || window.location.hash.slice(1) === hash) {
13186						return;
13187					}
13188
13189					window.location.hash = hash;
13190				}
13191			}, this)
13192		};
13193
13194		// set default options
13195		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
13196
13197		// register the event handlers
13198		this.$element.on(this._handlers);
13199
13200		// register event listener for hash navigation
13201		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
13202			var hash = window.location.hash.substring(1),
13203				items = this._core.$stage.children(),
13204				position = this._hashes[hash] && items.index(this._hashes[hash]);
13205
13206			if (position === undefined || position === this._core.current()) {
13207				return;
13208			}
13209
13210			this._core.to(this._core.relative(position), false, true);
13211		}, this));*/
13212	};
13213
13214	/**
13215	 * Default options.
13216	 * @public
13217	 */
13218	Hash.Defaults = {
13219		URLhashListener: false
13220	};
13221
13222	/**
13223	 * Destroys the plugin.
13224	 * @public
13225	 */
13226	Hash.prototype.destroy = function() {
13227		var handler, property;
13228
13229		$(window).off('hashchange.owl.navigation');
13230
13231		for (handler in this._handlers) {
13232			this._core.$element.off(handler, this._handlers[handler]);
13233		}
13234		for (property in Object.getOwnPropertyNames(this)) {
13235			typeof this[property] != 'function' && (this[property] = null);
13236		}
13237	};
13238
13239	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
13240
13241})(window.Zepto || window.jQuery, window, document);
13242
13243/**
13244 * Support Plugin
13245 *
13246 * @version 2.0.0-beta.3
13247 * @author Vivid Planet Software GmbH
13248 * @author Artus Kolanowski
13249 * @license The MIT License (MIT)
13250 */
13251;(function($, window, document, undefined) {
13252
13253	var style = $('<support>').get(0).style,
13254		prefixes = 'Webkit Moz O ms'.split(' '),
13255		events = {
13256			transition: {
13257				end: {
13258					WebkitTransition: 'webkitTransitionEnd',
13259					MozTransition: 'transitionend',
13260					OTransition: 'oTransitionEnd',
13261					transition: 'transitionend'
13262				}
13263			},
13264			animation: {
13265				end: {
13266					WebkitAnimation: 'webkitAnimationEnd',
13267					MozAnimation: 'animationend',
13268					OAnimation: 'oAnimationEnd',
13269					animation: 'animationend'
13270				}
13271			}
13272		},
13273		tests = {
13274			csstransforms: function() {
13275				return !!test('transform');
13276			},
13277			csstransforms3d: function() {
13278				return !!test('perspective');
13279			},
13280			csstransitions: function() {
13281				return !!test('transition');
13282			},
13283			cssanimations: function() {
13284				return !!test('animation');
13285			}
13286		};
13287
13288	function test(property, prefixed) {
13289		var result = false,
13290			upper = property.charAt(0).toUpperCase() + property.slice(1);
13291
13292		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
13293			if (style[property] !== undefined) {
13294				result = prefixed ? property : true;
13295				return false;
13296			}
13297		});
13298
13299		return result;
13300	}
13301
13302	function prefixed(property) {
13303		return test(property, true);
13304	}
13305
13306	if (tests.csstransitions()) {
13307		/* jshint -W053 */
13308		$.support.transition = new String(prefixed('transition'))
13309		$.support.transition.end = events.transition.end[ $.support.transition ];
13310	}
13311
13312	if (tests.cssanimations()) {
13313		/* jshint -W053 */
13314		$.support.animation = new String(prefixed('animation'))
13315		$.support.animation.end = events.animation.end[ $.support.animation ];
13316	}
13317
13318	if (tests.csstransforms()) {
13319		/* jshint -W053 */
13320		$.support.transform = new String(prefixed('transform'));
13321		$.support.transform3d = tests.csstransforms3d();
13322	}
13323
13324})(window.Zepto || window.jQuery, window, document);
13325
13326(function(window, document, undefined) {
13327
13328		/**
13329		 * Find the absolute position of an element
13330		 */
13331		var absPos = function(element) {
13332				var offsetLeft, offsetTop;
13333				offsetLeft = offsetTop = 0;
13334				if (element.offsetParent) {
13335						do {
13336								offsetLeft += element.offsetLeft;
13337								offsetTop += element.offsetTop;
13338						} while (element = element.offsetParent);
13339				}
13340				return [offsetLeft, offsetTop];
13341		};
13342
13343		/**
13344		 * @constructor Progress Circle class
13345		 * @param params.canvas Canvas on which the circles will be drawn.
13346		 * @param params.minRadius Inner radius of the innermost circle, in px.
13347		 * @param params.arcWidth Width of each circle(to be more accurate, ring).
13348		 * @param params.gapWidth Space between each circle.
13349		 * @param params.centerX X coordinate of the center of circles.
13350		 * @param params.centerY Y coordinate of the center of circles.
13351		 * @param params.infoLineBaseAngle Base angle of the info line.
13352		 * @param params.infoLineAngleInterval Angles between the info lines.
13353		 */
13354		var ProgressCircle = function(params) {
13355				this.canvas = params.canvas;
13356				this.minRadius = params.minRadius || 15;
13357				this.arcWidth = params.arcWidth || 5;
13358				this.gapWidth = params.gapWidth || 3;
13359				this.centerX = params.centerX || this.canvas.width / 2;
13360				this.centerY = params.centerY || this.canvas.height / 2;
13361				this.infoLineLength = params.infoLineLength || 60;
13362				this.horizLineLength = params.horizLineLength || 10;
13363				this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
13364				this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
13365
13366				this.context = this.canvas.getContext('2d');
13367
13368				this.width = this.canvas.width;
13369				this.height = this.canvas.height;
13370
13371				this.circles = [];
13372				this.runningCount = 0;
13373		};
13374
13375		ProgressCircle.prototype = {
13376				constructor: ProgressCircle,
13377
13378				/**
13379				 * @method Adds an progress monitor entry.
13380				 * @param params.fillColor Color to fill in the circle.
13381				 * @param params.outlineColor Color to outline the circle.
13382				 * @param params.progressListener Callback function to fetch the progress.
13383				 * @param params.infoListener Callback function to fetch the info.
13384				 * @returns this
13385				 */
13386				addEntry: function(params) {
13387						this.circles.push(new Circle({
13388								canvas: this.canvas,
13389								context: this.context,
13390								centerX: this.centerX,
13391								centerY: this.centerY,
13392								innerRadius: this.minRadius + this.circles.length *
13393										(this.gapWidth + this.arcWidth),
13394								arcWidth: this.arcWidth,
13395								infoLineLength: this.infoLineLength,
13396								horizLineLength: this.horizLineLength,
13397
13398								id: this.circles.length,
13399								fillColor: params.fillColor,
13400								outlineColor: params.outlineColor,
13401								progressListener: params.progressListener,
13402								infoListener: params.infoListener,
13403								infoLineAngle: this.infoLineBaseAngle +
13404										this.circles.length * this.infoLineAngleInterval,
13405						}));
13406
13407						return this;
13408				},
13409
13410				/**
13411				 * @method Starts the monitor and updates with the given interval.
13412				 * @param interval Interval between updates, in millisecond.
13413				 * @returns this
13414				 */
13415				start: function(interval) {
13416						var self = this;
13417						this.timer = setInterval(function() {
13418								self._update();
13419						}, interval || 33);
13420
13421						return this;
13422				},
13423
13424				/**
13425				 * @method Stop the animation.
13426				 */
13427				stop: function() {
13428						clearTimeout(this.timer);
13429				},
13430
13431				/**
13432				 * @private
13433				 * @method Call update on each circle and redraw them.
13434				 * @returns this
13435				 */
13436				_update: function() {
13437						this._clear();
13438						this.circles.forEach(function(circle, idx, array) {
13439								circle.update();
13440						});
13441
13442						return this;
13443				},
13444
13445				/**
13446				 * @private
13447				 * @method Clear the canvas.
13448				 * @returns this
13449				 */
13450				_clear: function() {
13451						this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
13452
13453						return this;
13454				},
13455
13456		};
13457
13458		/**
13459		 * @private
13460		 * @class Individual progress circle.
13461		 * @param params.canvas Canvas on which the circle will be drawn.
13462		 * @param params.context Context of the canvas.
13463		 * @param params.innerRadius Inner radius of the circle, in px.
13464		 * @param params.arcWidth Width of each arc(circle).
13465		 * @param params.gapWidth Distance between each arc.
13466		 * @param params.centerX X coordinate of the center of circles.
13467		 * @param params.centerY Y coordinate of the center of circles.
13468		 * @param params.fillColor Color to fill in the circle.
13469		 * @param params.outlineColor Color to outline the circle.
13470		 * @param params.progressListener Callback function to fetch the progress.
13471		 * @param params.infoListener Callback function to fetch the info.
13472		 * @param params.infoLineAngle Angle of info line.
13473		 */
13474		var Circle = function(params) {
13475				this.id = params.id;
13476				this.canvas = params.canvas;
13477				this.context = params.context;
13478				this.centerX = params.centerX;
13479				this.centerY = params.centerY;
13480				this.arcWidth = params.arcWidth;
13481				this.innerRadius = params.innerRadius || 0;
13482				this.fillColor = params.fillColor || '#fff';
13483				this.outlineColor = params.outlineColor || this.fillColor;
13484				this.progressListener = params.progressListener;
13485				this.infoLineLength = params.infoLineLength || 250;
13486				this.horizLineLength = params.horizLineLength || 50;
13487				this.infoListener = params.infoListener;
13488				this.infoLineAngle = params.infoLineAngle;
13489
13490				this.outerRadius = this.innerRadius + this.arcWidth;
13491
13492				// If the info listener is not registered, then don't calculate
13493				// the related coordinates
13494				if (!this.infoListener) return;
13495
13496				// calculate the info-line turning points
13497				var angle = this.infoLineAngle,
13498						arcDistance = (this.innerRadius + this.outerRadius) / 2,
13499
13500						sinA = Math.sin(angle),
13501						cosA = Math.cos(angle);
13502
13503				this.infoLineStartX = this.centerX + sinA * arcDistance;
13504				this.infoLineStartY = this.centerY - cosA * arcDistance;
13505
13506				this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
13507				this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
13508
13509				this.infoLineEndX = this.infoLineMidX +
13510						 (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
13511				this.infoLineEndY = this.infoLineMidY;
13512
13513				var infoText = document.createElement('div'),
13514						style = infoText.style;
13515
13516				style.color = this.fillColor;
13517				style.position = 'absolute';
13518				style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
13519				// style.top will be calculated in the `drawInfo` method. Since
13520				// user may want to change the size of the font, so the top offset
13521				// must be updated in each loop.
13522				infoText.className = 'ProgressCircleInfo'; // For css styling
13523				infoText.id = 'progress_circle_info_' + this.id;
13524				document.body.appendChild(infoText);
13525				this.infoText = infoText;
13526		};
13527
13528		Circle.prototype = {
13529				constructor: Circle,
13530
13531				update: function() {
13532						this.progress = this.progressListener();
13533						this._draw();
13534
13535						if (this.infoListener) {
13536								this.info = this.infoListener();
13537								this._drawInfo();
13538						}
13539				},
13540
13541				/**
13542				 * @private
13543				 * @method Draw the circle on the canvas.
13544				 * @returns this
13545				 */
13546				_draw: function() {
13547						var ctx = this.context,
13548
13549								ANGLE_OFFSET = -Math.PI / 2,
13550
13551								startAngle = 0 + ANGLE_OFFSET,
13552								endAngle= startAngle + this.progress * Math.PI * 2,
13553
13554								x = this.centerX,
13555								y = this.centerY,
13556
13557								innerRadius = this.innerRadius - this.arcWidth - 1,
13558								outerRadius = this.outerRadius - this.arcWidth - 1;
13559
13560						ctx.fillStyle = this.fillColor;
13561						ctx.strokeStyle = this.outlineColor;
13562
13563						ctx.beginPath();
13564						ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
13565						ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
13566						ctx.closePath();
13567						ctx.stroke();
13568						ctx.fill();
13569
13570						return this;
13571				},
13572
13573				/**
13574				 * @private
13575				 * @method Draw the info lines and info text.
13576				 * @returns this
13577				 */
13578				_drawInfo: function() {
13579
13580						var pointList, lineHeight;
13581
13582						pointList = [
13583								[this.infoLineStartX, this.infoLineStartY],
13584								[this.infoLineMidX, this.infoLineMidY],
13585								[this.infoLineEndX, this.infoLineEndY],
13586						];
13587						this._drawSegments(pointList, false);
13588
13589						this.infoText.innerHTML = this.info;
13590
13591						lineHeight = this.infoText.offsetHeight;
13592						this.infoText.style.top = this.infoLineEndY +
13593								absPos(this.canvas)[1] - lineHeight / 2 + 'px';
13594
13595						return this;
13596				},
13597
13598				/**
13599				 * @private
13600				 * @method Helper function to draw the segments
13601				 * @param pointList An array of points in the form of [x, y].
13602				 * @param close Whether to connect the first and last point.
13603				 */
13604				_drawSegments: function(pointList, close) {
13605						var ctx = this.context;
13606
13607						ctx.beginPath();
13608						ctx.moveTo(pointList[0][0], pointList[0][1]);
13609						for (var i = 1; i < pointList.length; ++i) {
13610								ctx.lineTo(pointList[i][0], pointList[i][1]);
13611						}
13612
13613						if (close) {
13614								ctx.closePath();
13615						}
13616						ctx.stroke();
13617				},
13618		};
13619
13620		window.ProgressCircle = ProgressCircle;
13621
13622})(window, document);
13623
13624
13625
13626
13627/* =========================================================
13628 * jquery.vc_chart.js v1.0
13629 * =========================================================
13630 * Copyright 2013 Wpbakery
13631 *
13632 * Jquery chart plugin for the Visual Composer.
13633 * ========================================================= */
13634(function($){
13635		/**
13636		 * Pie chart animated.
13637		 * @param element - DOM element
13638		 * @param options - settings object.
13639		 * @constructor
13640		 */
13641		var VcChart = function(element, options) {
13642				this.el = element;
13643				this.$el = $(this.el);
13644				this.options = $.extend({
13645						color: 'wpb_button',
13646						units: '',
13647						width: '',
13648						label_selector: '.vc_pie_chart_value',
13649						back_selector: '.vc_pie_chart_back',
13650						responsive: true
13651				}, options);
13652				this.init();
13653		};
13654		VcChart.prototype = {
13655				constructor: VcChart,
13656				_progress_v: 0,
13657				animated: false,
13658				colors: {
13659						'wpb_button': 'rgba(247, 247, 247, 1)',
13660						'btn-primary': 'rgba(0, 136, 204, 1)',
13661						'btn-info': 'rgba(88, 185, 218, 1)',
13662						'btn-success': 'rgba(106, 177, 101, 1)',
13663						'btn-warning': 'rgba(255, 153, 0, 1)',
13664						'btn-danger': 'rgba(255, 103, 91, 1)',
13665						'btn-inverse': 'rgba(85, 85, 85, 1)'
13666				},
13667				init: function() {
13668						this.setupColor();
13669						this.value = this.$el.data('pie-value')/100;
13670						this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
13671						this.$wrapper = $('.vc_pie_wrapper', this.$el);
13672						this.$label = $(this.options.label_selector, this.$el);
13673						this.$back = $(this.options.back_selector, this.$el);
13674						this.$canvas = this.$el.find('canvas');
13675						this.arcWidth = this.$el.data('pie-width') * 2;
13676						this.draw();
13677						this.setWayPoint();
13678						if(this.options.responsive === true) this.setResponsive();
13679						if (UNCODE.isMobile) this._progress_v = this.value;
13680				},
13681				setupColor: function() {
13682						// if(typeof this.colors[this.options.color] !== 'undefined') {
13683						//     this.color = this.colors[this.options.color];
13684						// } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
13685						//     this.color = this.options.color;
13686						// } else {
13687						//     this.color = 'rgba(247, 247, 247, 0.2)';
13688						// }
13689						if(typeof this.options.color !== 'undefined') {
13690								this.color = this.options.color;
13691						} else this.color = 'rgba(247, 247, 247, 0.2)';
13692
13693				},
13694				setResponsive: function() {
13695						var that = this;
13696						if (!UNCODE.isMobile) {
13697								$(window).resize(function(){
13698										if(that.animated === true) that.circle.stop();
13699										that.draw(true);
13700								});
13701						}
13702				},
13703					draw: function(redraw) {
13704						var w = this.$el.addClass('vc_ready').width() * 2,
13705								border_w = this.arcWidth,
13706								radius;
13707						if(!w) w = this.$el.parents(':visible').first().width()-2;
13708						//w = Math.round(w/100*80);
13709						//if (w < 250) w = 250;
13710						radius = w/2;
13711						this.$wrapper.css({"width" : (w / 2) + "px"});
13712						this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
13713						this.$back.css({"width" : (w / 2), "height" : (w / 2)});
13714						this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
13715						this.$el.addClass('vc_ready');
13716						this.circle = new ProgressCircle({
13717								canvas: this.$canvas.get(0),
13718								minRadius: radius,
13719								arcWidth: border_w
13720						});
13721						if(redraw === true && this.animated === true) {
13722								this._progress_v = this.value;
13723								this.circle.addEntry({
13724										fillColor: this.color,
13725										progressListener: $.proxy(this.setProgress, this)
13726								}).start();
13727						}
13728				},
13729				setProgress: function() {
13730						if (this._progress_v >= this.value) {
13731								this.circle.stop();
13732								this.$label.html(this.label_value + this.options.units);
13733								return this._progress_v;
13734						}
13735						this._progress_v += 0.01;
13736						if (!isNaN(this.label_value)) {
13737								var label_value = this._progress_v/this.value*this.label_value;
13738								var val = Math.round(label_value) + this.options.units;
13739								this.$label.html(val);
13740						} else this.$label.html(this.label_value + this.options.units);
13741						return this._progress_v;
13742				},
13743				animate: function() {
13744						if(this.animated !== true) {
13745								this.animated = true;
13746								this.circle.addEntry({
13747										fillColor: this.color,
13748										progressListener: $.proxy(this.setProgress, this)
13749								}).start(5);
13750						}
13751				},
13752				setWayPoint: function() {
13753						if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
13754								this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
13755						} else {
13756								this.animate();
13757						}
13758				}
13759		};
13760		/**
13761		 * jQuery plugin
13762		 * @param option - object with settings
13763		 * @return {*}
13764		 */
13765		$.fn.vcChat = function(option, value) {
13766				return this.each(function () {
13767						var $this = $(this),
13768								data = $this.data('vc_chart'),
13769								options = typeof option === 'object' ? option : {
13770										color: $this.data('pie-color'),
13771										units: $this.data('pie-units')
13772								};
13773						if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
13774						if (typeof option == 'string') data[option](value);
13775				});
13776		};
13777		/**
13778		 * Allows users to rewrite function inside theme.
13779		 */
13780		if ( typeof window['vc_pieChart'] !== 'function' ) {
13781				window.vc_pieChart = function() {
13782						$('.vc_pie_chart:visible').vcChat();
13783				}
13784		}
13785		$(document).ready(function(){
13786				!window.vc_iframe && vc_pieChart();
13787		});
13788
13789})(window.jQuery);
13790
13791
13792/* Progress bar
13793 ---------------------------------------------------------- */
13794function uncode_progress_bar() {    
13795	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
13796		if (!UNCODE.isMobile) {
13797			new Waypoint({
13798				element: val,
13799				handler: function() {
13800					var element = jQuery(this.element);
13801					element.find('.vc_single_bar').each(function(index) {          
13802						var $this = jQuery(this),
13803													bar = $this.find('.vc_bar'),
13804													val = bar.data('percentage-value');          
13805						setTimeout(function() {            
13806							bar.css({
13807								"width": val + '%'
13808							});          
13809						}, index * 200);        
13810					});
13811				},
13812				offset: '80%'
13813			});
13814		} else {
13815			var element = jQuery(val);
13816			element.find('.vc_single_bar').each(function(index) {          
13817				var $this = jQuery(this),
13818											bar = $this.find('.vc_bar'),
13819											val = bar.data('percentage-value');          
13820				setTimeout(function() {            
13821					bar.css({
13822						"width": val + '%'
13823					});          
13824				}, index * 200);        
13825			});
13826		}
13827	});
13828};
13829uncode_progress_bar();
13830
13831/*!
13832 * jquery.counterup.js 1.0
13833 *
13834 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
13835 * Released under the GPL v2 License
13836 *
13837 * Date: Nov 26, 2013
13838 */
13839(function($) {
13840	"use strict";
13841	$.fn.counterUp = function(options) {
13842		// Defaults
13843		var settings = $.extend({
13844			'time': 400,
13845			'delay': 10
13846		}, options);
13847		return this.each(function() {
13848			// Store the object
13849			var $this = $(this);
13850			var $settings = settings;
13851			var counterUpper = function() {
13852				var nums = [];
13853				var divisions = $settings.time / $settings.delay;
13854				var numReal = $this.text(),
13855				num = numReal;
13856				var isComma = /[0-9]+,[0-9]+/.test(num);
13857				num = num.replace(/,/g, '');
13858				var isInt = /^[0-9]+$/.test(num);
13859				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
13860				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
13861				// Generate list of incremental numbers to display
13862				for (var i = divisions; i >= 1; i--) {
13863					// Preserve as int if input was int
13864					var newNum = parseInt(num / divisions * i);
13865					// Preserve float if input was float
13866					if (isFloat) {
13867						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
13868					}
13869					// Preserve commas if input had commas
13870					if (isComma) {
13871						while (/(\d+)(\d{3})/.test(newNum.toString())) {
13872							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
13873						}
13874					}
13875					nums.unshift(newNum);
13876				}
13877				nums.push(numReal);
13878				$this.data('counterup-nums', nums);
13879				$this.text('0');
13880				// Updates the number until we're done
13881				var f = function() {
13882					if ($this.data('counterup-nums') != null) {
13883						$this.text($this.data('counterup-nums').shift());
13884						if ($this.data('counterup-nums').length) {
13885							setTimeout($this.data('counterup-func'), $settings.delay);
13886						} else {
13887							delete $this.data('counterup-nums');
13888							$this.data('counterup-nums', null);
13889							$this.data('counterup-func', null);
13890						}
13891					}
13892				};
13893				$this.data('counterup-func', f);
13894				// Start the count up
13895				setTimeout($this.data('counterup-func'), $settings.delay);
13896			};
13897			// Perform counts when the element gets into view
13898			new Waypoint({
13899				element: this,
13900				handler: function() {
13901					counterUpper();
13902					this.destroy();
13903				},
13904				offset: '80%'
13905			});
13906		});
13907	};
13908})(jQuery);
13909
13910/*!
13911 * The Final Countdown for jQuery v2.0.4 (http://hilios.github.io/jQuery.countdown/)
13912 * Copyright (c) 2014 Edson Hilios
13913 *
13914 * Permission is hereby granted, free of charge, to any person obtaining a copy of
13915 * this software and associated documentation files (the "Software"), to deal in
13916 * the Software without restriction, including without limitation the rights to
13917 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13918 * the Software, and to permit persons to whom the Software is furnished to do so,
13919 * subject to the following conditions:
13920 *
13921 * The above copyright notice and this permission notice shall be included in all
13922 * copies or substantial portions of the Software.
13923 *
13924 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13925 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
13926 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13927 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13928 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
13929 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13930 */
13931!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;
13931if(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])})}});
13932
13933/*! waitForImages jQuery Plugin - v2.0.2 - 2015-05-05
13934* https://github.com/alexanderdickson/waitForImages
13935* Copyright (c) 2015 Alex Dickson; Licensed MIT */
13936;(function (factory) {
13937		if (typeof define === 'function' && define.amd) {
13938				// AMD. Register as an anonymous module.
13939				define(['jquery'], factory);
13940		} else if (typeof exports === 'object') {
13941				// CommonJS / nodejs module
13942				module.exports = factory(require('jquery'));
13943		} else {
13944				// Browser globals
13945				factory(jQuery);
13946		}
13947}(function ($) {
13948		// Namespace all events.
13949		var eventNamespace = 'waitForImages';
13950
13951		// CSS properties which contain references to images.
13952		$.waitForImages = {
13953				hasImageProperties: [
13954						'backgroundImage',
13955						'listStyleImage',
13956						'borderImage',
13957						'borderCornerImage',
13958						'cursor'
13959				],
13960				hasImageAttributes: ['srcset']
13961		};
13962
13963		// Custom selector to find `img` elements that have a valid `src`
13964		// attribute and have not already loaded.
13965		$.expr[':'].uncached = function (obj) {
13966				// Ensure we are dealing with an `img` element with a valid
13967				// `src` attribute.
13968				if (!$(obj).is('img[src][src!=""]')) {
13969						return false;
13970				}
13971
13972				return !obj.complete;
13973		};
13974
13975		$.fn.waitForImages = function () {
13976
13977				var allImgsLength = 0;
13978				var allImgsLoaded = 0;
13979				var deferred = $.Deferred();
13980
13981				var finishedCallback;
13982				var eachCallback;
13983				var waitForAll;
13984
13985				// Handle options object (if passed).
13986				if ($.isPlainObject(arguments[0])) {
13987
13988						waitForAll = arguments[0].waitForAll;
13989						eachCallback = arguments[0].each;
13990						finishedCallback = arguments[0].finished;
13991
13992				} else {
13993
13994						// Handle if using deferred object and only one param was passed in.
13995						if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
13996								waitForAll = arguments[0];
13997						} else {
13998								finishedCallback = arguments[0];
13999								eachCallback = arguments[1];
14000								waitForAll = arguments[2];
14001						}
14002
14003				}
14004
14005				// Handle missing callbacks.
14006				finishedCallback = finishedCallback || $.noop;
14007				eachCallback = eachCallback || $.noop;
14008
14009				// Convert waitForAll to Boolean
14010				waitForAll = !! waitForAll;
14011
14012				// Ensure callbacks are functions.
14013				if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
14014						throw new TypeError('An invalid callback was supplied.');
14015				}
14016
14017				this.each(function () {
14018						// Build a list of all imgs, dependent on what images will
14019						// be considered.
14020						var obj = $(this);
14021						var allImgs = [];
14022						// CSS properties which may contain an image.
14023						var hasImgProperties = $.waitForImages.hasImageProperties || [];
14024						// Element attributes which may contain an image.
14025						var hasImageAttributes = $.waitForImages.hasImageAttributes || [];
14026						// To match `url()` references.
14027						// Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
14028						var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
14029
14030						if (waitForAll) {
14031
14032								// Get all elements (including the original), as any one of
14033								// them could have a background image.
14034								obj.find('*').addBack().each(function () {
14035										var element = $(this);
14036
14037										// If an `img` element, add it. But keep iterating in
14038										// case it has a background image too.
14039										if (element.is('img:uncached')) {
14040												allImgs.push({
14041														src: element.attr('src'),
14042														element: element[0]
14043												});
14044										}
14045
14046										$.each(hasImgProperties, function (i, property) {
14047												var propertyValue = element.css(property);
14048												var match;
14049
14050												// If it doesn't contain this property, skip.
14051												if (!propertyValue) {
14052														return true;
14053												}
14054
14055												// Get all url() of this element.
14056												while (match = matchUrl.exec(propertyValue)) {
14057														allImgs.push({
14058																src: match[2],
14059																element: element[0]
14060														});
14061												}
14062										});
14063
14064										$.each(hasImageAttributes, function (i, attribute) {
14065												var attributeValue = element.attr(attribute);
14066												var attributeValues;
14067
14068												// If it doesn't contain this property, skip.
14069												if (!attributeValue) {
14070														return true;
14071												}
14072
14073												// Check for multiple comma separated images
14074												attributeValues = attributeValue.split(',');
14075
14076												$.each(attributeValues, function(i, value) {
14077														// Trim value and get string before first
14078														// whitespace (for use with srcset).
14079														value = $.trim(value).split(' ')[0];
14080														allImgs.push({
14081																src: value,
14082																element: element[0]
14083														});
14084												});
14085										});
14086								});
14087						} else {
14088								// For images only, the task is simpler.
14089								obj.find('img:uncached')
14090										.each(function () {
14091										allImgs.push({
14092												src: this.src,
14093												element: this
14094										});
14095								});
14096						}
14097
14098						allImgsLength = allImgs.length;
14099						allImgsLoaded = 0;
14100
14101						// If no images found, don't bother.
14102						if (allImgsLength === 0) {
14103								finishedCallback.call(obj[0]);
14104								deferred.resolveWith(obj[0]);
14105						}
14106
14107						$.each(allImgs, function (i, img) {
14108
14109								var image = new Image();
14110								var events =
14111									'load.' + eventNamespace + ' error.' + eventNamespace;
14112
14113								// Handle the image loading and error with the same callback.
14114								$(image).one(events, function me (event) {
14115										// If an error occurred with loading the image, set the
14116										// third argument accordingly.
14117										var eachArguments = [
14118												allImgsLoaded,
14119												allImgsLength,
14120												event.type == 'load'
14121										];
14122										allImgsLoaded++;
14123
14124										eachCallback.apply(img.element, eachArguments);
14125										deferred.notifyWith(img.element, eachArguments);
14126
14127										// Unbind the event listeners. I use this in addition to
14128										// `one` as one of those events won't be called (either
14129										// 'load' or 'error' will be called).
14130										$(this).off(events, me);
14131
14132										if (allImgsLoaded == allImgsLength) {
14133												finishedCallback.call(obj[0]);
14134												deferred.resolveWith(obj[0]);
14135												return false;
14136										}
14137
14138								});
14139
14140								image.src = img.src;
14141						});
14142				});
14143
14144				return deferred.promise();
14145
14146		};
14147}));
14148
14149/**
14150 * @preserve  textfill
14151 * @name      jquery.textfill.js
14152 * @author    Russ Painter
14153 * @author    Yu-Jie Lin
14154 * @author    Alexandre Dantas
14155 * @version   0.6.0
14156 * @date      2014-08-19
14157 * @copyright (c) 2014 Alexandre Dantas
14158 * @copyright (c) 2012-2013 Yu-Jie Lin
14159 * @copyright (c) 2009 Russ Painter
14160 * @license   MIT License
14161 * @homepage  https://github.com/jquery-textfill/jquery-textfill
14162 * @example   http://jquery-textfill.github.io/jquery-textfill/index.html
14163 */
14164; (function($) {
14165
14166	/**
14167	 * Resizes an inner element's font so that the
14168	 * inner element completely fills the outer element.
14169	 *
14170	 * @param {Object} options User options that take
14171	 *                         higher precedence when
14172	 *                         merging with the default ones.
14173	 *
14174	 * @return All outer elements processed
14175	 */
14176	$.fn.textfill = function(options) {
14177
14178		// ______  _______ _______ _______ _     _        _______ _______
14179		// |     \ |______ |______ |_____| |     | |         |    |______
14180		// |_____/ |______ |       |     | |_____| |_____    |    ______|
14181				//
14182		// Merging user options with the default values
14183
14184		var defaults = {
14185			debug            : false,
14186			maxFontPixels    : 40,
14187			minFontPixels    : 4,
14188			innerTag         : 'span',
14189			widthOnly        : false,
14190			success          : null, // callback when a resizing is done
14191			callback         : null, // callback when a resizing is done (deprecated, use success)
14192			fail             : null, // callback when a resizing is failed
14193			complete         : null, // callback when all is done
14194			explicitWidth    : null,
14195			explicitHeight   : null,
14196			changeLineHeight : false
14197		};
14198
14199		var Opts = $.extend(defaults, options);
14200
14201		// _______ _     _ __   _ _______ _______ _____  _____  __   _ _______
14202		// |______ |     | | \  | |          |      |   |     | | \  | |______
14203		// |       |_____| |  \_| |_____     |    __|__ |_____| |  \_| ______|
14204		//
14205		// Predefining the awesomeness
14206
14207		// Output arguments to the Debug console
14208		// if "Debug Mode" is enabled
14209		function _debug() {
14210			if (!Opts.debug
14211				||  typeof console       == 'undefined'
14212				||  typeof console.debug == 'undefined') {
14213				return;
14214			}
14215			console.debug.apply(console, arguments);
14216		}
14217
14218		// Output arguments to the Warning console
14219		function _warn() {
14220			if (typeof console      == 'undefined' ||
14221				typeof console.warn == 'undefined') {
14222				return;
14223			}
14224			console.warn.apply(console, arguments);
14225		}
14226
14227		// Outputs all information on the current sizing
14228		// of the font.
14229		function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
14230
14231			function _m(v1, v2) {
14232
14233				var marker = ' / ';
14234
14235				if (v1 > v2)
14236					marker = ' > ';
14237
14238				else if (v1 == v2)
14239					marker = ' = ';
14240
14241				return marker;
14242			}
14243
14244			_debug(
14245				'[TextFill] '  + prefix + ' { ' +
14246				'font-size: ' + ourText.css('font-size') + ',' +
14247				'Height: '    + ourText.height() + 'px ' + _m(ourText.height(), maxHeight) + maxHeight + 'px,' +
14248				'Width: '     + ourText.width()  + _m(ourText.width() , maxWidth)  + maxWidth + ',' +
14249				'minFontPixels: ' + minFontPixels + 'px, ' +
14250				'maxFontPixels: ' + maxFontPixels + 'px }'
14251			);
14252		}
14253
14254		/**
14255		 * Calculates which size the font can get resized,
14256		 * according to constrains.
14257		 *
14258		 * @param {String} prefix Gets shown on the console before
14259		 *                        all the arguments, if debug mode is on.
14260		 * @param {Object} ourText The DOM element to resize,
14261		 *                         that contains the text.
14262		 * @param {function} func Function called on `ourText` that's
14263		 *                        used to compare with `max`.
14264		 * @param {number} max Maximum value, that gets compared with
14265		 *                     `func` called on `ourText`.
14266		 * @param {number} minFontPixels Minimum value the font can
14267		 *                               get resized to (in pixels).
14268		 * @param {number} maxFontPixels Maximum value the font can
14269		 *                               get resized to (in pixels).
14270		 *
14271		 * @return Size (in pixels) that the font can be resized.
14272		 */
14273		function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
14274
14275			_debug_sizing(
14276				prefix, ourText,
14277				maxHeight, maxWidth,
14278				minFontPixels, maxFontPixels
14279			);
14280
14281			// The kernel of the whole plugin, take most attention
14282			// on this part.
14283			//
14284			// This is a loop that keeps increasing the `font-size`
14285			// until it fits the parent element.
14286			//
14287			// - Start from the minimal allowed value (`minFontPixels`)
14288			// - Guesses an average font size (in pixels) for the font,
14289			// - Resizes the text and sees if its size is within the
14290			//   boundaries (`minFontPixels` and `maxFontPixels`).
14291			//   - If so, keep guessing until we break.
14292			//   - If not, return the last calculated size.
14293			//
14294			// I understand this is not optimized and we should
14295			// consider implementing something akin to
14296			// Daniel Hoffmann's answer here:
14297			//
14298			//     http://stackoverflow.com/a/17433451/1094964
14299			//
14300
14301			while (minFontPixels < (maxFontPixels - 1)) {
14302
14303				var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2);
14304				ourText.css('font-size', fontSize);
14305
14306				if (func.call(ourText) <= max) {
14307					minFontPixels = fontSize;
14308
14309					if (func.call(ourText) == max)
14310						break;
14311				}
14312				else
14313					maxFontPixels = fontSize;
14314
14315				_debug_sizing(
14316					prefix, ourText,
14317					maxHeight, maxWidth,
14318					minFontPixels, maxFontPixels
14319				);
14320			}
14321
14322			ourText.css('font-size', maxFontPixels);
14323
14324			if (func.call(ourText) <= max) {
14325				minFontPixels = maxFontPixels;
14326
14327				_debug_sizing(
14328					prefix + '* ', ourText,
14329					maxHeight, maxWidth,
14330					minFontPixels, maxFontPixels
14331				);
14332			}
14333			return minFontPixels;
14334		}
14335
14336		// _______ _______ _______  ______ _______
14337		// |______    |    |_____| |_____/    |
14338		// ______|    |    |     | |    \_    |
14339				//
14340		// Let's get it started (yeah)!
14341
14342		_debug('[TextFill] Start Debug');
14343
14344		this.each(function() {
14345
14346			// Contains the child element we will resize.
14347			// $(this) means the parent container
14348			var ourText = $(Opts.innerTag + ':visible:first', this);
14349
14350			// Will resize to this dimensions.
14351			// Use explicit dimensions when specified
14352			var maxHeight = Opts.explicitHeight || $(this).height();
14353			var maxWidth  = Opts.explicitWidth  || $(this).width();
14354
14355			var oldFontSize = ourText.css('font-size');
14356
14357			var lineHeight  = parseFloat(ourText.css('line-height')) / parseFloat(oldFontSize);
14358
14359			_debug('[TextFill] Inner text: ' + ourText.text());
14360			_debug('[TextFill] All options: ', Opts);
14361			_debug('[TextFill] Maximum sizes: { ' +
14362					 'Height: ' + maxHeight + 'px, ' +
14363					 'Width: '  + maxWidth  + 'px' + ' }'
14364					);
14365
14366			var minFontPixels = Opts.minFontPixels;
14367
14368			// Remember, if this `maxFontPixels` is negative,
14369			// the text will resize to as long as the container
14370			// can accomodate
14371			var maxFontPixels = (Opts.maxFontPixels <= 0 ?
14372								 maxHeight :
14373								 Opts.maxFontPixels);
14374
14375
14376			// Let's start it all!
14377
14378			// 1. Calculate which `font-size` would
14379			//    be best for the Height
14380			var fontSizeHeight = undefined;
14381
14382			if (! Opts.widthOnly)
14383				fontSizeHeight = _sizing(
14384					'Height', ourText,
14385					$.fn.height, maxHeight,
14386					maxHeight, maxWidth,
14387					minFontPixels, maxFontPixels
14388				);
14389
14390			// 2. Calculate which `font-size` would
14391			//    be best for the Width
14392			var fontSizeWidth = undefined;
14393
14394			fontSizeWidth = _sizing(
14395				'Width', ourText,
14396				$.fn.width, maxWidth,
14397				maxHeight, maxWidth,
14398				minFontPixels, maxFontPixels
14399			);
14400
14401			// 3. Actually resize the text!
14402
14403			if (Opts.widthOnly) {
14404				ourText.css({
14405					'font-size'  : fontSizeWidth,
14406					'white-space': 'nowrap'
14407				});
14408
14409				if (Opts.changeLineHeight)
14410					ourText.parent().css(
14411						'line-height',
14412						(lineHeight * fontSizeWidth + 'px')
14413					);
14414			}
14415			else {
14416				var fontSizeFinal = Math.min(fontSizeHeight, fontSizeWidth);
14417
14418				ourText.css('font-size', fontSizeFinal);
14419
14420				if (Opts.changeLineHeight)
14421					ourText.parent().css(
14422						'line-height',
14423						(lineHeight * fontSizeFinal) + 'px'
14424					);
14425			}
14426
14427			_debug(
14428				'[TextFill] Finished { ' +
14429				'Old font-size: ' + oldFontSize              + ', ' +
14430				'New font-size: ' + ourText.css('font-size') + ' }'
14431			);
14432
14433			// Oops, something wrong happened!
14434			// We weren't supposed to exceed the original size
14435			if ((ourText.width()  > maxWidth) ||
14436				(ourText.height() > maxHeight && !Opts.widthOnly)) {
14437
14438				ourText.css('font-size', oldFontSize);
14439
14440				// Failure callback
14441				if (Opts.fail)
14442					Opts.fail(this);
14443
14444				_debug(
14445					'[TextFill] Failure { ' +
14446					'Current Width: '  + ourText.width()  + ', ' +
14447					'Maximum Width: '  + maxWidth         + ', ' +
14448					'Current Height: ' + ourText.height() + ', ' +
14449					'Maximum Height: ' + maxHeight        + ' }'
14450				);
14451			}
14452			else if (Opts.success) {
14453				Opts.success(this);
14454			}
14455			else if (Opts.callback) {
14456				_warn('callback is deprecated, use success, instead');
14457
14458				// Success callback
14459				Opts.callback(this);
14460			}
14461		});
14462
14463		// Complete callback
14464		if (Opts.complete)
14465			Opts.complete(this);
14466
14467		_debug('[TextFill] End Debug');
14468		return this;
14469	};
14470
14471})(window.jQuery);
14472
14473
14474!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;
14475function getStyles(config){
14476	// 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;
14476left: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+"}"
14477};
14478	var ShareUtils;
14479
14480if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
14481	Object.defineProperty(HTMLElement.prototype, "classList", {
14482		get: function() {
14483			var ret, self, update;
14484			update = function(fn) {
14485				return function(value) {
14486					var classes, index;
14487					classes = self.className.split(/\s+/);
14488					index = classes.indexOf(value);
14489					fn(classes, index, value);
14490					self.className = classes.join(" ");
14491				};
14492			};
14493			self = this;
14494			ret = {
14495				add: update(function(classes, index, value) {
14496					~index || classes.push(value);
14497				}),
14498				remove: update(function(classes, index) {
14499					~index && classes.splice(index, 1);
14500				}),
14501				toggle: update(function(classes, index, value) {
14502					if (~index) {
14503						classes.splice(index, 1);
14504					} else {
14505						classes.push(value);
14506					}
14507				}),
14508				contains: function(value) {
14509					return !!~self.className.split(/\s+/).indexOf(value);
14510				},
14511				item: function(i) {
14512					return self.className.split(/\s+/)[i] || null;
14513				}
14514			};
14515			Object.defineProperty(ret, "length", {
14516				get: function() {
14517					return self.className.split(/\s+/).length;
14518				}
14519			});
14520			return ret;
14521		}
14522	});
14523}
14524
14525String.prototype.to_rfc3986 = function() {
14526	var tmp;
14527	tmp = encodeURIComponent(this);
14528	return tmp.replace(/[!'()*]/g, function(c) {
14529		return "%" + c.charCodeAt(0).toString(16);
14530	});
14531};
14532
14533ShareUtils = (function() {
14534	function ShareUtils() {}
14535
14536	ShareUtils.prototype.extend = function(to, from, overwrite) {
14537		var hasProp, prop;
14538		for (prop in from) {
14539			hasProp = to[prop] !== undefined;
14540			if (hasProp && typeof from[prop] === "object") {
14541				this.extend(to[prop], from[prop], overwrite);
14542			} else {
14543				if (overwrite || !hasProp) {
14544					to[prop] = from[prop];
14545				}
14546			}
14547		}
14548	};
14549
14550	ShareUtils.prototype.hide = function(el) {
14551		return el.style.display = "none";
14552	};
14553
14554	ShareUtils.prototype.show = function(el) {
14555		return el.style.display = "block";
14556	};
14557
14558	ShareUtils.prototype.has_class = function(el, class_name) {
14559		return el.classList.contains(class_name);
14560	};
14561
14562	ShareUtils.prototype.add_class = function(el, class_name) {
14563		return el.classList.add(class_name);
14564	};
14565
14566	ShareUtils.prototype.remove_class = function(el, class_name) {
14567		return el.classList.remove(class_name);
14568	};
14569
14570	ShareUtils.prototype.is_encoded = function(str) {
14571		str = str.to_rfc3986();
14572		return decodeURIComponent(str) !== str;
14573	};
14574
14575	ShareUtils.prototype.encode = function(str) {
14576		if (typeof str === "undefined" || this.is_encoded(str)) {
14577			return str;
14578		} else {
14579			return str.to_rfc3986();
14580		}
14581	};
14582
14583	ShareUtils.prototype.popup = function(url, params) {
14584		var k, popup, qs, v;
14585		if (params == null) {
14586			params = {};
14587		}
14588		popup = {
14589			width: 500,
14590			height: 350
14591		};
14592		popup.top = (screen.height / 2) - (popup.height / 2);
14593		popup.left = (screen.width / 2) - (popup.width / 2);
14594		qs = ((function() {
14595			var _results;
14596			_results = [];
14597			for (k in params) {
14598				v = params[k];
14599				_results.push("" + k + "=" + (this.encode(v)));
14600			}
14601			return _results;
14602		}).call(this)).join('&');
14603		if (qs) {
14604			qs = "?" + qs;
14605		}
14606		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=" 
14606+ popup.width + ",height=" + popup.height);
14607	};
14608
14609	return ShareUtils;
14610
14611})();
14612var Share,
14613	__hasProp = {}.hasOwnProperty,
14614	__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; };
14615
14616Share = (function(_super) {
14617	__extends(Share, _super);
14618
14619	function Share(element, options) {
14620		this.element = element;
14621		this.el = {
14622			head: document.getElementsByTagName('head')[0],
14623			body: document.getElementsByTagName('body')[0]
14624		};
14625		this.config = {
14626			enabled_networks: 0,
14627			protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
14628			url: window.location.href.replace("&", "%26"),
14629			caption: null,
14630			title: this.default_title(),
14631			image: this.default_image(),
14632			description: this.default_description(),
14633			ui: {
14634				flyout: 'top center',
14635				button_text: 'Share',
14636				button_font: true,
14637				icon_font: true
14638			},
14639			networks: {
14640				google_plus: {
14641					enabled: true,
14642					url: null
14643				},
14644				twitter: {
14645					enabled: true,
14646					url: null,
14647					title: null,
14648					description: null
14649				},
14650				facebook: {
14651					enabled: true,
14652					load_sdk: true,
14653					url: null,
14654					app_id: null,
14655					title: null,
14656					caption: null,
14657					description: null,
14658					image: null
14659				},
14660				pinterest: {
14661					enabled: true,
14662					url: null,
14663					image: null,
14664					description: null
14665				},
14666				reddit: {
14667					enabled: true,
14668					url: null,
14669					title: null
14670				},
14671				linkedin: {
14672					enabled: true,
14673					url: null,
14674					title: null,
14675					description: null
14676				},
14677				xing: {
14678					enabled: true,
14679					url: null,
14680					title: null,
14681					image: null,
14682					description: null
14683				},
14684				whatsapp: {
14685					enabled: true,
14686					description: null,
14687					url: null
14688				},
14689				email: {
14690					enabled: true,
14691					title: null,
14692					description: null,
14693					url: null
14694				}
14695			}
14696		};
14697		this.setup(element, options);
14698		return this;
14699	}
14700
14701	Share.prototype.setup = function(element, opts) {
14702		var index, instance, instances, _i, _len;
14703		instances = document.querySelectorAll(element);
14704		this.extend(this.config, opts, true);
14705		this.set_global_configuration();
14706		this.normalize_network_configuration();
14707		if (this.config.ui.icon_font) {
14708			this.inject_icons();
14709		}
14710		if (this.config.ui.button_font) {
14711			this.inject_fonts();
14712		}
14713		if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
14714			this.inject_facebook_sdk();
14715		}
14716		for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
14717			instance = instances[index];
14718			this.setup_instance(element, index);
14719		}
14720	};
14721
14722	Share.prototype.setup_instance = function(element, index) {
14723		var button, instance, label, network, networks, _i, _len, _results,
14724			_this = this;
14725		instance = document.querySelectorAll(element)[index];
14726		this.hide(instance);
14727		this.add_class(instance, "sharer-" + index);
14728		instance = document.querySelectorAll(element)[index];
14729		this.inject_css(instance);
14730		this.inject_html(instance);
14731		this.show(instance);
14732		label = instance.getElementsByTagName("label")[0];
14733		button = instance.getElementsByClassName("social")[0];
14734		networks = instance.getElementsByTagName('li');
14735		this.add_class(button, "networks-" + this.config.enabled_networks);
14736		label.addEventListener("click", function() {
14737			return _this.event_toggle(button);
14738		});
14739		_this = this;
14740		_results = [];
14741		for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
14742			network = networks[index];
14743			_results.push(network.addEventListener("click", function() {
14744				_this.event_network(instance, this);
14745				return _this.event_close(button);
14746			}));
14747		}
14748		return _results;
14749	};
14750
14751	Share.prototype.event_toggle = function(button) {
14752		if (this.has_class(button, "active")) {
14753			return this.event_close(button);
14754		} else {
14755			return this.event_open(button);
14756		}
14757	};
14758
14759	Share.prototype.event_open = function(button) {
14760		if (this.has_class(button, "load")) {
14761			this.remove_class(button, "load");
14762		}
14763		return this.add_class(button, "active");
14764	};
14765
14766	Share.prototype.event_close = function(button) {
14767		return this.remove_class(button, "active");
14768	};
14769
14770	Share.prototype.event_network = function(instance, network) {
14771		var name;
14772		name = network.getAttribute("data-network");
14773		this.hook("before", name, instance);
14774		this["network_" + name]();
14775		return this.hook("after", name, instance);
14776	};
14777
14778	Share.prototype.open = function() {
14779		return this["public"]("open");
14780	};
14781
14782	Share.prototype.close = function() {
14783		return this["public"]("close");
14784	};
14785
14786	Share.prototype.toggle = function() {
14787		return this["public"]("toggle");
14788	};
14789
14790	Share.prototype["public"] = function(action) {
14791		var button, index, instance, _i, _len, _ref, _results;
14792		_ref = document.querySelectorAll(this.element);
14793		_results = [];
14794		for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
14795			instance = _ref[index];
14796			button = instance.getElementsByClassName("social")[0];
14797			_results.push(this["event_" + action](button));
14798		}
14799		return _results;
14800	};
14801
14802	Share.prototype.network_facebook = function() {
14803		if (this.config.networks.facebook.load_sdk) {
14804			if (!window.FB) {
14805				return console.error("The Facebook JS SDK hasn't loaded yet.");
14806			}
14807			return FB.ui({
14808				method: 'feed',
14809				name: this.config.networks.facebook.title,
14810				link: this.config.networks.facebook.url,
14811				picture: this.config.networks.facebook.image,
14812				caption: this.config.networks.facebook.caption,
14813				description: this.config.networks.facebook.description
14814			});
14815		} else {
14816			return this.popup('https://www.facebook.com/sharer/sharer.php', {
14817				u: this.config.networks.facebook.url
14818			});
14819		}
14820	};
14821
14822	Share.prototype.network_twitter = function() {
14823		return this.popup('https://twitter.com/intent/tweet', {
14824			text: this.config.networks.twitter.title,
14825			url: this.config.networks.twitter.url
14826		});
14827	};
14828
14829	Share.prototype.network_google_plus = function() {
14830		return this.popup('https://plus.google.com/share', {
14831			url: this.config.networks.google_plus.url
14832		});
14833	};
14834
14835	Share.prototype.network_pinterest = function() {
14836		return this.popup('https://www.pinterest.com/pin/create/button', {
14837			url: this.config.networks.pinterest.url,
14838			media: this.config.networks.pinterest.image,
14839			description: this.config.networks.pinterest.description
14840		});
14841	};
14842
14843	Share.prototype.network_linkedin = function() {
14844		return this.popup('https://www.linkedin.com/shareArticle', {
14845			url: this.config.networks.linkedin.url,
14846			title: this.config.networks.linkedin.title,
14847			summary: this.config.networks.linkedin.description
14848		});
14849	}
14850
14851	Share.prototype.network_xing = function() {
14852		return this.popup('https://www.xing.com/spi/shares/new', {
14853			url: this.config.networks.xing.url,
14854			image: this.config.networks.xing.image,
14855			title: this.config.networks.xing.title,
14856			summary: this.config.networks.xing.description
14857		});
14858	}
14859
14860	Share.prototype.network_email = function() {
14861		return this.popup('mailto:', {
14862			subject: this.config.networks.email.title,
14863			body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
14864		});
14865	};
14866
14867	Share.prototype.inject_icons = function() {
14868	//  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
14869	};
14870
14871	Share.prototype.inject_fonts = function() {
14872	 // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
14873	};
14874
14875	Share.prototype.inject_stylesheet = function(url) {
14876		var link;
14877		if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
14878			link = document.createElement("link");
14879			link.setAttribute("rel", "stylesheet");
14880			link.setAttribute("href", url);
14881			return this.el.head.appendChild(link);
14882		}
14883	};
14884
14885	Share.prototype.inject_css = function(instance) {
14886		var css, meta, selector, style;
14887		selector = "." + (instance.getAttribute('class').split(" ").join("."));
14888		if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
14889			this.config.selector = selector;
14890			css = getStyles(this.config);
14891			style = document.createElement("style");
14892			style.type = "text/css";
14893			if (style.styleSheet) {
14894				style.styleSheet.cssText = css;
14895			} else {
14896				style.appendChild(document.createTextNode(css));
14897			}
14898			this.el.head.appendChild(style);
14899			delete this.config.selector;
14900			meta = document.createElement("meta");
14901			meta.setAttribute("name", "sharer" + selector);
14902			return this.el.head.appendChild(meta);
14903		}
14904	};
14905
14906	Share.prototype.inject_html = function(instance) {
14907		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>";
14908	};
14909
14910	Share.prototype.inject_facebook_sdk = function() {
14911		var fb_root, script;
14912		if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
14913			script = document.createElement("script");
14914			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')";
14915			fb_root = document.createElement("div");
14916			fb_root.id = "fb-root";
14917			this.el.body.appendChild(fb_root);
14918			return this.el.body.appendChild(script);
14919		}
14920	};
14921
14922	Share.prototype.hook = function(type, network, instance) {
14923		var fn, opts;
14924		fn = this.config.networks[network][type];
14925		if (typeof fn === "function") {
14926			opts = fn.call(this.config.networks[network], instance);
14927			if (opts !== void 0) {
14928				opts = this.normalize_filter_config_updates(opts);
14929				this.extend(this.config.networks[network], opts, true);
14930				this.normalize_network_configuration();
14931			}
14932		}
14933	};
14934
14935	Share.prototype.default_title = function() {
14936		var content;
14937		if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
14938			return encodeURIComponent(content.getAttribute('content'));
14939		} else if (content = document.querySelector('title')) {
14940			return encodeURIComponent(content.innerText);
14941		}
14942	};
14943
14944	Share.prototype.default_image = function() {
14945		var content;
14946		if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
14947			return content.getAttribute('content');
14948		}
14949	};
14950
14951	Share.prototype.default_description = function() {
14952		var content;
14953		if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
14954			return encodeURIComponent(content.getAttribute('content'));
14955		} else {
14956			return '';
14957		}
14958	};
14959
14960	Share.prototype.set_global_configuration = function() {
14961		var display, network, option, options, _ref, _results;
14962		_ref = this.config.networks;
14963		_results = [];
14964		for (network in _ref) {
14965			options = _ref[network];
14966			for (option in options) {
14967				if (this.config.networks[network][option] == null) {
14968					this.config.networks[network][option] = this.config[option];
14969				}
14970			}
14971			if (this.config.networks[network].enabled) {
14972				display = 'block';
14973				this.config.enabled_networks += 1;
14974			} else {
14975				display = 'none';
14976			}
14977			_results.push(this.config.networks[network].display = display);
14978		}
14979		return _results;
14980	};
14981
14982	Share.prototype.normalize_network_configuration = function() {
14983		if (!this.config.networks.facebook.app_id) {
14984			this.config.networks.facebook.load_sdk = false;
14985		}
14986		if (!this.is_encoded(this.config.networks.twitter.description)) {
14987			this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
14988		}
14989		if (typeof this.config.networks.facebook.app_id === 'number') {
14990			return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
14991		}
14992	};
14993
14994	Share.prototype.normalize_filter_config_updates = function(opts) {
14995		if (this.config.networks.facebook.app_id !== opts.app_id) {
14996			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.");
14997			delete opts.app_id;
14998		}
14999		if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
15000			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.");
15001			delete opts.app_id;
15002		}
15003		return opts;
15004	};
15005
15006	return Share;
15007
15008})(ShareUtils);
15009 return Share;
15010});
15011
15012
15013// Generated by CoffeeScript 1.9.2
15014
15015// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
15016
15017(function() {
15018	var $, win;
15019
15020	$ = this.jQuery || window.jQuery;
15021
15022	win = $(window);
15023
15024	$.fn.stick_in_parent = function(opts) {
15025		var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
15026		if (opts == null) {
15027			opts = {};
15028		}
15029		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;
15030		if (offset_top == null) {
15031			offset_top = 0;
15032		}
15033		if (parent_selector == null) {
15034			parent_selector = void 0;
15035		}
15036		if (inner_scrolling == null) {
15037			inner_scrolling = true;
15038		}
15039		if (sticky_class == null) {
15040			sticky_class = "is_stuck";
15041		}
15042		doc = $(document);
15043		if (enable_bottoming == null) {
15044			enable_bottoming = true;
15045		}
15046		outer_width = function(el) {
15047			var _el, computed, w;
15048			if (window.getComputedStyle) {
15049				_el = el[0];
15050				computed = window.getComputedStyle(el[0]);
15051				w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
15052				if (computed.getPropertyValue("box-sizing") !== "border-box") {
15053					w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
15054				}
15055				return w;
15056			} else {
15057				return el.outerWidth(true);
15058			}
15059		};
15060		fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
15061			var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
15062			if (elm.data("sticky_kit")) {
15063				return;
15064			}
15065			elm.data("sticky_kit", true);
15066			last_scroll_height = doc.height();
15067			parent = elm.parent();
15068			if (parent_selector != null) {
15069				parent = parent.closest(parent_selector);
15070			}
15071			if (!parent.length) {
15072				throw "failed to find stick parent";
15073			}
15074			fixed = false;
15075			bottomed = false;
15076			spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
15077			if (spacer) {
15078				spacer.css('position', elm.css('position'));
15079			}
15080			recalc = function() {
15081				var border_top, padding_top, restore;
15082				if (detached) {
15083					return;
15084				}
15085				last_scroll_height = doc.height();
15086				border_top = parseInt(parent.css("border-top-width"), 10);
15087				padding_top = parseInt(parent.css("padding-top"), 10);
15088				padding_bottom = parseInt(parent.css("padding-bottom"), 10);
15089				parent_top = parent.offset().top + border_top + padding_top;
15090				parent_height = parent.height();
15091				if (fixed) {
15092					fixed = false;
15093					bottomed = false;
15094					if (manual_spacer == null) {
15095						elm.insertAfter(spacer);
15096						spacer.detach();
15097					}
15098					elm.css({
15099						position: "",
15100						top: "",
15101						width: "",
15102						bottom: ""
15103					}).removeClass(sticky_class);
15104					restore = true;
15105				}
15106				top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
15107				height = elm.outerHeight(true);
15108				el_float = elm.css("float");
15109				if (spacer) {
15110					spacer.css({
15111						width: outer_width(elm),
15112						height: height,
15113						display: elm.css("display"),
15114						"vertical-align": elm.css("vertical-align"),
15115						"float": el_float
15116					});
15117				}
15118				if (restore) {
15119					return tick();
15120				}
15121			};
15122			recalc();
15123			if (height === parent_height) {
15124				return;
15125			}
15126			last_pos = void 0;
15127			offset = offset_top;
15128			recalc_counter = recalc_every;
15129			tick = function() {
15130				var css, delta, recalced, scroll, will_bottom, win_height;
15131				if (detached) {
15132					return;
15133				}
15134				recalced = false;
vendor: 4,152 bytes, lines 15135-15288
15135				if (recalc_counter != null) {
15136					recalc_counter -= 1;
15137					if (recalc_counter <= 0) {
15138						recalc_counter = recalc_every;
15139						recalc();
15140						recalced = true;
15141					}
15142				}
15143				if (!recalced && doc.height() !== last_scroll_height) {
15144					recalc();
15145					recalced = true;
15146				}
15147				scroll = win.scrollTop();
15148				if (last_pos != null) {
15149					delta = scroll - last_pos;
15150				}
15151				last_pos = scroll;
15152				if (fixed) {
15153					if (enable_bottoming) {
15154						will_bottom = scroll + height + offset > parent_height + parent_top;
15155						if (bottomed && !will_bottom) {
15156							bottomed = false;
15157							elm.css({
15158								position: "fixed",
15159								bottom: "",
15160								top: offset
15161							}).trigger("sticky_kit:unbottom");
15162						}
15163					}
15164					if (scroll < top) {
15165						fixed = false;
15166						offset = offset_top;
15167						if (manual_spacer == null) {
15168							if (el_float === "left" || el_float === "right") {
15169								elm.insertAfter(spacer);
15170							}
15171							spacer.detach();
15172						}
15173						css = {
15174							position: "",
15175							width: "",
15176							top: ""
15177						};
15178						elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
15179					}
15180					if (inner_scrolling) {
15181						win_height = win.height();
15182						if (height + offset_top > win_height) {
15183							if (!bottomed) {
15184								offset -= delta;
15185								offset = Math.max(win_height - height, offset);
15186								offset = Math.min(offset_top, offset);
15187								if (fixed) {
15188									elm.css({
15189										top: offset + "px"
15190									});
15191								}
15192							}
15193						}
15194					}
15195				} else {
15196					if (scroll > top) {
15197						fixed = true;
15198						css = {
15199							position: "fixed",
15200							top: offset
15201						};
15202						css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
15203						elm.css(css).addClass(sticky_class);
15204						if (manual_spacer == null) {
15205							elm.after(spacer);
15206							if (el_float === "left" || el_float === "right") {
15207								spacer.append(elm);
15208							}
15209						}
15210						elm.trigger("sticky_kit:stick");
15211					}
15212				}
15213				if (fixed && enable_bottoming) {
15214					if (will_bottom == null) {
15215						will_bottom = scroll + height + offset > parent_height + parent_top;
15216					}
15217					if (!bottomed && will_bottom) {
15218						bottomed = true;
15219						if (parent.css("position") === "static") {
15220							parent.css({
15221								position: "relative"
15222							});
15223						}
15224						return elm.css({
15225							position: "absolute",
15226							bottom: padding_bottom,
15227							top: "auto"
15228						}).trigger("sticky_kit:bottom");
15229					}
15230				}
15231			};
15232			recalc_and_tick = function() {
15233				recalc();
15234				return tick();
15235			};
15236			detach = function() {
15237				detached = true;
15238				win.off("touchmove", tick);
15239				win.off("scroll", tick);
15240				win.off("resize", recalc_and_tick);
15241				$(document.body).off("sticky_kit:recalc", recalc_and_tick);
15242				elm.off("sticky_kit:detach", detach);
15243				elm.removeData("sticky_kit");
15244				elm.css({
15245					position: "",
15246					bottom: "",
15247					top: "",
15248					width: ""
15249				});
15250				parent.position("position", "");
15251				if (fixed) {
15252					if (manual_spacer == null) {
15253						if (el_float === "left" || el_float === "right") {
15254							elm.insertAfter(spacer);
15255						}
15256						spacer.remove();
15257					}
15258					return elm.removeClass(sticky_class);
15259				}
15260			};
15261			win.on("touchmove", tick);
15262			win.on("scroll", tick);
15263			win.on("resize", recalc_and_tick);
15264			$(document.body).on("sticky_kit:recalc", recalc_and_tick);
15265			elm.on("sticky_kit:detach", detach);
15266			return setTimeout(tick, 0);
15267		};
15268		for (i = 0, len = this.length; i < len; i++) {
15269			elm = this[i];
15270			fn($(elm));
15271		}
15272		return this;
15273	};
15274
15275}).call(this);
15276
15277/* ==========================================================================
15278 * bootstrap-tab-history.js
15279 * Author: Michael Narayan <[email protected]>
15280 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
15281 * ==========================================================================
15282 * Licensed under the Apache License, Version 2.0 (the "License"); you may
15283 * not use this file except in compliance with the License. You may obtain a
15284 * copy of the License at
15285 *
15286 * http://www.apache.org/licenses/LICENSE-2.0
15287 *
15288 * Unless required by applicable law or agreed to in writing, softw
15288are
15289 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15290 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15291 * License for the specific language governing permissions and limitations
15292 * under the License.
15293 * ========================================================================== */
15294
15295/* ========================================================================== */
15296/* JSHint directives                                                          */
15297/*                                                                            */
15298/* global BootstrapTabHistory: true                                           */
15299/*                                                                            */
15300/* global document                                                            */
15301/* global jQuery                                                              */
15302/* global history                                                             */
15303/* global window                                                              */
15304/* ========================================================================== */
15305
15306/**
15307 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
15308 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
15309 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
15310 *
15311 * See the README for additional information.
15312 *
15313 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
15314 */
15315
15316BootstrapTabHistory = {
15317	options: {
15318		/**
15319		 * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
15320		 * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
15321		 *
15322		 * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
15323		 *
15324		 * @public
15325		 * @type {?number}
15326		 */
15327		defaultAnchorYOffset: 0,
15328		/**
15329		 * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
15330		 *
15331		 * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
15332		 *
15333		 * @public
15334		 * @type {string}
15335		 */
15336		defaultChanger: 'replace',
15337		/**
15338		 * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
15339		 * `null` is passed as the third parameter to these calls.
15340		 *
15341		 * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
15342		 *
15343		 * @public
15344		 * @type {boolean}
15345		 */
15346		defaultUpdateURL: false,
15347		/**
15348		 * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
15349		 * load.
15350		 *
15351		 * @public
15352		 * @type {boolean}
15353		 */
15354		showTabsBasedOnAnchor: true
15355	}
15356};
15357
15358(function () {
15359	'use strict';
15360
15361	jQuery(function () {
15362		if(history && history.pushState && history.replaceState) {
15363			var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
15364
15365			if(bootstrapTabHistory) {
15366				showTabsBasedOnState(bootstrapTabHistory);
15367			} else {
15368				showTabsBasedOnAnchor();
15369			}
15370
15371			backfillHistoryState();
15372
15373			jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
15374			jQuery(window).on('popstate', onPopState);
15375		} else {
15376			showTabsBasedOnAnchor();
15377		}
15378	});
15379
15380	/**
15381	 * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
15382	 *
15383	 * @type {boolean}
15384	 */
15385	var showingTabsBasedOnState = false;
15386
15387	/**
15388	 * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
15389	 * `history.back` handling when `data-tab-history-update-url` is true.
15390	 */
15391	function backfillHistoryState() {
15392		var newState = null;
15393
15394		jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
15395			var $activeTabElement = jQuery(this);
15396			var selector = getTabSelector($activeTabElement);
15397
15398			if(selector) {
15399				var tabGroup = getTabGroup($activeTabElement);
15400
15401				if(tabGroup) {
15402					newState = createNewHistoryState(newState || history.state, tabGroup, selector);
15403				}
15404			}
15405		});
15406
15407		if(newState) {
15408			history.replaceState(newState, '', null);
15409		}
15410	}
15411
15412	/**
15413	 * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
15414	 * said bootstrapTabHistory attribute.
15415	 *
15416	 * @param {?object} existingState
15417	 * @param {!string} tabGroup
15418	 * @param {!string} selector
15419	 * @returns {!object}
15420	 */
15421	function createNewHistoryState(existingState, tabGroup, selector) {
15422		// Clone history.state and ensure it has a bootstrapTabHistory entry.
15423		var newState = jQuery.extend(true, {}, existingState, {
15424			bootstrapTabHistory: {}
15425		});
15426
15427		newState.bootstrapTabHistory[tabGroup] = selector;
15428
15429		return newState;
15430	}
15431
15432	/**
15433	 * @param {jQuery} $tab
15434	 * @returns {?string}
15435	 */
15436	function getTabGroup($tab) {
15437		return parseTruthyAttributeValue($tab.data('tab-history'));
15438	}
15439
15440	/**
15441	 * @param {jQuery} $tab
15442	 * @returns {?string}
15443	 */
15444	function getTabSelector($tab) {
15445		return $tab.data('target') || $tab.attr('href');
15446	}
15447
15448	/**
15449	 * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
15450	 *
15451	 * @param {jQuery.Event} shownEvt
15452	 */
15453	function onShownTab(shownEvt) {
15454		if(!showingTabsBasedOnState) {
15455			var $activatedTab = jQuery(shownEvt.target);
15456			if ( $activatedTab.hasClass('panel-collapse') )
15457				$activatedTab = $activatedTab.closest('.panel').find('a');
15458			var selector = getTabSelector($activatedTab);
15459
15460			if(selector) {
15461				var tabGroup = getTabGroup($activatedTab);
15462
15463				if(tabGroup) {
15464					var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
15465					var newState = createNewHistoryState(history.state, tabGroup, selector);
15466					var updateURL = (function ($activatedTab) {
15467						if(selector[0] === '#') {
15468							var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
15469
15470							if(elementUpdateURLOption === undefined) {
15471								return BootstrapTabHistory.options.defaultUpdateURL;
15472							} else {
15473								return elementUpdateURLOption;
15474							}
15475						} else {
15476							return false;
15477						}
15478					})($activatedTab);
15479
15480					switch(historyChanger) {
15481						case 'push':
15482							history.pushState(newState, '', updateURL ? selector : null);
15483							break;
15484						case 'replace':
15485							history.replaceState(newState, '', updateURL ? selector : null);
15486							break;
15487						default:
15488							throw new Error('Unknown tab-history-changer: ' + historyChanger);
15489					}
15490				}
15491			}
15492		}
15493	}
15494
15495	/**
15496	 * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
15497	 */
15498	function onPopState() {
15499		var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
15500
15501		if(bootstrapTabHistory) {
15502			showTabsBasedOnState(bootstrapTabHistory);
15503		}
15504	}
15505
15506	/**
15507	 * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
15508	 *
15509	 * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
15510	 *
15511	 * @param {*} value
15512	 * @returns {*}
15513	 */
15514	function parseTruthyAttributeValue(value) {
15515		if(value) {
15516			return value;
15517		} else if(value === '') {
15518			return true;
15519		} else {
15520			return value;
15521		}
15522	}
15523
15524	/**
15525	 * Show tabs based upon the anchor component of `window.location`.
15526	 */
15527	function showTabsBasedOnAnchor() {
15528		if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
15529			var anchor = window.location && window.location.hash;
15530
15531			if(anchor) {
15532				var $tabElement = showTabForSelector(anchor);
15533
15534				if($tabElement && window.addEventListener && window.removeEventListener) {
15535					var anchorYOffset = (function ($tabElement) {
15536						var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
15537
15538						if(elementSetting === undefined) {
15539							return BootstrapTabHistory.options.defaultAnchorYOffset;
15540						} else {
15541							return elementSetting;
15542						}
15543					})($tabElement);
15544
15545					// HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
15546					//   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
15547					//   `history.state` object should have been used (unless the browser did not support the modern History API).
15548					if(anchorYOffset || anchorYOffset === 0) {
15549						var scrollListener = function resetAnchorScroll () {
15550							window.removeEventListener('scroll', scrollListener);
15551							window.scrollTo(0, anchorYOffset);
15552						};
15553
15554						window.addEventListener('scroll', scrollListener);
15555					}
15556				}
15557			}
15558		}
15559	}
15560
vendor: 4,905 bytes, lines 15561-15727
15561	/**
15562	 * Show a tab which corresponds to the provided selector.
15563	 *
15564	 * @param {string} selector - A CSS selector.
15565	 * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
15566	 */
15567	function showTabForSelector(selector) {
15568		var $tabElement = (function (selector) {
15569			var $ret = null;
15570
15571			jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
15572				var $potentialTab = jQuery(this);
15573
15574				if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
15575					$ret = $potentialTab;
15576					return false;
15577				} else {
15578				 return null;
15579				}
15580			});
15581
15582			return $ret;
15583		})(selector);
15584
15585		if($tabElement) {
15586			$tabElement.trigger('click');
15587			//$tabElement.tab('show');
15588		}
15589
15590		return $tabElement;
15591	}
15592
15593	/**
15594	 * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
15595	 *
15596	 * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
15597	 */
15598	function showTabsBasedOnState(bootstrapTabHistory) {
15599		showingTabsBasedOnState = true;
15600
15601		try {
15602			for(var k in bootstrapTabHistory) {
15603				if(bootstrapTabHistory.hasOwnProperty(k)) {
15604					showTabForSelector(bootstrapTabHistory[k]);
15605				}
15606			}
15607		} finally {
15608			showingTabsBasedOnState = false;
15609		}
15610	}
15611})();
15612
15613
15614/*!
15615 * Justified Gallery - v3.6.3
15616 * http://miromannino.github.io/Justified-Gallery/
15617 * Copyright (c) 2016 Miro Mannino
15618 * Licensed under the MIT license.
15619 */
15620(function($) {
15621
15622	function hasScrollBar() {
15623		return $("body").height() > $(window).height();
15624	}
15625	/**
15626	 * Justified Gallery controller constructor
15627	 *
15628	 * @param $gallery the gallery to build
15629	 * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults)
15630	 * @constructor
15631	 */
15632	var JustifiedGallery = function ($gallery, settings) {
15633
15634		this.settings = settings;
15635		this.checkSettings();
15636
15637		this.imgAnalyzerTimeout = null;
15638		this.entries = null;
15639		this.buildingRow = {
15640			entriesBuff : [],
15641			width : 0,
15642			height : 0,
15643			aspectRatio : 0
15644		};
15645		this.lastFetchedEntry = null;
15646		this.lastAnalyzedIndex = -1;
15647		this.yield = {
15648			every : 2, // do a flush every n flushes (must be greater than 1)
15649			flushed : 0 // flushed rows without a yield
15650		};
15651		this.border = settings.border >= 0 ? settings.border : settings.margins;
15652		this.maxRowHeight = this.retrieveMaxRowHeight();
15653		this.suffixRanges = this.retrieveSuffixRanges();
15654		this.offY = this.border;
15655		this.rows = 0;
15656		this.spinner = {
15657			phase : 0,
15658			timeSlot : 150,
15659			$el : $('<div class="spinner"><span></span><span></span><span></span></div>'),
15660			intervalId : null
15661		};
15662		this.checkWidthIntervalId = null;
15663		this.galleryWidth = $gallery.width();
15664		this.$gallery = $gallery;
15665
15666	};
15667
15668	/** @returns {String} the best suffix given the width and the height */
15669	JustifiedGallery.prototype.getSuffix = function (width, height) {
15670		var longestSide, i;
15671		longestSide = (width > height) ? width : height;
15672		for (i = 0; i < this.suffixRanges.length; i++) {
15673			if (longestSide <= this.suffixRanges[i]) {
15674				return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
15675			}
15676		}
15677		return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
15678	};
15679
15680	/**
15681	 * Remove the suffix from the string
15682	 *
15683	 * @returns {string} a new string without the suffix
15684	 */
15685	JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
15686		return str.substring(0, str.length - suffix.length);
15687	};
15688
15689	/**
15690	 * @returns {boolean} a boolean to say if the suffix is contained in the str or not
15691	 */
15692	JustifiedGallery.prototype.endsWith = function (str, suffix) {
15693		return str.indexOf(suffix, str.length - suffix.length) !== -1;
15694	};
15695
15696	/**
15697	 * Get the used suffix of a particular url
15698	 *
15699	 * @param str
15700	 * @returns {String} return the used suffix
15701	 */
15702	JustifiedGallery.prototype.getUsedSuffix = function (str) {
15703		for (var si in this.settings.sizeRangeSuffixes) {
15704			if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
15705				if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
15706				if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
15707			}
15708		}
15709		return '';
15710	};
15711
15712	/**
15713	 * Given an image src, with the width and the height, returns the new image src with the
15714	 * best suffix to show the best quality thumbnail.
15715	 *
15716	 * @returns {String} the suffix to use
15717	 */
15718	JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
15719		var newImageSrc;
15720
15721		if (this.settings.thumbnailPath) {
15722			newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
15723		} else {
15724			var matchRes = imageSrc.match(this.settings.extension);
15725			var ext = (matchRes !== null) ? matchRes[0] : '';
15726			newImageSrc = imageSrc.replace(this.settings.extension, '');
15727			newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
15728			newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
15729		}
15730
15731		return newImageSrc;
15732	};
15733
15734	/**
15735	 * Shows the images that is in the given entry
15736	 *
15737	 * @param $entry the entry
15738	 * @param callback the callback that is called when the show animation is finished
15739	 */
15740	JustifiedGallery.prototype.showImg = function ($entry, callback) {
15741		if (this.settings.cssAnimation) {
15742			$entry.addClass('entry-visible');
15743			if (callback) callback();
15744		} else {
15745			$entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
15746			$entry.find('> img, > a > img').stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
15747		}
15748	};
15749
15750	/**
15751	 * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
15752	 * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
15753	 *
15754	 * @param $image the image to analyze
15755	 * @returns {String} the extracted src
15756	 */
15757	JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
15758		var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src');
15759		$image.data('jg.originalSrc', imageSrc);
15760		return imageSrc;
15761	};
15762
15763	/** @returns {jQuery} the image in the given entry */
15764	JustifiedGallery.prototype.imgFromEntry = function ($entry) {
15765		var $img = $entry.find('> img');
15766		if ($img.length === 0) $img = $entry.find('> a > img');
15767		if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
15768		return $img.length === 0 ? null : $img;
15769	};
15770
15771	/** @returns {jQuery} the caption in the given entry */
15772	JustifiedGallery.prototype.captionFromEntry = function ($entry) {
15773		var $caption = $entry.find('> .caption');
15774		return $caption.length === 0 ? null : $caption;
15775	};
15776
15777	/**
15778	 * Display the entry
15779	 *
15780	 * @param {jQuery} $entry the entry to display
15781	 * @param {int} x the x position where the entry must be positioned
15782	 * @param y the y position where the entry must be positioned
15783	 * @param imgWidth the image width
15784	 * @param imgHeight the image height
15785	 * @param rowHeight the row height of the row that owns the entry
15786	 */
15787	JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
15788		$entry.width(imgWidth);
15789		$entry.height(Math.floor(rowHeight));//hacked by Uncode
15790		$entry.css('top', Math.floor(y));//hacked by Uncode
15791		$entry.css('left', x);
15792
15793		var $image = this.imgFromEntry($entry);
15794		if ($image !== null) {
15795			$image.css('width', imgWidth);
15796			$image.css('height', imgHeight);
15797			$image.css('margin-left', - imgWidth / 2);
15798			$image.css('margin-top', - imgHeight / 2);
15799
15800			// Image reloading for an high quality of thumbnails
15801			var imageSrc = $image.attr('src');
15802			var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
15803
15804			$image.one('error', function () {
15805				$image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it.
15806			});
15807
15808			var loadNewImage = function () {
15809				if (imageSrc !== newImageSrc) { //load the new image after the fadeIn
15810					$image.attr('src', newImageSrc);
15811				}
15812			};
15813
15814			if ($entry.data('jg.loaded') === 'skipped') {
15815				this.onImageEvent(imageSrc, $.proxy(function() {
15816					this.showImg($entry, loadNewImage);
15817					$entry.data('jg.loaded', true);
15818				}, this));
15819			} else {
15820				this.showImg($entry, loadNewImage);
15821			}
15822
15823		} else {
15824			this.showImg($entry);
15825		}
15826
15827		this.displayEntryCaption($entry);
15828	};
15829
15830	/**
15831	 * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
15832	 * or the 'title' attributes.
15833	 *
15834	 * @param {jQuery} $entry the entry to process
15835	 */
15836	JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
15837		var $image = this.imgFromEntry($entry);
15838		if ($image !== null && this.settings.captions) {
15839			var $imgCaption = this.captionFromEntry($entry);
15840
15841			// Create it if it doesn't exists
15842			if ($imgCaption === null) {
15843				var caption = $image.attr('alt');
15844				if (!this.isValidCaption(caption)) caption = $entry.attr('title');
15845				if (this.isValidCaption(caption)) { // Create only we found something
15846					$imgCaption = $('<div class="caption">' + caption + '</div>');
15847					$entry.append($imgCaption);
15848					$entry.data('jg.createdCaption', true);
15849				}
15850			}
15851
15852			// Create events (we check again the $imgCaption because it can be still inexistent)
15853			if ($imgCaption !== null) {
15854				if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
15855				this.addCaptionEventsHandlers($entry);
15856			}
15857		} else {
15858			this.removeCaptionEventsHandlers($entry);
15859		}
15860	};
15861
15862	/**
15863	 * Validates the caption
15864	 *
15865	 * @param caption The caption that should be validated
15866	 * @return {boolean} Validation result
15867	 */
15868	JustifiedGallery.prototype.isValidCaption = function (caption) {
15869		return (typeof caption !== 'undefined' && caption.length > 0);
15870	};
15871
15872	/**
15873	 * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
15874	 * It shows the caption using jQuery (or using CSS if it is configured so)
15875	 *
15876	 * @param {Event} eventObject the event object
15877	 */
15878	JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
15879		var $caption = this.captionFromEntry($(eventObject.currentTarget));
15880		if (this.settings.cssAnimation) {
15881			$caption.addClass('caption-visible').removeClass('caption-hidden');
15882		} else {
15883			$caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
15884					this.settings.captionSettings.visibleOpacity);
15885		}
15886	};
15887
15888	/**
15889	 * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
15890	 * It hides the caption using jQuery (or using CSS if it is configured so)
15891	 *
15892	 * @param {Event} eventObject the event object
15893	 */
15894	JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
15895		var $caption = this.captionFromEntry($(eventObject.currentTarget));
15896		if (this.settings.cssAnimation) {
15897			$caption.removeClass('caption-visible').removeClass('caption-hidden');
15898		} else {
15899			$caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
15900					this.settings.captionSettings.nonVisibleOpacity);
15901		}
15902	};
15903
15904	/**
15905	 * Add the handlers of the entry for the caption
15906	 *
15907	 * @param $entry the entry to modify
15908	 */
15909	JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
15910		var captionMouseEvents = $entry.data('jg.captionMouseEvents');
15911		if (typeof captionMouseEvents === 'undefined') {
15912			captionMouseEvents = {
15913				mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
15914				mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
15915			};
15916			$entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
15917			$entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
15918			$entry.data('jg.captionMouseEvents', captionMouseEvents);
15919		}
15920	};
15921
15922	/**
15923	 * Remove the handlers of the entry for the caption
15924	 *
15925	 * @param $entry the entry to modify
15926	 */
15927	JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
15928		var captionMouseEvents = $entry.data('jg.captionMouseEvents');
15929		if (typeof captionMouseEvents !== 'undefined') {
15930			$entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
15931			$entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
15932			$entry.removeData('jg.captionMouseEvents');
15933		}
15934	};
15935
15936	/**
15937	 * Justify the building row, preparing it to
15938	 *
15939	 * @param isLastRow
15940	 * @returns a boolean to know if the row has been justified or not
15941	 */
15942	JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) {
15943		var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
15944		var minHeight = 0;
15945		var availableWidth = this.galleryWidth - 2 * this.border - (
15946				(this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
15947		var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
15948		var defaultRowHeight = this.settings.rowHeight;
15949		var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
15950
15951		//Skip the last row if we can't justify it and the lastRow == 'hide'
15952		if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) {
15953			for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
15954				$entry = this.buildingRow.entriesBuff[i];
15955				if (this.settings.cssAnimation)
15956					$entry.removeClass('entry-visible');
15957				else {
15958					$entry.stop().fadeTo(0, 0.1);
15959					$entry.find('> img, > a > img').fadeTo(0, 0);
15960				}
15961			}
15962			return -1;
15963		}
15964
15965		// With lastRow = nojustify, justify if is justificable (the images will not become too big)
15966		if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
15967			justify = false;
15968
15969			if (this.rows > 0) {
15970				defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
15971				justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
15972			}
15973		}
15974
15975		for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
15976			$entry = this.buildingRow.entriesBuff[i];
15977			imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
15978
15979			if (justify) {
15980				newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
15981				newImgH = rowHeight;
15982			} else {
15983				newImgW = defaultRowHeight * imgAspectRatio;
15984				newImgH = defaultRowHeight;
15985			}
15986
15987			availableWidth -= Math.round(newImgW);
15988			$entry.data('jg.jwidth', Math.round(newImgW));
15989			$entry.data('jg.jheight', Math.ceil(newImgH));
15990			if (i === 0 || minHeight > newImgH) minHeight = newImgH;
15991		}
15992
15993		this.buildingRow.height = minHeight;
15994		return justify;
15995	};
15996
15997	/**
15998	 * Clear the building row data to be used for a new row
15999	 */
16000	JustifiedGallery.prototype.clearBuildingRow = function () {
16001		this.buildingRow.entriesBuff = [];
16002		this.buildingRow.aspectRatio = 0;
16003		this.buildingRow.width = 0;
16004	};
16005
16006	/**
16007	 * Flush a row: justify it, modify the gallery height accordingly to the row height
16008	 *
16009	 * @param isLastRow
16010	 */
16011	JustifiedGallery.prototype.flushRow = function (isLastRow) {
16012		var settings = this.settings;
16013		var $entry, buildingRowRes, offX = this.border, i;
16014
16015		buildingRowRes = this.prepareBuildingRow(isLastRow);
16016		if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) {
16017			this.clearBuildingRow();
16018			return;
16019		}
16020
16021		if (this.maxRowHeight) {
16022			if (this.maxRowHeight.isPercentage && this.maxRowHeight.value * settings.rowHeight < this.buildingRow.height) {
16023				this.buildingRow.height = this.maxRowHeight.value * settings.rowHeight;
16024			} else if (this.maxRowHeight.value >= settings.rowHeight && this.maxRowHeight.value < this.buildingRow.height) {
16025				this.buildingRow.height = this.maxRowHeight.value;
16026			}
16027		}
16028
16029		//Align last (unjustified) row
16030		if (settings.lastRow === 'center' || settings.lastRow === 'right') {
16031			var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
16032
16033			for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
16034				$entry = this.buildingRow.entriesBuff[i];
16035				availableWidth -= $entry.data('jg.jwidth');
16036			}
16037
16038			if (settings.lastRow === 'center')
16039				offX += availableWidth / 2;
16040			else if (settings.lastRow === 'right')
16041				offX += availableWidth;
16042		}
16043
16044		for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
16045			$entry = this.buildingRow.entriesBuff[i];
16046			this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
16047			offX += $entry.data('jg.jwidth') + settings.margins;
16048		}
16049
16050		//Gallery Height
16051		this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
16052		this.$gallery.height(this.galleryHeightToSet + this.getSpinnerHeight());
16053
16054		if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
16055			//Ready for a new row
16056			this.offY += this.buildingRow.height + settings.margins;
16057			this.rows += 1;
16058			this.clearBuildingRow();
16059			this.$gallery.trigger('jg.rowflush');
16060		}
16061	};
16062
16063	/**
16064	 * Checks the width of the gallery container, to know if a new justification is needed
16065	 */
16066	var scrollBarOn = false;
16067	JustifiedGallery.prototype.checkWidth = function () {
16068		this.checkWidthIntervalId = setInterval($.proxy(function () {
16069			var galleryWidth = parseFloat(this.$gallery.width());
16070			if (hasScrollBar() === scrollBarOn) {
16071				if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
16072					this.galleryWidth = galleryWidth;
16073					this.rewind();
16074
16075					// Restart to analyze
16076					this.startImgAnalyzer(true);
16077				}
16078			} else {
16079				scrollBarOn = hasScrollBar();
16080				this.galleryWidth = galleryWidth;
16081			}
16082		}, this), this.settings.refreshTime);
16083	};
16084
16085	/**
16086	 * @returns {boolean} a boolean saying if the spinner is active or not
16087	 */
16088	JustifiedGallery.prototype.isSpinnerActive = function () {
16089		return this.spinner.intervalId !== null;
16090	};
16091
16092	/**
16093	 * @returns {int} the spinner height
16094	 */
16095	JustifiedGallery.prototype.getSpinnerHeight = function () {
16096		return this.spinner.$el.innerHeight();
16097	};
16098
16099	/**
16100	 * Stops the spinner animation and modify the gallery height to exclude the spinner
16101	 */
16102	JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
16103		clearInterval(this.spinner.intervalId);
16104		this.spinner.intervalId = null;
16105		this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight());
16106		this.spinner.$el.detach();
16107	};
16108
16109	/**
16110	 * Starts the spinner animation
16111	 */
16112	JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
16113		var spinnerContext = this.spinner;
16114		var $spinnerPoints = spinnerContext.$el.find('span');
16115		clearInterval(spinnerContext.intervalId);
16116		this.$gallery.append(spinnerContext.$el);
16117		this.$gallery.height(this.offY + this.buildingRow.height + this.getSpinnerHeight());
16118		spinnerContext.intervalId = setInterval(function () {
16119			if (spinnerContext.phase < $spinnerPoints.length) {
16120				$spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
16121			} else {
16122				$spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
16123			}
16124			spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
16125		}, spinnerContext.timeSlot);
16126	};
16127
16128	/**
16129	 * Rewind the image analysis to start from the first entry.
16130	 */
16131	JustifiedGallery.prototype.rewind = function () {
16132		this.lastFetchedEntry = null;
16133		this.lastAnalyzedIndex = -1;
16134		this.offY = this.border;
16135		this.rows = 0;
16136		this.clearBuildingRow();
16137	};
16138
16139	/**
16140	 * Update the entries searching it from the justified gallery HTML element
16141	 *
16142	 * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
16143	 * @returns {boolean} true if some entries has been founded
16144	 */
16145	JustifiedGallery.prototype.updateEntries = function (norewind) {
16146		var newEntries;
16147
16148		if (norewind && this.lastFetchedEntry != null) {
16149			newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray();
16150		} else {
16151			this.entries = [];
16152			newEntries = this.$gallery.children(this.settings.selector).toArray();
16153		}
16154
16155		if (newEntries.length > 0) {
16156
16157			// Sort or randomize
16158			if ($.isFunction(this.settings.sort)) {
16159				newEntries = this.sortArray(newEntries);
16160			} else if (this.settings.randomize) {
16161				newEntries = this.shuffleArray(newEntries);
16162			}
16163			this.lastFetchedEntry = newEntries[newEntries.length - 1];
16164
16165			// Filter
16166			if (this.settings.filter) {
16167				newEntries = this.filterArray(newEntries);
16168			} else {
16169				this.resetFilters(newEntries);
16170			}
16171
16172		}
16173
16174		this.entries = this.entries.concat(newEntries);
16175		return true;
16176	};
16177
16178	/**
16179	 * Apply the entries order to the DOM, iterating the entries and appending the images
16180	 *
16181	 * @param entries the entries that has been modified and that must be re-ordered in the DOM
16182	 */
16183	JustifiedGallery.prototype.insertToGallery = function (entries) {
16184		var that = this;
16185		$.each(entries, function () {
16186			$(this).appendTo(that.$gallery);
16187		});
16188	};
16189
16190	/**
16191	 * Shuffle the array using the Fisher-Yates shuffle algorithm
16192	 *
16193	 * @param a the array to shuffle
16194	 * @return the shuffled array
16195	 */
16196	JustifiedGallery.prototype.shuffleArray = function (a) {
16197		var i, j, temp;
16198		for (i = a.length - 1; i > 0; i--) {
16199			j = Math.floor(Math.random() * (i + 1));
16200			temp = a[i];
16201			a[i] = a[j];
16202			a[j] = temp;
16203		}
16204		this.insertToGallery(a);
16205		return a;
16206	};
16207
16208	/**
16209	 * Sort the array using settings.comparator as comparator
16210	 *
16211	 * @param a the array to sort (it is sorted)
16212	 * @return the sorted array
16213	 */
16214	JustifiedGallery.prototype.sortArray = function (a) {
16215		a.sort(this.settings.sort);
16216		this.insertToGallery(a);
16217		return a;
16218	};
16219
16220	/**
16221	 * Reset the filters removing the 'jg-filtered' class from all the entries
16222	 *
16223	 * @param a the array to reset
16224	 */
16225	JustifiedGallery.prototype.resetFilters = function (a) {
16226		for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
16227	};
16228
16229	/**
16230	 * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
16231	 *
16232	 * @param a the array to filter
16233	 * @return the filtered array
16234	 */
16235	JustifiedGallery.prototype.filterArray = function (a) {
16236		var settings = this.settings;
16237		if ($.type(settings.filter) === 'string') {
16238			// Filter only keeping the entries passed in the string
16239			return a.filter(function (el) {
16240				var $el = $(el);
16241				if ($el.is(settings.filter)) {
16242					$el.removeClass('jg-filtered');
16243					return true;
16244				} else {
16245					$el.addClass('jg-filtered').removeClass('jg-visible');
16246					return false;
16247				}
16248			});
16249		} else if ($.isFunction(settings.filter)) {
16250			// Filter using the passed function
16251			var filteredArr = a.filter(settings.filter);
16252			for (var i = 0; i < a.length; i++) {
16253				if (filteredArr.indexOf(a[i]) == -1) {
16254					$(a[i]).addClass('jg-filtered').removeClass('jg-visible');
16255				} else {
16256					$(a[i]).removeClass('jg-filtered');
16257				}
16258			}
16259			return filteredArr;
16260		}
16261	};
16262
16263	/**
16264	 * Destroy the Justified Gallery instance.
16265	 *
16266	 * It clears all the css properties added in the style attributes. We doesn't backup the original
16267	 * values for those css attributes, because it costs (performance) and because in general one
16268	 * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
16269	 * classes). Creating a backup is also difficult because JG could be called multiple times and
16270	 * with different style attributes.
16271	 */
16272	JustifiedGallery.prototype.destroy = function () {
16273		clearInterval(this.checkWidthIntervalId);
16274
16275		$.each(this.entries, $.proxy(function(_, entry) {
16276			var $entry = $(entry);
16277
16278			// Reset entry style
16279			$entry.css('width', '');
16280			$entry.css('height', '');
16281			$entry.css('top', '');
16282			$entry.css('left', '');
16283			$entry.data('jg.loaded', undefined);
16284			$entry.removeClass('jg-entry');
16285
16286			// Reset image style
16287			var $img = this.imgFromEntry($entry);
16288			$img.css('width', '');
16289			$img.css('height', '');
16290			$img.css('margin-left', '');
16291			$img.css('margin-top', '');
16292			$img.attr('src', $img.data('jg.originalSrc'));
16293			$img.data('jg.originalSrc', undefined);
16294
16295			// Remove caption
16296			this.removeCaptionEventsHandlers($entry);
16297			var $caption = this.captionFromEntry($entry);
16298			if ($entry.data('jg.createdCaption')) {
16299				// remove also the caption element (if created by jg)
16300				$entry.data('jg.createdCaption', undefined);
16301				if ($caption !== null) $caption.remove();
16302			} else {
16303				if ($caption !== null) $caption.fadeTo(0, 1);
16304			}
16305
16306		}, this));
16307
16308		this.$gallery.css('height', '');
16309		this.$gallery.removeClass('justified-gallery');
16310		this.$gallery.data('jg.controller', undefined);
16311	};
16312
16313	/**
16314	 * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
16315	 *
16316	 * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
16317	 */
16318	JustifiedGallery.prototype.analyzeImages = function (isForResize) {
16319		for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
16320			var $entry = $(this.entries[i]);
16321			if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
16322				var availableWidth = this.galleryWidth - 2 * this.border - (
16323						(this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
16324				var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
16325				if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
16326					this.flushRow(false);
16327					if(++this.yield.flushed >= this.yield.every) {
16328						this.startImgAnalyzer(isForResize);
16329						return;
16330					}
16331				}
16332
16333				this.buildingRow.entriesBuff.push($entry);
16334				this.buildingRow.aspectRatio += imgAspectRatio;
16335				this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
16336				this.lastAnalyzedIndex = i;
16337
16338			} else if ($entry.data('jg.loaded') !== 'error') {
16339				return;
16340			}
16341		}
16342
16343		// Last row flush (the row is not full)
16344		if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true);
16345
16346		if (this.isSpinnerActive()) {
16347			this.stopLoadingSpinnerAnimation();
16348		}
16349
16350		/* Stop, if there is, the timeout to start the analyzeImages.
16351		 This is because an image can be set loaded, and the timeout can be set,
16352		 but this image can be analyzed yet.
16353		 */
16354		this.stopImgAnalyzerStarter();
16355
16356		//On complete callback
16357		this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete');
16358		this.$gallery.height(this.galleryHeightToSet);
16359	};
16360
16361	/**
16362	 * Stops any ImgAnalyzer starter (that has an assigned timeout)
16363	 */
16364	JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
16365		this.yield.flushed = 0;
16366		if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout);
16367	};
16368
16369	/**
16370	 * Starts the image analyzer. It is not immediately called to let the browser to update the view
16371	 *
16372	 * @param isForResize specifies if the image analyzer must be called for resizing or not
16373	 */
16374	JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
16375		var that = this;
16376		this.stopImgAnalyzerStarter();
16377		this.imgAnalyzerTimeout = setTimeout(function () {
16378			that.analyzeImages(isForResize);
16379		}, 0.001); // we can't start it immediately due to a IE different behaviour
16380	};
16381
16382	/**
16383	 * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
16384	 * because some browsers, with a 404 set complete = true.
16385	 *
16386	 * @param imageSrc the image src to load
16387	 * @param onLoad callback that is called when the image has been loaded
16388	 * @param onError callback that is called in case of an error
16389	 */
16390	JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
16391		if (!onLoad && !onError) return;
16392
16393		var memImage = new Image();
16394		var $memImage = $(memImage);
16395		if (onLoad) {
16396			$memImage.one('load', function () {
16397				$memImage.off('load error');
16398				onLoad(memImage);
16399			});
16400		}
16401		if (onError) {
16402			$memImage.one('error', function() {
16403				$memImage.off('load error');
16404				onError(memImage);
16405			});
16406		}
16407		memImage.src = imageSrc;
16408	};
16409
16410	/**
16411	 * Init of Justified Gallery controlled
16412	 * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
16413	 */
16414	JustifiedGallery.prototype.init = function () {
16415		var imagesToLoad = false, skippedImages = false, that = this;
16416		$.each(this.entries, function (index, entry) {
16417			var $entry = $(entry);
16418			var $image = that.imgFromEntry($entry);
16419
16420			$entry.addClass('jg-entry');
16421
16422			if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
16423
16424				// Link Rel global overwrite
16425				if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
16426
16427				// Link Target global overwrite
16428				if (that.settings.target !== null) $entry.attr('target', that.settings.target);
16429
16430				if ($image !== null) {
16431
16432					// Image src
16433					var imageSrc = that.extractImgSrcFromImage($image);
16434					$image.attr('src', imageSrc);
16435
16436					/* If we have the height and the width, we don't wait that the image is loaded, but we start directly
16437					 * with the justification */
16438					if (that.settings.waitThumbnailsLoad === false) {
16439						var width = parseFloat($image.attr('width'));
16440						var height = parseFloat($image.attr('height'));
16441						if (!isNaN(width) && !isNaN(height)) {
16442							$entry.data('jg.width', width);
16443							$entry.data('jg.height', height);
16444							$entry.data('jg.loaded', 'skipped');
16445							skippedImages = true;
16446							that.startImgAnalyzer(false);
16447							return true; // continue
16448						}
16449					}
16450
16451					$entry.data('jg.loaded', false);
16452					imagesToLoad = true;
16453
16454					// Spinner start
16455					if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
16456
16457					that.onImageEvent(imageSrc, function (loadImg) { // image loaded
16458						$entry.data('jg.width', loadImg.width);
vendor: 10,190 bytes, lines 16459-16738
16459						$entry.data('jg.height', loadImg.height);
16460						$entry.data('jg.loaded', true);
16461						that.startImgAnalyzer(false);
16462					}, function () { // image load error
16463						$entry.data('jg.loaded', 'error');
16464						that.startImgAnalyzer(false);
16465					});
16466
16467				} else {
16468					$entry.data('jg.loaded', true);
16469					$entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
16470					$entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
16471				}
16472
16473			}
16474
16475		});
16476
16477		if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
16478		this.checkWidth();
16479	};
16480
16481	/**
16482	 * Checks that it is a valid number. If a string is passed it is converted to a number
16483	 *
16484	 * @param settingContainer the object that contains the setting (to allow the conversion)
16485	 * @param settingName the setting name
16486	 */
16487	JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
16488		if ($.type(settingContainer[settingName]) === 'string') {
16489			settingContainer[settingName] = parseFloat(settingContainer[settingName]);
16490		}
16491
16492		if ($.type(settingContainer[settingName]) === 'number') {
16493			if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
16494		} else {
16495			throw settingName + ' must be a number';
16496		}
16497	};
16498
16499	/**
16500	 * Checks the sizeRangeSuffixes and, if necessary, converts
16501	 * its keys from string (e.g. old settings with 'lt100') to int.
16502	 */
16503	JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
16504		if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
16505			throw 'sizeRangeSuffixes must be defined and must be an object';
16506		}
16507
16508		var suffixRanges = [];
16509		for (var rangeIdx in this.settings.sizeRangeSuffixes) {
16510			if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
16511		}
16512
16513		var newSizeRngSuffixes = {0: ''};
16514		for (var i = 0; i < suffixRanges.length; i++) {
16515			if ($.type(suffixRanges[i]) === 'string') {
16516				try {
16517					var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
16518					newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
16519				} catch (e) {
16520					throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
16521				}
16522			} else {
16523				newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
16524			}
16525		}
16526
16527		this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
16528	};
16529
16530	/**
16531	 * check and convert the maxRowHeight setting
16532	 */
16533	JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
16534		var newMaxRowHeight = { };
16535
16536		if ($.type(this.settings.maxRowHeight) === 'string') {
16537			if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
16538				newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
16539				newMaxRowHeight.isPercentage = false;
16540			} else {
16541				newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight);
16542				newMaxRowHeight.isPercentage = true;
16543			}
16544		} else if ($.type(this.settings.maxRowHeight) === 'number') {
16545			newMaxRowHeight.value = this.settings.maxRowHeight;
16546			newMaxRowHeight.isPercentage = false;
16547		} else if (this.settings.maxRowHeight === false ||
16548				this.settings.maxRowHeight === null ||
16549				typeof this.settings.maxRowHeight == 'undefined') {
16550			return null;
16551		} else {
16552			throw 'maxRowHeight must be a number or a percentage';
16553		}
16554
16555		// check if the converted value is not a number
16556		if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight';
16557
16558		// check values
16559		if (newMaxRowHeight.isPercentage) {
16560			if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100;
16561		}
16562
16563		return newMaxRowHeight;
16564	};
16565
16566	/**
16567	 * Checks the settings
16568	 */
16569	JustifiedGallery.prototype.checkSettings = function () {
16570		this.checkSizeRangesSuffixes();
16571
16572		this.checkOrConvertNumber(this.settings, 'rowHeight');
16573		this.checkOrConvertNumber(this.settings, 'margins');
16574		this.checkOrConvertNumber(this.settings, 'border');
16575
16576		var lastRowModes = [
16577			'justify',
16578			'nojustify',
16579			'left',
16580			'center',
16581			'right',
16582			'hide'
16583		];
16584		if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
16585			throw 'lastRow must be one of: ' + lastRowModes.join(', ');
16586		}
16587
16588		this.checkOrConvertNumber(this.settings, 'justifyThreshold');
16589		if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
16590			throw 'justifyThreshold must be in the interval [0,1]';
16591		}
16592		if ($.type(this.settings.cssAnimation) !== 'boolean') {
16593			throw 'cssAnimation must be a boolean';
16594		}
16595
16596		if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
16597		this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
16598
16599		this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
16600		if (this.settings.captionSettings.visibleOpacity < 0 ||
16601				this.settings.captionSettings.visibleOpacity > 1) {
16602			throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
16603		}
16604
16605		this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
16606		if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
16607				this.settings.captionSettings.nonVisibleOpacity > 1) {
16608			throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
16609		}
16610
16611		this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
16612		this.checkOrConvertNumber(this.settings, 'refreshTime');
16613		this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
16614		if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
16615		if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
16616
16617		if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
16618			throw 'sort must be false or a comparison function';
16619		}
16620
16621		if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
16622				$.type(this.settings.filter) !== 'string') {
16623			throw 'filter must be false, a string or a filter function';
16624		}
16625	};
16626
16627	/**
16628	 * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
16629	 * @returns {Array} sorted suffix ranges
16630	 */
16631	JustifiedGallery.prototype.retrieveSuffixRanges = function () {
16632		var suffixRanges = [];
16633		for (var rangeIdx in this.settings.sizeRangeSuffixes) {
16634			if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
16635		}
16636		suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
16637		return suffixRanges;
16638	};
16639
16640	/**
16641	 * Update the existing settings only changing some of them
16642	 *
16643	 * @param newSettings the new settings (or a subgroup of them)
16644	 */
16645	JustifiedGallery.prototype.updateSettings = function (newSettings) {
16646		// In this case Justified Gallery has been called again changing only some options
16647		this.settings = $.extend({}, this.settings, newSettings);
16648		this.checkSettings();
16649
16650		// As reported in the settings: negative value = same as margins, 0 = disabled
16651		this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
16652
16653		this.maxRowHeight = this.retrieveMaxRowHeight();
16654		this.suffixRanges = this.retrieveSuffixRanges();
16655	};
16656
16657	/**
16658	 * Justified Gallery plugin for jQuery
16659	 *
16660	 * Events
16661	 *  - jg.complete : called when all the gallery has been created
16662	 *  - jg.resize : called when the gallery has been resized
16663	 *  - jg.rowflush : when a new row appears
16664	 *
16665	 * @param arg the action (or the settings) passed when the plugin is called
16666	 * @returns {*} the object itself
16667	 */
16668	$.fn.justifiedGallery = function (arg) {
16669		return this.each(function (index, gallery) {
16670
16671			var $gallery = $(gallery);
16672			$gallery.addClass('justified-gallery');
16673
16674			var controller = $gallery.data('jg.controller');
16675			if (typeof controller === 'undefined') {
16676				// Create controller and assign it to the object data
16677				if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
16678					if (arg === 'destroy') return; // Just a call to an unexisting object
16679					throw 'The argument must be an object';
16680				}
16681				controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg));
16682				$gallery.data('jg.controller', controller);
16683			} else if (arg === 'norewind') {
16684				// In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
16685				// ... left to be more readable
16686			} else if (arg === 'destroy') {
16687				controller.destroy();
16688				return;
16689			} else {
16690				// In this case Justified Gallery has been called again changing only some options
16691				controller.updateSettings(arg);
16692				controller.rewind();
16693			}
16694
16695			// Update the entries list
16696			if (!controller.updateEntries(arg === 'norewind')) return;
16697
16698			// Init justified gallery
16699			controller.init();
16700
16701		});
16702	};
16703
16704	// Default options
16705	$.fn.justifiedGallery.defaults = {
16706		sizeRangeSuffixes: { }, /* e.g. Flickr configuration
16707				{
16708					100: '_t',  // used when longest is less than 100px
16709					240: '_m',  // used when longest is between 101px and 240px
16710					320: '_n',  // ...
16711					500: '',
16712					640: '_z',
16713					1024: '_b'  // used as else case because it is the last
16714				}
16715		*/
16716		thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
16717		path relative to a specific thumbnail size. The function should accept respectively three arguments:
16718		current path, width and height */
16719		rowHeight: 120,
16720		maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
16721												 // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
16722												 // can't exceed 3 * rowHeight)
16723		margins: 1,
16724		border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
16725
16726		lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
16727
16728		justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
16729														 * (i.e. lastRow setting is not considered) */
16730		waitThumbnailsLoad: true,
16731		captions: true,
16732		cssAnimation: true,
16733		imagesAnimationDuration: 500, // ignored with css animations
16734		captionSettings: { // ignored with css animations
16735			animationDuration: 500,
16736			visibleOpacity: 0.7,
16737			nonVisibleOpacity: 0.0
16738		},
16739		rel: null, // rewrite the rel of each analyzed links
16740		target: null, // rewrite the target of all links
16741		extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
16742		refreshTime: 200, // time interval (in ms) to check if the page changes its width
16743		refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
16744		randomize: false,
16745		sort: false, /*
16746			- false: to do not sort
16747			- function: to sort them using the function as comparator (see Array.prototype.sort())
16748		*/
16749		filter: false, /*
16750			- false, null or undefined: for a disabled filter
16751			- a string: an entry is kept if entry.is(filter string) returns true
16752									see jQuery's .is() function for further information
16753			- a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
16754										It follows the specifications of the Array.prototype.filter() function of JavaScript.
16755		*/
16756		selector: 'a, div:not(.spinner)' // The selector that is used to know what are the entries of the gallery
16757	};
16758
16759}(jQuery));
16760
16761/*!
16762* Customized version of iScroll.js 0.0.1
16763* It fixes bugs affecting its integration with fullpage.js
16764*/
16765/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
16766(function (window, document, Math) {
16767var rAF = window.requestAnimationFrame  ||
16768		window.webkitRequestAnimationFrame  ||
16769		window.mozRequestAnimationFrame     ||
16770		window.oRequestAnimationFrame       ||
16771		window.msRequestAnimationFrame      ||
16772		function (callback) { window.setTimeout(callback, 1000 / 60); };
16773
16774var utils = (function () {
16775		var me = {};
16776
16777		var _elementStyle = document.createElement('div').style;
16778		var _vendor = (function () {
16779				var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
16780						transform,
16781						i = 0,
16782						l = vendors.length;
16783
16784				for ( ; i < l; i++ ) {
16785						transform = vendors[i] + 'ransform';
16786						if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
16787				}
16788
16789				return false;
16790		})();
16791
16792		function _prefixStyle (style) {
16793				if ( _vendor === false ) return false;
16794				if ( _vendor === '' ) return style;
16795				return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
16796		}
16797
16798		me.getTime = Date.now || function getTime () { return new Date().getTime(); };
16799
16800		me.extend = function (target, obj) {
16801				for ( var i in obj ) {
16802						target[i] = obj[i];
16803				}
16804		};
16805
16806		me.addEvent = function (el, type, fn, capture) {
16807				el.addEventListener(type, fn, !!capture);
16808		};
16809
16810		me.removeEvent = function (el, type, fn, capture) {
16811				el.removeEventListener(type, fn, !!capture);
16812		};
16813
16814		me.prefixPointerEvent = function (pointerEvent) {
16815				return window.MSPointerEvent ?
16816						'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
16817						pointerEvent;
16818		};
16819
16820		me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
16821				var distance = current - start,
16822						speed = Math.abs(distance) / time,
16823						destination,
16824						duration;
16825
16826				deceleration = deceleration === undefined ? 0.0006 : deceleration;
16827
16828				destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
16829				duration = speed / deceleration;
16830
16831				if ( destination < lowerMargin ) {
16832						destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
16833						distance = Math.abs(destination - current);
16834						duration = distance / speed;
16835				} else if ( destination > 0 ) {
16836						destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
16837						distance = Math.abs(current) + destination;
16838						duration = distance / speed;
16839				}
16840
16841				return {
16842						destination: Math.round(destination),
16843						duration: duration
16844				};
16845		};
16846
16847		var _transform = _prefixStyle('transform');
16848
16849		me.extend(me, {
16850				hasTransform: _transform !== false,
16851				hasPerspective: _prefixStyle('perspective') in _elementStyle,
16852				hasTouch: 'ontouchstart' in window,
16853				hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
16854				hasTransition: _prefixStyle('transition') in _elementStyle
16855		});
16856
16857		/*
16858		This should find all Android browsers lower than build 535.19 (both stock browser and webview)
16859		- galaxy S2 is ok
16860		- 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
16861		- 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16862	 - galaxy S3 is badAndroid (stock brower, webview)
16863		 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16864	 - galaxy S4 is badAndroid (stock brower, webview)
16865		 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
16866	 - galaxy S5 is OK
16867		 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
16868	 - galaxy S6 is OK
16869		 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
16870	*/
16871		me.isBadAndroid = (function() {
16872				var appVersion = window.navigator.appVersion;
16873				// Android browser is not a chrome browser.
16874				if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
16875						var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
16876						if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
16877								return parseFloat(safariVersion[1]) < 535.19;
16878						} else {
16879								return true;
16880						}
16881				} else {
16882						return false;
16883				}
16884		})();
16885
16886		me.extend(me.style = {}, {
16887				transform: _transform,
16888				transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
16889				transitionDuration: _prefixStyle('transitionDuration'),
16890				transitionDelay: _prefixStyle('transitionDelay'),
16891				transformOrigin: _prefixStyle('transformOrigin')
16892		});
16893
16894		me.hasClass = function (e, c) {
16895				var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
16896				return re.test(e.className);
16897		};
16898
16899		me.addClass = function (e, c) {
16900				if ( me.hasClass(e, c) ) {
16901						return;
16902				}
16903
16904				var newclass = e.className.split(' ');
16905				newclass.push(c);
16906				e.className = newclass.join(' ');
16907		};
16908
16909		me.removeClass = function (e, c) {
16910				if ( !me.hasClass(e, c) ) {
16911						return;
16912				}
16913
16914				var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
16915				e.className = e.className.replace(re, ' ');
16916		};
16917
16918		me.offset = function (el) {
16919				var left = -el.offsetLeft,
16920						top = -el.offsetTop;
16921
16922				// jshint -W084
16923				while (el = el.offsetParent) {
16924						left -= el.offsetLeft;
16925						top -= el.offsetTop;
16926				}
16927				// jshint +W084
16928
16929				return {
16930						left: left,
16931						top: top
16932				};
16933		};
16934
16935		me.preventDefaultException = function (el, exceptions) {
16936				for ( var i in exceptions ) {
16937						if ( exceptions[i].test(el[i]) ) {
16938								return true;
16939						}
16940				}
16941
16942				return false;
16943		};
16944
16945		me.extend(me.eventType = {}, {
16946				touchstart: 1,
16947				touchmove: 1,
16948				touchend: 1,
16949
16950				mousedown: 2,
16951				mousemove: 2,
16952				mouseup: 2,
16953
16954				pointerdown: 3,
16955				pointermove: 3,
16956				pointerup: 3,
16957
16958				MSPointerDown: 3,
16959				MSPointerMove: 3,
16960				MSPointerUp: 3
16961		});
16962
16963		me.extend(me.ease = {}, {
16964				quadratic: {
16965						style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
16966						fn: function (k) {
16967								return k * ( 2 - k );
16968						}
16969				},
16970				circular: {
16971						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)
16972						fn: function (k) {
16973								return Math.sqrt( 1 - ( --k * k ) );
16974						}
16975				},
16976				back: {
16977						style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
16978						fn: function (k) {
16979								var b = 4;
16980								return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
16981						}
16982				},
16983				bounce: {
16984						style: '',
16985						fn: function (k) {
16986								if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
16987										return 7.5625 * k * k;
16988								} else if ( k < ( 2 / 2.75 ) ) {
16989										return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
16990								} else if ( k < ( 2.5 / 2.75 ) ) {
16991										return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
16992								} else {
16993										return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
16994								}
16995						}
16996				},
16997				elastic: {
16998						style: '',
16999						fn: function (k) {
17000								var f = 0.22,
17001										e = 0.4;
17002
17003								if ( k === 0 ) { return 0; }
17004								if ( k == 1 ) { return 1; }
17005
17006								return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
17007						}
17008				}
17009		});
17010
17011		me.tap = function (e, eventName) {
17012				var ev = document.createEvent('Event');
17013				ev.initEvent(eventName, true, true);
17014				ev.pageX = e.pageX;
17015				ev.pageY = e.pageY;
17016				e.target.dispatchEvent(ev);
17017		};
17018
17019		me.click = function (e) {
17020				var target = e.target,
17021						ev;
17022
17023				if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
17024						// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
17025						// initMouseEvent is deprecated.
17026						ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
17027						ev.initEvent('click', true, true);
17028						ev.view = e.view || window;
17029						ev.detail = 1;
17030						ev.screenX = target.screenX || 0;
17031						ev.screenY = target.screenY || 0;
17032						ev.clientX = target.clientX || 0;
17033						ev.clientY = target.clientY || 0;
17034						ev.ctrlKey = !!e.ctrlKey;
17035						ev.altKey = !!e.altKey;
17036						ev.shiftKey = !!e.shiftKey;
17037						ev.metaKey = !!e.metaKey;
17038						ev.button = 0;
17039						ev.relatedTarget = null;
17040						ev._constructed = true;
17041						target.dispatchEvent(ev);
17042				}
17043		};
17044
17045		return me;
17046})();
17047function IScroll (el, options) {
17048		this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
17049		this.scroller = this.wrapper.children[0];
17050		this.scrollerStyle = this.scroller.style;       // cache style for better performance
17051
17052		this.options = {
17053
17054				resizeScrollbars: true,
17055
17056				mouseWheelSpeed: 20,
17057
17058				snapThreshold: 0.334,
17059
17060// INSERT POINT: OPTIONS
17061				disablePointer : !utils.hasPointer,
17062				disableTouch : utils.hasPointer || !utils.hasTouch,
17063				disableMouse : utils.hasPointer || utils.hasTouch,
17064				startX: 0,
17065				startY: 0,
17066				scrollY: true,
17067				directionLockThreshold: 5,
17068				momentum: true,
17069
17070				bounce: true,
17071				bounceTime: 600,
17072				bounceEasing: '',
17073
17074				preventDefault: true,
17075				preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
17075SELECT|LABEL)$/ },
17076
17077				HWCompositing: true,
17078				useTransition: true,
17079				useTransform: true,
17080				bindToWrapper: typeof window.onmousedown === "undefined"
17081		};
17082
17083		for ( var i in options ) {
17084				this.options[i] = options[i];
17085		}
17086
17087		// Normalize options
17088		this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
17089
17090		this.options.useTransition = utils.hasTransition && this.options.useTransition;
17091		this.options.useTransform = utils.hasTransform && this.options.useTransform;
17092
17093		this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
17094		this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
17095
17096		// If you want eventPassthrough I have to lock one of the axes
17097		this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
17098		this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
17099
17100		// With eventPassthrough we also need lockDirection mechanism
17101		this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
17102		this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
17103
17104		this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
17105
17106		this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
17107
17108		if ( this.options.tap === true ) {
17109				this.options.tap = 'tap';
17110		}
17111
17112		// https://github.com/cubiq/iscroll/issues/1029
17113		if (!this.options.useTransition && !this.options.useTransform) {
17114				if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
17115						this.scrollerStyle.position = "relative";
17116				}
17117		}
17118
17119		if ( this.options.shrinkScrollbars == 'scale' ) {
17120				this.options.useTransition = false;
17121		}
17122
17123		this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
17124
17125// INSERT POINT: NORMALIZATION
17126
17127		// Some defaults
17128		this.x = 0;
17129		this.y = 0;
17130		this.directionX = 0;
17131		this.directionY = 0;
17132		this._events = {};
17133
17134// INSERT POINT: DEFAULTS
17135
17136		this._init();
17137		this.refresh();
17138
17139		this.scrollTo(this.options.startX, this.options.startY);
17140		this.enable();
17141}
17142
17143IScroll.prototype = {
17144		version: '5.2.0',
17145
17146		_init: function () {
17147				this._initEvents();
17148
17149				if ( this.options.scrollbars || this.options.indicators ) {
17150						this._initIndicators();
17151				}
17152
17153				if ( this.options.mouseWheel ) {
17154						this._initWheel();
17155				}
17156
17157				if ( this.options.snap ) {
17158						this._initSnap();
17159				}
17160
17161				if ( this.options.keyBindings ) {
17162						this._initKeys();
17163				}
17164
17165// INSERT POINT: _init
17166
17167		},
17168
17169		destroy: function () {
17170				this._initEvents(true);
17171				clearTimeout(this.resizeTimeout);
17172				this.resizeTimeout = null;
17173				this._execEvent('destroy');
17174		},
17175
17176		_transitionEnd: function (e) {
17177				if ( e.target != this.scroller || !this.isInTransition ) {
17178						return;
17179				}
17180
17181				this._transitionTime();
17182				if ( !this.resetPosition(this.options.bounceTime) ) {
17183						this.isInTransition = false;
17184						this._execEvent('scrollEnd');
17185				}
17186		},
17187
17188		_start: function (e) {
17189				// React to left mouse button only
17190				if ( utils.eventType[e.type] != 1 ) {
17191					// for button property
17192					// http://unixpapa.com/js/mouse.html
17193					var button;
17194				if (!e.which) {
17195					/* IE case */
17196					button = (e.button < 2) ? 0 :
17197									 ((e.button == 4) ? 1 : 2);
17198				} else {
17199					/* All others */
17200					button = e.button;
17201				}
17202						if ( button !== 0 ) {
17203								return;
17204						}
17205				}
17206
17207				if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
17208						return;
17209				}
17210
17211				if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
17212						e.preventDefault();
17213				}
17214
17215				var point = e.touches ? e.touches[0] : e,
17216						pos;
17217
17218				this.initiated  = utils.eventType[e.type];
17219				this.moved      = false;
17220				this.distX      = 0;
17221				this.distY      = 0;
17222				this.directionX = 0;
17223				this.directionY = 0;
17224				this.directionLocked = 0;
17225
17226				this.startTime = utils.getTime();
17227
17228				if ( this.options.useTransition && this.isInTransition ) {
17229						this._transitionTime();
17230						this.isInTransition = false;
17231						pos = this.getComputedPosition();
17232						this._translate(Math.round(pos.x), Math.round(pos.y));
17233						this._execEvent('scrollEnd');
17234				} else if ( !this.options.useTransition && this.isAnimating ) {
17235						this.isAnimating = false;
17236						this._execEvent('scrollEnd');
17237				}
17238
17239				this.startX    = this.x;
17240				this.startY    = this.y;
17241				this.absStartX = this.x;
17242				this.absStartY = this.y;
17243				this.pointX    = point.pageX;
17244				this.pointY    = point.pageY;
17245
17246				this._execEvent('beforeScrollStart');
17247		},
17248
17249		_move: function (e) {
17250				if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
17251						return;
17252				}
17253
17254				if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
17255						e.preventDefault();
17256				}
17257
17258				var point       = e.touches ? e.touches[0] : e,
17259						deltaX      = point.pageX - this.pointX,
17260						deltaY      = point.pageY - this.pointY,
17261						timestamp   = utils.getTime(),
17262						newX, newY,
17263						absDistX, absDistY;
17264
17265				this.pointX     = point.pageX;
17266				this.pointY     = point.pageY;
17267
17268				this.distX      += deltaX;
17269				this.distY      += deltaY;
17270				absDistX        = Math.abs(this.distX);
17271				absDistY        = Math.abs(this.distY);
17272
17273				// We need to move at least 10 pixels for the scrolling to initiate
17274				if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
17275						return;
17276				}
17277
17278				// If you are scrolling in one direction lock the other
17279				if ( !this.directionLocked && !this.options.freeScroll ) {
17280						if ( absDistX > absDistY + this.options.directionLockThreshold ) {
17281								this.directionLocked = 'h';     // lock horizontally
17282						} else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
17283								this.directionLocked = 'v';     // lock vertically
17284						} else {
17285								this.directionLocked = 'n';     // no lock
17286						}
17287				}
17288
17289				if ( this.directionLocked == 'h' ) {
17290						if ( this.options.eventPassthrough == 'vertical' ) {
17291								e.preventDefault();
17292						} else if ( this.options.eventPassthrough == 'horizontal' ) {
17293								this.initiated = false;
17294								return;
17295						}
17296
17297						deltaY = 0;
17298				} else if ( this.directionLocked == 'v' ) {
17299						if ( this.options.eventPassthrough == 'horizontal' ) {
17300								e.preventDefault();
17301						} else if ( this.options.eventPassthrough == 'vertical' ) {
17302								this.initiated = false;
17303								return;
17304						}
17305
17306						deltaX = 0;
17307				}
17308
17309				deltaX = this.hasHorizontalScroll ? deltaX : 0;
17310				deltaY = this.hasVerticalScroll ? deltaY : 0;
17311
17312				newX = this.x + deltaX;
17313				newY = this.y + deltaY;
17314
17315				// Slow down if outside of the boundaries
17316				if ( newX > 0 || newX < this.maxScrollX ) {
17317						newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
17318				}
17319				if ( newY > 0 || newY < this.maxScrollY ) {
17320						newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
17321				}
17322
17323				this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
17324				this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
17325
17326				if ( !this.moved ) {
17327						this._execEvent('scrollStart');
17328				}
17329
17330				this.moved = true;
17331
17332				this._translate(newX, newY);
17333
17334/* REPLACE START: _move */
17335
17336				if ( timestamp - this.startTime > 300 ) {
17337						this.startTime = timestamp;
17338						this.startX = this.x;
17339						this.startY = this.y;
17340				}
17341
17342/* REPLACE END: _move */
17343
17344		},
17345
17346		_end: function (e) {
17347				if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
17348						return;
17349				}
17350
17351				if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
17352						e.preventDefault();
17353				}
17354
17355				var point = e.changedTouches ? e.changedTouches[0] : e,
17356						momentumX,
17357						momentumY,
17358						duration = utils.getTime() - this.startTime,
17359						newX = Math.round(this.x),
17360						newY = Math.round(this.y),
17361						distanceX = Math.abs(newX - this.startX),
17362						distanceY = Math.abs(newY - this.startY),
17363						time = 0,
17364						easing = '';
17365
17366				this.isInTransition = 0;
17367				this.initiated = 0;
17368				this.endTime = utils.getTime();
17369
17370				// reset if we are outside of the boundaries
17371				if ( this.resetPosition(this.options.bounceTime) ) {
17372						return;
17373				}
17374
17375				this.scrollTo(newX, newY);  // ensures that the last position is rounded
17376
17377				// we scrolled less than 10 pixels
17378				if ( !this.moved ) {
17379						if ( this.options.tap ) {
17380								utils.tap(e, this.options.tap);
17381						}
17382
17383						if ( this.options.click ) {
17384								utils.click(e);
17385						}
17386
17387						this._execEvent('scrollCancel');
17388						return;
17389				}
17390
17391				if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
17392						this._execEvent('flick');
17393						return;
17394				}
17395
17396				// start momentum animation if needed
17397				if ( this.options.momentum && duration < 300 ) {
17398						momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
17398idth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
17399						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 };
17400						newX = momentumX.destination;
17401						newY = momentumY.destination;
17402						time = Math.max(momentumX.duration, momentumY.duration);
17403						this.isInTransition = 1;
17404				}
17405
17406
17407				if ( this.options.snap ) {
17408						var snap = this._nearestSnap(newX, newY);
17409						this.currentPage = snap;
17410						time = this.options.snapSpeed || Math.max(
17411										Math.max(
17412												Math.min(Math.abs(newX - snap.x), 1000),
17413												Math.min(Math.abs(newY - snap.y), 1000)
17414										), 300);
17415						newX = snap.x;
17416						newY = snap.y;
17417
17418						this.directionX = 0;
17419						this.directionY = 0;
17420						easing = this.options.bounceEasing;
17421				}
17422
17423// INSERT POINT: _end
17424
17425				if ( newX != this.x || newY != this.y ) {
17426						// change easing function when scroller goes out of the boundaries
17427						if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
17428								easing = utils.ease.quadratic;
17429						}
17430
17431						this.scrollTo(newX, newY, time, easing);
17432						return;
17433				}
17434
17435				this._execEvent('scrollEnd');
17436		},
17437
17438		_resize: function () {
17439				var that = this;
17440
17441				clearTimeout(this.resizeTimeout);
17442
17443				this.resizeTimeout = setTimeout(function () {
17444						that.refresh();
17445				}, this.options.resizePolling);
17446		},
17447
17448		resetPosition: function (time) {
17449				var x = this.x,
17450						y = this.y;
17451
17452				time = time || 0;
17453
17454				if ( !this.hasHorizontalScroll || this.x > 0 ) {
17455						x = 0;
17456				} else if ( this.x < this.maxScrollX ) {
17457						x = this.maxScrollX;
17458				}
17459
17460				if ( !this.hasVerticalScroll || this.y > 0 ) {
17461						y = 0;
17462				} else if ( this.y < this.maxScrollY ) {
17463						y = this.maxScrollY;
17464				}
17465
17466				if ( x == this.x && y == this.y ) {
17467						return false;
17468				}
17469
17470				this.scrollTo(x, y, time, this.options.bounceEasing);
17471
17472				return true;
17473		},
17474
17475		disable: function () {
17476				this.enabled = false;
17477		},
17478
17479		enable: function () {
17480				this.enabled = true;
17481		},
17482
17483		refresh: function () {
17484				var rf = this.wrapper.offsetHeight;     // Force reflow
17485
17486				this.wrapperWidth   = this.wrapper.clientWidth;
17487				this.wrapperHeight  = this.wrapper.clientHeight;
17488
17489/* REPLACE START: refresh */
17490
17491				this.scrollerWidth  = this.scroller.offsetWidth;
17492				this.scrollerHeight = this.scroller.offsetHeight;
17493
17494				this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
17495				this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
17496
17497/* REPLACE END: refresh */
17498
17499				this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
17500				this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
17501
17502				if ( !this.hasHorizontalScroll ) {
17503						this.maxScrollX = 0;
17504						this.scrollerWidth = this.wrapperWidth;
17505				}
17506
17507				if ( !this.hasVerticalScroll ) {
17508						this.maxScrollY = 0;
17509						this.scrollerHeight = this.wrapperHeight;
17510				}
17511
17512				this.endTime = 0;
17513				this.directionX = 0;
17514				this.directionY = 0;
17515
17516				this.wrapperOffset = utils.offset(this.wrapper);
17517
17518				this._execEvent('refresh');
17519
17520				this.resetPosition();
17521
17522// INSERT POINT: _refresh
17523
17524		},
17525
17526		on: function (type, fn) {
17527				if ( !this._events[type] ) {
17528						this._events[type] = [];
17529				}
17530
17531				this._events[type].push(fn);
17532		},
17533
17534		off: function (type, fn) {
17535				if ( !this._events[type] ) {
17536						return;
17537				}
17538
17539				var index = this._events[type].indexOf(fn);
17540
17541				if ( index > -1 ) {
17542						this._events[type].splice(index, 1);
17543				}
17544		},
17545
17546		_execEvent: function (type) {
17547				if ( !this._events[type] ) {
17548						return;
17549				}
17550
17551				var i = 0,
17552						l = this._events[type].length;
17553
17554				if ( !l ) {
17555						return;
17556				}
17557
17558				for ( ; i < l; i++ ) {
17559						this._events[type][i].apply(this, [].slice.call(arguments, 1));
17560				}
17561		},
17562
17563		scrollBy: function (x, y, time, easing) {
17564				x = this.x + x;
17565				y = this.y + y;
17566				time = time || 0;
17567
17568				this.scrollTo(x, y, time, easing);
17569		},
17570
17571		scrollTo: function (x, y, time, easing) {
17572				easing = easing || utils.ease.circular;
17573
17574				this.isInTransition = this.options.useTransition && time > 0;
17575				var transitionType = this.options.useTransition && easing.style;
17576				if ( !time || transitionType ) {
17577								if(transitionType) {
17578										this._transitionTimingFunction(easing.style);
17579										this._transitionTime(time);
17580								}
17581						this._translate(x, y);
17582				} else {
17583						this._animate(x, y, time, easing.fn);
17584				}
17585		},
17586
17587		scrollToElement: function (el, time, offsetX, offsetY, easing) {
17588				el = el.nodeType ? el : this.scroller.querySelector(el);
17589
17590				if ( !el ) {
17591						return;
17592				}
17593
17594				var pos = utils.offset(el);
17595
17596				pos.left -= this.wrapperOffset.left;
17597				pos.top  -= this.wrapperOffset.top;
17598
17599				// if offsetX/Y are true we center the element to the screen
17600				if ( offsetX === true ) {
17601						offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
17602				}
17603				if ( offsetY === true ) {
17604						offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
17605				}
17606
17607				pos.left -= offsetX || 0;
17608				pos.top  -= offsetY || 0;
17609
17610				pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
17611				pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
17612
17613				time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
17614
17615				this.scrollTo(pos.left, pos.top, time, easing);
17616		},
17617
17618		_transitionTime: function (time) {
17619				if (!this.options.useTransition) {
17620						return;
17621				}
17622				time = time || 0;
17623				var durationProp = utils.style.transitionDuration;
17624				if(!durationProp) {
17625						return;
17626				}
17627
17628				this.scrollerStyle[durationProp] = time + 'ms';
17629
17630				if ( !time && utils.isBadAndroid ) {
17631						this.scrollerStyle[durationProp] = '0.0001ms';
17632						// remove 0.0001ms
17633						var self = this;
17634						rAF(function() {
17635								if(self.scrollerStyle[durationProp] === '0.0001ms') {
17636										self.scrollerStyle[durationProp] = '0s';
17637								}
17638						});
17639				}
17640
17641
17642				if ( this.indicators ) {
17643						for ( var i = this.indicators.length; i--; ) {
17644								this.indicators[i].transitionTime(time);
17645						}
17646				}
17647
17648
17649// INSERT POINT: _transitionTime
17650
17651		},
17652
17653		_transitionTimingFunction: function (easing) {
17654				this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
17655
17656
17657				if ( this.indicators ) {
17658						for ( var i = this.indicators.length; i--; ) {
17659								this.indicators[i].transitionTimingFunction(easing);
17660						}
17661				}
17662
17663
17664// INSERT POINT: _transitionTimingFunction
17665
17666		},
17667
17668		_translate: function (x, y) {
17669				//Uncode addition
17670				if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
17671						return false;
17672
17673				if ( this.options.useTransform ) {
17674
17675/* REPLACE START: _translate */
17676
17677						this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
17678
17679/* REPLACE END: _translate */
17680
17681				} else {
17682						x = Math.round(x);
17683						y = Math.round(y);
17684						this.scrollerStyle.left = x + 'px';
17685						this.scrollerStyle.top = y + 'px';
17686				}
17687
17688				this.x = x;
17689				this.y = y;
17690
17691
17692				if ( this.indicators ) {
17693						for ( var i = this.indicators.length; i--; ) {
17694								this.indicators[i].updatePosition();
17695						}
17696				}
17697
17698				//Uncode addition
17699				var uncodevent = new CustomEvent('fp-slide-scroll');
17700				window.dispatchEvent(uncodevent);
17701
17702// INSERT POINT: _translate
17703
17704		},
17705
17706		_initEvents: function (remove) {
17707				var eventType = remove ? utils.removeEvent : utils.addEvent,
17708						target = this.options.bindToWrapper ? this.wrapper : window;
17709
17710				eventType(window, 'orientationchange', this);
17711				eventType(window, 'resize', this);
17712
17713				if ( this.options.click ) {
17714						eventType(this.wrapper, 'click', this, true);
17715				}
17716
17717				if ( !this.options.disableMouse ) {
17718						eventType(this.wrapper, 'mousedown', this);
17719						eventType(target, 'mousemove', this);
17720						eventType(target, 'mousecancel', this);
17721						eventType(target, 'mouseup', this);
17722				}
17723
17724				if ( utils.hasPointer && !this.options.disablePointer ) {
17725						eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
17726						eventType(target, utils.prefixPointerEvent('pointermove'), this);
17727						eventType(target, utils.prefixPointerEvent('pointercancel'), this);
17728						eventType(target, utils.prefixPointerEvent('pointerup'), this);
17729				}
17730
17731				if ( utils.hasTouch && !this.options.disableTouch ) {
17732						eventType(this.wrapper, 'touchstart', this);
17733						eventType(target, 'touchmove', this);
17734						eventType(target, 'touchcancel', this);
17735						eventType(target, 'touchend', this);
17736				}
17737
17738				eventType(this.scroller, 'transitionend', this);
17739				eventType(this.scroller, 'webkitTransitionEnd', this);
17740				eventType(this.scroller, 'oTransitionEnd', this);
17741				eventType(this.scroller, 'MSTransitionEnd', this);
17742		},
17743
17744		getComputedPosition: function () {
17745				var matrix = window.getComputedStyle(this.scroller, null),
17746						x, y;
17747
17748				if ( this.options.useTransform ) {
17749						matrix = matrix[utils.style.transform].split(')')[0].split(', ');
17750						x = +(matrix[12] || matrix[4]);
17751						y = +(matrix[13] || matrix[5]);
17752				} else {
17753						x = +matrix.left.replace(/[^-\d.]/g, '');
17754						y = +matrix.top.replace(/[^-\d.]/g, '');
17755				}
17756
17757				return { x: x, y: y };
17758		},
17759		_initIndicators: function () {
17760				var interactive = this.options.interactiveScrollbars,
17761						customStyle = typeof this.options.scrollbars != 'string',
17762						indicators = [],
17763						indicator;
17764
17765				var that = this;
17766
17767				this.indicators = [];
17768
17769				if ( this.options.scrollbars ) {
17770						// Vertical scrollbar
17771						if ( this.options.scrollY ) {
17772								indicator = {
17773										el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
17774										interactive: interactive,
17775										defaultScrollbars: true,
17776										customStyle: customStyle,
17777										resize: this.options.resizeScrollbars,
17778										shrink: this.options.shrinkScrollbars,
17779										fade: this.options.fadeScrollbars,
17780										listenX: false
17781								};
17782
17783								this.wrapper.appendChild(indicator.el);
17784								indicators.push(indicator);
17785						}
17786
17787						// Horizontal scrollbar
17788						if ( this.options.scrollX ) {
17789								indicator = {
17790										el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
17791										interactive: interactive,
17792										defaultScrollbars: true,
17793										customStyle: customStyle,
17794										resize: this.options.resizeScrollbars,
17795										shrink: this.options.shrinkScrollbars,
17796										fade: this.options.fadeScrollbars,
17797										listenY: false
17798								};
17799
17800								this.wrapper.appendChild(indicator.el);
17801								indicators.push(indicator);
17802						}
17803				}
17804
17805				if ( this.options.indicators ) {
17806						// TODO: check concat compatibility
17807						indicators = indicators.concat(this.options.indicators);
17808				}
17809
17810				for ( var i = indicators.length; i--; ) {
17811						this.indicators.push( new Indicator(this, indicators[i]) );
17812				}
17813
17814				// TODO: check if we can use array.map (wide compatibility and performance issues)
17815				function _indicatorsMap (fn) {
17816						if (that.indicators) {
17817								for ( var i = that.indicators.length; i--; ) {
17818										fn.call(that.indicators[i]);
17819								}
17820						}
17821				}
17822
17823				if ( this.options.fadeScrollbars ) {
17824						this.on('scrollEnd', function () {
17825								_indicatorsMap(function () {
17826										this.fade();
17827								});
17828						});
17829
17830						this.on('scrollCancel', function () {
17831								_indicatorsMap(function () {
17832										this.fade();
17833								});
17834						});
17835
17836						this.on('scrollStart', function () {
17837								_indicatorsMap(function () {
17838										this.fade(1);
17839								});
17840						});
17841
17842						this.on('beforeScrollStart', function () {
17843								_indicatorsMap(function () {
17844										this.fade(1, true);
17845								});
17846						});
17847				}
17848
17849
17850				this.on('refresh', function () {
17851						_indicatorsMap(function () {
17852								this.refresh();
17853						});
17854				});
17855
17856				this.on('destroy', function () {
17857						_indicatorsMap(function () {
17858								this.destroy();
17859						});
17860
17861						delete this.indicators;
17862				});
17863		},
17864
17865		_initWheel: function () {
17866				utils.addEvent(this.wrapper, 'wheel', this);
17867				utils.addEvent(this.wrapper, 'mousewheel', this);
17868				utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
17869
17870				this.on('destroy', function () {
17871						clearTimeout(this.wheelTimeout);
17872						this.wheelTimeout = null;
17873						utils.removeEvent(this.wrapper, 'wheel', this);
17874						utils.removeEvent(this.wrapper, 'mousewheel', this);
17875						utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
17876				});
17877		},
17878
17879		_wheel: function (e) {
17880				if ( !this.enabled ) {
17881						return;
17882				}
17883
17884				var wheelDeltaX, wheelDeltaY,
17885						newX, newY,
17886						that = this;
17887
17888				if ( this.wheelTimeout === undefined ) {
17889						that._execEvent('scrollStart');
17890				}
17891
17892				// Execute the scrollEnd event after 400ms the wheel stopped scrolling
17893				clearTimeout(this.wheelTimeout);
17894				this.wheelTimeout = setTimeout(function () {
17895						if(!that.options.snap) {
17896								that._execEvent('scrollEnd');
17897						}
17898						that.wheelTimeout = undefined;
17899				}, 400);
17900
17901				if ( 'deltaX' in e ) {
17902						if (e.deltaMode === 1) {
17903								wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
17904								wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
17905						} else {
17906								wheelDeltaX = -e.deltaX;
17907								wheelDeltaY = -e.deltaY;
17908						}
17909				} else if ( 'wheelDeltaX' in e ) {
17910						wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
17911						wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
17912				} else if ( 'wheelDelta' in e ) {
17913						wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
17914				} else if ( 'detail' in e ) {
17915						wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
17916				} else {
17917						return;
17918				}
17919
17920				wheelDeltaX *= this.options.invertWheelDirection;
17921				wheelDeltaY *= this.options.invertWheelDirection;
17922
17923				if ( !this.hasVerticalScroll ) {
17924						wheelDeltaX = wheelDeltaY;
17925						wheelDeltaY = 0;
17926				}
17927
17928				if ( this.options.snap ) {
17929						newX = this.currentPage.pageX;
17930						newY = this.currentPage.pageY;
17931
17932						if ( wheelDeltaX > 0 ) {
17933								newX--;
17934						} else if ( wheelDeltaX < 0 ) {
17935								newX++;
17936						}
17937
17938						if ( wheelDeltaY > 0 ) {
17939								newY--;
17940						} else if ( wheelDeltaY < 0 ) {
17941								newY++;
17942						}
17943
17944						this.goToPage(newX, newY);
17945
17946						return;
17947				}
17948
17949				newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
17950				newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
17951
17952				this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
17953				this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
17954
17955				if ( newX > 0 ) {
17956						newX = 0;
17957				} else if ( newX < this.maxScrollX ) {
17958						newX = this.maxScrollX;
17959				}
17960
17961				if ( newY > 0 ) {
17962						newY = 0;
17963				} else if ( newY < this.maxScrollY ) {
17964						newY = this.maxScrollY;
17965				}
17966
17967				this.scrollTo(newX, newY, 0);
17968
17969// INSERT POINT: _wheel
17970		},
17971
17972		_initSnap: function () {
17973				this.currentPage = {};
17974
17975				if ( typeof this.options.snap == 'string' ) {
17976						this.options.snap = this.scroller.querySelectorAll(this.options.snap);
17977				}
17978
17979				this.on('refresh', function () {
17980						var i = 0, l,
17981								m = 0, n,
17982								cx, cy,
17983								x = 0, y,
17984								stepX = this.options.snapStepX || this.wrapperWidth,
17985								stepY = this.options.snapStepY || this.wrapperHeight,
17986								el;
17987
17988						this.pages = [];
17989
17990						if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
17991								return;
17992						}
17993
17994						if ( this.options.snap === true ) {
17995								cx = Math.round( stepX / 2 );
17996								cy = Math.round( stepY / 2 );
17997
17998								while ( x > -this.scrollerWidth ) {
17999										this.pages[i] = [];
18000										l = 0;
18001										y = 0;
18002
18003										while ( y > -this.scrollerHeight ) {
18004												this.pages[i][l] = {
18005														x: Math.max(x, this.maxScrollX),
18006														y: Math.max(y, this.maxScrollY),
18007														width: stepX,
18008														height: stepY,
18009														cx: x - cx,
18010														cy: y - cy
18011												};
18012
18013												y -= stepY;
18014												l++;
18015										}
18016
18017										x -= stepX;
18018										i++;
18019								}
18020						} else {
18021								el = this.options.snap;
18022								l = el.length;
18023								n = -1;
18024
18025								for ( ; i < l; i++ ) {
18026										if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
18027												m = 0;
18028												n++;
18029										}
18030
18031										if ( !this.pages[m] ) {
18032												this.pages[m] = [];
18033										}
18034
18035										x = Math.max(-el[i].offsetLeft, this.maxScrollX);
18036										y = Math.max(-el[i].offsetTop, this.maxScrollY);
18037										cx = x - Math.round(el[i].offsetWidth / 2);
18038										cy = y - Math.round(el[i].offsetHeight / 2);
18039
18040										this.pages[m][n] = {
18041												x: x,
18042												y: y,
18043												width: el[i].offsetWidth,
18044												height: el[i].offsetHeight,
18045												cx: cx,
18046												cy: cy
18047										};
18048
18049										if ( x > this.maxScrollX ) {
18050												m++;
18051										}
18052								}
18053						}
18054
18055						this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
18056
18057						// Update snap threshold if needed
18058						if ( this.options.snapThreshold % 1 === 0 ) {
18059								this.snapThresholdX = this.options.snapThreshold;
18060								this.snapThresholdY = this.options.snapThreshold;
18061						} else {
18062								this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
18063								this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
18064						}
18065				});
18066
18067				this.on('flick', function () {
18068						var time = this.options.snapSpeed || Math.max(
18069										Math.max(
18070												Math.min(Math.abs(this.x - this.startX), 1000),
18071												Math.min(Math.abs(this.y - this.startY), 1000)
18072										), 300);
18073
18074						this.goToPage(
18075								this.currentPage.pageX + this.directionX,
18076								this.currentPage.pageY + this.directionY,
18077								time
18078						);
18079				});
18080		},
18081
18082		_nearestSnap: function (x, y) {
18083				if ( !this.pages.length ) {
18084						return { x: 0, y: 0, pageX: 0, pageY: 0 };
18085				}
18086
18087				var i = 0,
18088						l = this.pages.length,
18089						m = 0;
18090
18091				// Check if we exceeded the snap threshold
18092				if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
18093						Math.abs(y - this.absStartY) < this.snapThresholdY ) {
18094						return this.currentPage;
18095				}
18096
18097				if ( x > 0 ) {
18098						x = 0;
18099				} else if ( x < this.maxScrollX ) {
18100						x = this.maxScrollX;
18101				}
18102
18103				if ( y > 0 ) {
18104						y = 0;
18105				} else if ( y < this.maxScrollY ) {
18106						y = this.maxScrollY;
18107				}
18108
18109				for ( ; i < l; i++ ) {
18110						if ( x >= this.pages[i][0].cx ) {
18111								x = this.pages[i][0].x;
18112								break;
18113						}
18114				}
18115
18116				l = this.pages[i].length;
18117
18118				for ( ; m < l; m++ ) {
18119						if ( y >= this.pages[0][m].cy ) {
18120								y = this.pages[0][m].y;
18121								break;
18122						}
18123				}
18124
18125				if ( i == this.currentPage.pageX ) {
18126						i += this.directionX;
18127
18128						if ( i < 0 ) {
18129								i = 0;
18130						} else if ( i >= this.pages.length ) {
18131								i = this.pages.length - 1;
18132						}
18133
18134						x = this.pages[i][0].x;
18135				}
18136
18137				if ( m == this.currentPage.pageY ) {
18138						m += this.directionY;
18139
18140						if ( m < 0 ) {
18141								m = 0;
18142						} else if ( m >= this.pages[0].length ) {
18143								m = this.pages[0].length - 1;
18144						}
18145
18146						y = this.pages[0][m].y;
18147				}
18148
18149				return {
18150						x: x,
18151						y: y,
18152						pageX: i,
18153						pageY: m
18154				};
18155		},
18156
18157		goToPage: function (x, y, time, easing) {
18158				easing = easing || this.options.bounceEasing;
18159
18160				if ( x >= this.pages.length ) {
18161						x = this.pages.length - 1;
18162				} else if ( x < 0 ) {
18163						x = 0;
18164				}
18165
18166				if ( y >= this.pages[x].length ) {
18167						y = this.pages[x].length - 1;
18168				} else if ( y < 0 ) {
18169						y = 0;
18170				}
18171
18172				var posX = this.pages[x][y].x,
18173						posY = this.pages[x][y].y;
18174
18175				time = time === undefined ? this.options.snapSpeed || Math.max(
18176						Math.max(
18177								Math.min(Math.abs(posX - this.x), 1000),
18178								Math.min(Math.abs(posY - this.y), 1000)
18179						), 300) : time;
18180
18181				this.currentPage = {
18182						x: posX,
18183						y: posY,
18184						pageX: x,
18185						pageY: y
18186				};
18187
18188				this.scrollTo(posX, posY, time, easing);
18189		},
18190
18191		next: function (time, easing) {
18192				var x = this.currentPage.pageX,
18193						y = this.currentPage.pageY;
18194
18195				x++;
18196
18197				if ( x >= this.pages.length && this.hasVerticalScroll ) {
18198						x = 0;
18199						y++;
18200				}
18201
18202				this.goToPage(x, y, time, easing);
18203		},
18204
18205		prev: function (time, easing) {
18206				var x = this.currentPage.pageX,
18207						y = this.currentPage.pageY;
18208
18209				x--;
18210
18211				if ( x < 0 && this.hasVerticalScroll ) {
18212						x = 0;
18213						y--;
18214				}
18215
18216				this.goToPage(x, y, time, easing);
18217		},
18218
18219		_initKeys: function (e) {
18220				// default key bindings
18221				var keys = {
18222						pageUp: 33,
18223						pageDown: 34,
18224						end: 35,
18225						home: 36,
18226						left: 37,
18227						up: 38,
18228						right: 39,
18229						down: 40
18230				};
18231				var i;
18232
18233				// if you give me characters I give you keycode
18234				if ( typeof this.options.keyBindings == 'object' ) {
18235						for ( i in this.options.keyBindings ) {
18236								if ( typeof this.options.keyBindings[i] == 'string' ) {
18237										this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
18237deAt(0);
18238								}
18239						}
18240				} else {
18241						this.options.keyBindings = {};
18242				}
18243
18244				for ( i in keys ) {
18245						this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
18246				}
18247
18248				utils.addEvent(window, 'keydown', this);
18249
18250				this.on('destroy', function () {
18251						utils.removeEvent(window, 'keydown', this);
18252				});
18253		},
18254
18255		_key: function (e) {
18256				if ( !this.enabled ) {
18257						return;
18258				}
18259
18260				var snap = this.options.snap,   // we are using this alot, better to cache it
18261						newX = snap ? this.currentPage.pageX : this.x,
18262						newY = snap ? this.currentPage.pageY : this.y,
18263						now = utils.getTime(),
18264						prevTime = this.keyTime || 0,
18265						acceleration = 0.250,
18266						pos;
18267
18268				if ( this.options.useTransition && this.isInTransition ) {
18269						pos = this.getComputedPosition();
18270
18271						this._translate(Math.round(pos.x), Math.round(pos.y));
18272						this.isInTransition = false;
18273				}
18274
18275				this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
18276
18277				switch ( e.keyCode ) {
18278						case this.options.keyBindings.pageUp:
18279								if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
18280										newX += snap ? 1 : this.wrapperWidth;
18281								} else {
18282										newY += snap ? 1 : this.wrapperHeight;
18283								}
18284								break;
18285						case this.options.keyBindings.pageDown:
18286								if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
18287										newX -= snap ? 1 : this.wrapperWidth;
18288								} else {
18289										newY -= snap ? 1 : this.wrapperHeight;
18290								}
18291								break;
18292						case this.options.keyBindings.end:
18293								newX = snap ? this.pages.length-1 : this.maxScrollX;
18294								newY = snap ? this.pages[0].length-1 : this.maxScrollY;
18295								break;
18296						case this.options.keyBindings.home:
18297								newX = 0;
18298								newY = 0;
18299								break;
18300						case this.options.keyBindings.left:
18301								newX += snap ? -1 : 5 + this.keyAcceleration>>0;
18302								break;
18303						case this.options.keyBindings.up:
18304								newY += snap ? 1 : 5 + this.keyAcceleration>>0;
18305								break;
18306						case this.options.keyBindings.right:
18307								newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
18308								break;
18309						case this.options.keyBindings.down:
18310								newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
18311								break;
18312						default:
18313								return;
18314				}
18315
18316				if ( snap ) {
18317						this.goToPage(newX, newY);
18318						return;
18319				}
18320
18321				if ( newX > 0 ) {
18322						newX = 0;
18323						this.keyAcceleration = 0;
18324				} else if ( newX < this.maxScrollX ) {
18325						newX = this.maxScrollX;
18326						this.keyAcceleration = 0;
18327				}
18328
18329				if ( newY > 0 ) {
18330						newY = 0;
18331						this.keyAcceleration = 0;
18332				} else if ( newY < this.maxScrollY ) {
18333						newY = this.maxScrollY;
18334						this.keyAcceleration = 0;
18335				}
18336
18337				this.scrollTo(newX, newY, 0);
18338
18339				this.keyTime = now;
18340		},
18341
18342		_animate: function (destX, destY, duration, easingFn) {
18343				var that = this,
18344						startX = this.x,
18345						startY = this.y,
18346						startTime = utils.getTime(),
18347						destTime = startTime + duration;
18348
18349				function step () {
18350						var now = utils.getTime(),
18351								newX, newY,
18352								easing;
18353
18354						if ( now >= destTime ) {
18355								that.isAnimating = false;
18356								that._translate(destX, destY);
18357
18358								if ( !that.resetPosition(that.options.bounceTime) ) {
18359										that._execEvent('scrollEnd');
18360								}
18361
18362								return;
18363						}
18364
18365						now = ( now - startTime ) / duration;
18366						easing = easingFn(now);
18367						newX = ( destX - startX ) * easing + startX;
18368						newY = ( destY - startY ) * easing + startY;
18369						that._translate(newX, newY);
18370
18371						if ( that.isAnimating ) {
18372								rAF(step);
18373						}
18374				}
18375
18376				this.isAnimating = true;
18377				step();
18378		},
18379		handleEvent: function (e) {
18380				switch ( e.type ) {
18381						case 'touchstart':
18382						case 'pointerdown':
18383						case 'MSPointerDown':
18384						case 'mousedown':
18385								this._start(e);
18386								break;
18387						case 'touchmove':
18388						case 'pointermove':
18389						case 'MSPointerMove':
18390						case 'mousemove':
18391								this._move(e);
18392								break;
18393						case 'touchend':
18394						case 'pointerup':
18395						case 'MSPointerUp':
18396						case 'mouseup':
18397						case 'touchcancel':
18398						case 'pointercancel':
18399						case 'MSPointerCancel':
18400						case 'mousecancel':
18401								this._end(e);
18402								break;
18403						case 'orientationchange':
18404						case 'resize':
18405								this._resize();
18406								break;
18407						case 'transitionend':
18408						case 'webkitTransitionEnd':
18409						case 'oTransitionEnd':
18410						case 'MSTransitionEnd':
18411								this._transitionEnd(e);
18412								break;
18413						case 'wheel':
18414						case 'DOMMouseScroll':
18415						case 'mousewheel':
18416								this._wheel(e);
18417								break;
18418						case 'keydown':
18419								this._key(e);
18420								break;
18421						case 'click':
18422								if ( this.enabled && !e._constructed ) {
18423										e.preventDefault();
18424										e.stopPropagation();
18425								}
18426								break;
18427				}
18428		}
18429};
18430function createDefaultScrollbar (direction, interactive, type) {
18431		var scrollbar = document.createElement('div'),
18432				indicator = document.createElement('div');
18433
18434		if ( type === true ) {
18435				scrollbar.style.cssText = 'position:absolute;z-index:9999';
18436				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';
18437		}
18438
18439		indicator.className = 'iScrollIndicator';
18440
18441		if ( direction == 'h' ) {
18442				if ( type === true ) {
18443						scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
18444						indicator.style.height = '100%';
18445				}
18446				scrollbar.className = 'iScrollHorizontalScrollbar';
18447		} else {
18448				if ( type === true ) {
18449						scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
18450						indicator.style.width = '100%';
18451				}
18452				scrollbar.className = 'iScrollVerticalScrollbar';
18453		}
18454
18455		scrollbar.style.cssText += ';overflow:hidden';
18456
18457		if ( !interactive ) {
18458				scrollbar.style.pointerEvents = 'none';
18459		}
18460
18461		scrollbar.appendChild(indicator);
18462
18463		return scrollbar;
18464}
18465
18466function Indicator (scroller, options) {
18467		this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
18468		this.wrapperStyle = this.wrapper.style;
18469		this.indicator = this.wrapper.children[0];
18470		this.indicatorStyle = this.indicator.style;
18471		this.scroller = scroller;
18472
18473		this.options = {
18474				listenX: true,
18475				listenY: true,
18476				interactive: false,
18477				resize: true,
18478				defaultScrollbars: false,
18479				shrink: false,
18480				fade: false,
18481				speedRatioX: 0,
18482				speedRatioY: 0
18483		};
18484
18485		for ( var i in options ) {
18486				this.options[i] = options[i];
18487		}
18488
18489		this.sizeRatioX = 1;
18490		this.sizeRatioY = 1;
18491		this.maxPosX = 0;
18492		this.maxPosY = 0;
18493
18494		if ( this.options.interactive ) {
18495				if ( !this.options.disableTouch ) {
18496						utils.addEvent(this.indicator, 'touchstart', this);
18497						utils.addEvent(window, 'touchend', this);
18498				}
18499				if ( !this.options.disablePointer ) {
18500						utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
18501						utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
18502				}
18503				if ( !this.options.disableMouse ) {
18504						utils.addEvent(this.indicator, 'mousedown', this);
18505						utils.addEvent(window, 'mouseup', this);
18506				}
18507		}
18508
18509		if ( this.options.fade ) {
18510				this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
18511				var durationProp = utils.style.transitionDuration;
18512				if(!durationProp) {
18513						return;
18514				}
18515				this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
18516				// remove 0.0001ms
18517				var self = this;
18518				if(utils.isBadAndroid) {
18519						rAF(function() {
18520								if(self.wrapperStyle[durationProp] === '0.0001ms') {
18521										self.wrapperStyle[durationProp] = '0s';
18522								}
18523						});
18524				}
18525				this.wrapperStyle.opacity = '0';
18526		}
18527}
18528
18529Indicator.prototype = {
18530		handleEvent: function (e) {
18531				switch ( e.type ) {
18532						case 'touchstart':
18533						case 'pointerdown':
18534						case 'MSPointerDown':
18535						case 'mousedown':
18536								this._start(e);
18537								break;
18538						case 'touchmove':
18539						case 'pointermove':
18540						case 'MSPointerMove':
18541						case 'mousemove':
18542								this._move(e);
18543								break;
18544						case 'touchend':
18545						case 'pointerup':
18546						case 'MSPointerUp':
18547						case 'mouseup':
18548						case 'touchcancel':
18549						case 'pointercancel':
18550						case 'MSPointerCancel':
18551						case 'mousecancel':
18552								this._end(e);
18553								break;
18554				}
18555		},
18556
18557		destroy: function () {
18558				if ( this.options.fadeScrollbars ) {
18559						clearTimeout(this.fadeTimeout);
18560						this.fadeTimeout = null;
18561				}
18562				if ( this.options.interactive ) {
18563						utils.removeEvent(this.indicator, 'touchstart', this);
18564						utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
18565						utils.removeEvent(this.indicator, 'mousedown', this);
18566
18567						utils.removeEvent(window, 'touchmove', this);
18568						utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
18569						utils.removeEvent(window, 'mousemove', this);
18570
18571						utils.removeEvent(window, 'touchend', this);
18572						utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
18573						utils.removeEvent(window, 'mouseup', this);
18574				}
18575
18576				if ( this.options.defaultScrollbars ) {
18577						this.wrapper.parentNode.removeChild(this.wrapper);
18578				}
18579		},
18580
18581		_start: function (e) {
18582				var point = e.touches ? e.touches[0] : e;
18583
18584				e.preventDefault();
18585				e.stopPropagation();
18586
18587				this.transitionTime();
18588
18589				this.initiated = true;
18590				this.moved = false;
18591				this.lastPointX = point.pageX;
18592				this.lastPointY = point.pageY;
18593
18594				this.startTime  = utils.getTime();
18595
18596				if ( !this.options.disableTouch ) {
18597						utils.addEvent(window, 'touchmove', this);
18598				}
18599				if ( !this.options.disablePointer ) {
18600						utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
18601				}
18602				if ( !this.options.disableMouse ) {
18603						utils.addEvent(window, 'mousemove', this);
18604				}
18605
18606				this.scroller._execEvent('beforeScrollStart');
18607		},
18608
18609		_move: function (e) {
18610				var point = e.touches ? e.touches[0] : e,
18611						deltaX, deltaY,
18612						newX, newY,
18613						timestamp = utils.getTime();
18614
18615				if ( !this.moved ) {
18616						this.scroller._execEvent('scrollStart');
18617				}
18618
18619				this.moved = true;
18620
18621				deltaX = point.pageX - this.lastPointX;
18622				this.lastPointX = point.pageX;
18623
18624				deltaY = point.pageY - this.lastPointY;
18625				this.lastPointY = point.pageY;
18626
18627				newX = this.x + deltaX;
18628				newY = this.y + deltaY;
18629
18630				this._pos(newX, newY);
18631
18632// INSERT POINT: indicator._move
18633
18634				e.preventDefault();
18635				e.stopPropagation();
18636		},
18637
18638		_end: function (e) {
18639				if ( !this.initiated ) {
18640						return;
18641				}
18642
18643				this.initiated = false;
18644
18645				e.preventDefault();
18646				e.stopPropagation();
18647
18648				utils.removeEvent(window, 'touchmove', this);
18649				utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
18650				utils.removeEvent(window, 'mousemove', this);
18651
18652				if ( this.scroller.options.snap ) {
18653						var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
18654
18655						var time = this.options.snapSpeed || Math.max(
18656										Math.max(
18657												Math.min(Math.abs(this.scroller.x - snap.x), 1000),
18658												Math.min(Math.abs(this.scroller.y - snap.y), 1000)
18659										), 300);
18660
18661						if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
18662								this.scroller.directionX = 0;
18663								this.scroller.directionY = 0;
18664								this.scroller.currentPage = snap;
18665								this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
18666						}
18667				}
18668
18669				if ( this.moved ) {
18670						this.scroller._execEvent('scrollEnd');
18671				}
18672		},
18673
18674		transitionTime: function (time) {
18675				time = time || 0;
18676				var durationProp = utils.style.transitionDuration;
18677				if(!durationProp) {
18678						return;
18679				}
18680
18681				this.indicatorStyle[durationProp] = time + 'ms';
18682
18683				if ( !time && utils.isBadAndroid ) {
18684						this.indicatorStyle[durationProp] = '0.0001ms';
18685						// remove 0.0001ms
18686						var self = this;
18687						rAF(function() {
18688								if(self.indicatorStyle[durationProp] === '0.0001ms') {
18689										self.indicatorStyle[durationProp] = '0s';
18690								}
18691						});
18692				}
18693		},
18694
18695		transitionTimingFunction: function (easing) {
18696				this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
18697		},
18698
18699		refresh: function () {
18700				this.transitionTime();
18701
18702				if ( this.options.listenX && !this.options.listenY ) {
18703						this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
18704				} else if ( this.options.listenY && !this.options.listenX ) {
18705						this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
18706				} else {
18707						this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
18708				}
18709
18710				if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
18711						utils.addClass(this.wrapper, 'iScrollBothScrollbars');
18712						utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
18713
18714						if ( this.options.defaultScrollbars && this.options.customStyle ) {
18715								if ( this.options.listenX ) {
18716										this.wrapper.style.right = '8px';
18717								} else {
18718										this.wrapper.style.bottom = '8px';
18719								}
18720						}
18721				} else {
18722						utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
18723						utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
18724
18725						if ( this.options.defaultScrollbars && this.options.customStyle ) {
18726								if ( this.options.listenX ) {
18727										this.wrapper.style.right = '2px';
18728								} else {
18729										this.wrapper.style.bottom = '2px';
18730								}
18731						}
18732				}
18733
18734				var r = this.wrapper.offsetHeight;  // force refresh
18735
18736				if ( this.options.listenX ) {
18737						this.wrapperWidth = this.wrapper.clientWidth;
18738						if ( this.options.resize ) {
18739								this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
18740								this.indicatorStyle.width = this.indicatorWidth + 'px';
18741						} else {
18742								this.indicatorWidth = this.indicator.clientWidth;
18743						}
18744
18745						this.maxPosX = this.wrapperWidth - this.indicatorWidth;
18746
18747						if ( this.options.shrink == 'clip' ) {
18748								this.minBoundaryX = -this.indicatorWidth + 8;
18749								this.maxBoundaryX = this.wrapperWidth - 8;
18750						} else {
18751								this.minBoundaryX = 0;
18752								this.maxBoundaryX = this.maxPosX;
18753						}
18754
18755						this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
18756				}
18757
18758				if ( this.options.listenY ) {
18759						this.wrapperHeight = this.wrapper.clientHeight;
18760						if ( this.options.resize ) {
18761								this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
18762								this.indicatorStyle.height = this.indicatorHeight + 'px';
18763						} else {
18764								this.indicatorHeight = this.indicator.clientHeight;
18765						}
18766
18767						this.maxPosY = this.wrapperHeight - this.indicatorHeight;
18768
18769						if ( this.options.shrink == 'clip' ) {
18770								this.minBoundaryY = -this.indicatorHeight + 8;
18771								this.maxBoundaryY = this.wrapperHeight - 8;
18772						} else {
18773								this.minBoundaryY = 0;
18774								this.maxBoundaryY = this.maxPosY;
18775						}
18776
18777						this.maxPosY = this.wrapperHeight - this.indicatorHeight;
18778						this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
18779				}
18780
18781				this.updatePosition();
18782		},
18783
18784		updatePosition: function () {
18785				var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
18786						y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
18787
18788				if ( !this.options.ignoreBoundaries ) {
18789						if ( x < this.minBoundaryX ) {
18790								if ( this.options.shrink == 'scale' ) {
18791										this.width = Math.max(this.indicatorWidth + x, 8);
18792										this.indicatorStyle.width = this.width + 'px';
18793								}
18794								x = this.minBoundaryX;
18795						} else if ( x > this.maxBoundaryX ) {
18796								if ( this.options.shrink == 'scale' ) {
18797										this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
18798										this.indicatorStyle.width = this.width + 'px';
18799										x = this.maxPosX + this.indicatorWidth - this.width;
18800								} else {
18801										x = this.maxBoundaryX;
18802								}
18803						} else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
18804								this.width = this.indicatorWidth;
18805								this.indicatorStyle.width = this.width + 'px';
18806						}
18807
18808						if ( y < this.minBoundaryY ) {
18809								if ( this.options.shrink == 'scale' ) {
18810										this.height = Math.max(this.indicatorHeight + y * 3, 8);
18811										this.indicatorStyle.height = this.height + 'px';
18812								}
18813								y = this.minBoundaryY;
18814						} else if ( y > this.maxBoundaryY ) {
18815								if ( this.options.shrink == 'scale' ) {
18816										this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
18817										this.indicatorStyle.height = this.height + 'px';
18818										y = this.maxPosY + this.indicatorHeight - this.height;
18819								} else {
18820										y = this.maxBoundaryY;
18821								}
18822						} else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
18823								this.height = this.indicatorHeight;
18824								this.indicatorStyle.height = this.height + 'px';
18825						}
18826				}
18827
18828				this.x = x;
18829				this.y = y;
18830
18831				if ( this.scroller.options.useTransform ) {
18832						this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
18833				} else {
18834						this.indicatorStyle.left = x + 'px';
18835						this.indicatorStyle.top = y + 'px';
18836				}
18837		},
18838
18839		_pos: function (x, y) {
18840				if ( x < 0 ) {
18841						x = 0;
18842				} else if ( x > this.maxPosX ) {
18843						x = this.maxPosX;
18844				}
18845
18846				if ( y < 0 ) {
18847						y = 0;
18848				} else if ( y > this.maxPosY ) {
18849						y = this.maxPosY;
18850				}
18851
18852				x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
18853				y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
18854
18855				this.scroller.scrollTo(x, y);
18856		},
18857
18858		fade: function (val, hold) {
18859				if ( hold && !this.visible ) {
18860						return;
18861				}
18862
18863				clearTimeout(this.fadeTimeout);
18864				this.fadeTimeout = null;
18865
18866				var time = val ? 250 : 500,
18867						delay = val ? 0 : 300;
18868
18869				val = val ? '1' : '0';
18870
18871				this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
18872
18873				this.fadeTimeout = setTimeout((function (val) {
18874						this.wrapperStyle.opacity = val;
18875						this.visible = +val;
18876				}).bind(this, val), delay);
18877		}
18878};
18879
18880IScroll.utils = utils;
18881
18882if ( typeof module != 'undefined' && module.exports ) {
18883		module.exports = IScroll;
18884} else if ( typeof define == 'function' && define.amd ) {
18885				define( function () { return IScroll; } );
18886} else {
18887		window.IScroll = IScroll;
18888}
18889
18890})(window, document, Math);
18891/*!
18892 * fullPage 2.9.4
18893 * https://github.com/alvarotrigo/fullPage.js
18894 * @license MIT licensed
18895 *
18896 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
18897 */
18898(function(global, factory) {
18899		'use strict';
18900		if (typeof define === 'function' && define.amd) {
18901				define(['jquery'], function($) {
18902					return factory($, global, global.document, global.Math);
18903				});
18904		} else if (typeof exports === "object" && exports) {
18905				module.exports = factory(require('jquery'), global, global.document, global.Math);
18906		} else {
18907				factory(jQuery, global, global.document, global.Math);
18908		}
18909})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
18910		'use strict';
18911
18912		// keeping central set of classnames and selectors
18913		var WRAPPER =               'fullpage-wrapper';
18914		var WRAPPER_SEL =           '.' + WRAPPER;
18915
18916		// slimscroll
18917		var SCROLLABLE =            'fp-scrollable';
18918		var SCROLLABLE_SEL =        '.' + SCROLLABLE;
18919
18920		// util
18921		var RESPONSIVE =            'fp-responsive';
18922		var NO_TRANSITION =         'fp-notransition';
18923		var DESTROYED =             'fp-destroyed';
18924		var ENABLED =               'fp-enabled';
18925		var VIEWING_PREFIX =        'fp-viewing';
18926		var ACTIVE =                'active';
18927		var ACTIVE_SEL =            '.' + ACTIVE;
18928		var COMPLETELY =            'fp-completely';
18929		var COMPLETELY_SEL =        '.' + COMPLETELY;
18930
18931		// section
18932		var SECTION_DEFAULT_SEL =   '.section';
18933		var SECTION =               'fp-section';
18934		var SECTION_SEL =           '.' + SECTION;
18935		var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
18936		var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
18937		var SECTION_LAST_SEL =      SECTION_SEL + ':last';
18938		var TABLE_CELL =            'fp-tableCell';
18939		var TABLE_CELL_SEL =        '.' + TABLE_CELL;
18940		var AUTO_HEIGHT =           'fp-auto-height';
18941		var AUTO_HEIGHT_SEL =       '.fp-auto-height';
18942		var NORMAL_SCROLL =         'fp-normal-scroll';
18943		var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
18944
18945		// section nav
18946		var SECTION_NAV =           'fp-nav';
18947		var SECTION_NAV_SEL =       '#' + SECTION_NAV;
18948		var SECTION_NAV_TOOLTIP =   'fp-tooltip';
18949		var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
18950		var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
18951
18952		// slide
18953		var SLIDE_DEFAULT_SEL =     '.slide';
18954		var SLIDE =                 'fp-slide';
18955		var SLIDE_SEL =             '.' + SLIDE;
18956		var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
18957		var SLIDES_WRAPPER =        'fp-slides';
18958		var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
18959		var SLIDES_CONTAINER =      'fp-slidesContainer';
18960		var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
18961		var TABLE =                 'fp-table';
18962
18963		// slide nav
18964		var SLIDES_NAV =            'fp-slidesNav';
18965		var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
18966		var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
18967		var SLIDES_ARROW =          'fp-controlArrow';
18968		var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
18969		var SLIDES_PREV =           'fp-prev';
18970		var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
18971		var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
18972		var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
18973		var SLIDES_NEXT =           'fp-next';
18974		var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
18975		var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
18976		var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
18977
18978		var $window = $(window);
18979		var $document = $(document);
18980
18981		// Default options for iScroll.js used when using scrollOverflow
18982		var iscrollOptions = {
18983				scrollbars: true,
18984				mouseWheel: true,
18985				hideScrollbars: false,
18986				fadeScrollbars: false,
18987				disableMouse: true,
18988				interactiveScrollbars: true,
18989				bounce: false,
18990		};
18991
18992		$.fn.fullpage = function(options) {
18993				//only once my friend!
18994				if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
18995
18996				// common jQuery objects
18997				var $htmlBody = $('html, body');
18998				var $body = $('body');
18999
19000				var FP = $.fn.fullpage;
19001
19002				// Creating some defaults, extending them with any options that were provided
19003				options = $.extend({
19004						//navigation
19005						menu: false,
19006						anchors:[],
19007						lockAnchors: false,
19008						navigation: false,
19009						navigationPosition: 'right',
19010						navigationTooltips: [],
19011						showActiveTooltip: false,
19012						slidesNavigation: false,
19013						slidesNavPosition: 'bottom',
19014						scrollBar: false,
19015						hybrid: false,
19016
19017						//scrolling
19018						css3: true,
19019						scrollingSpeed: 700,
19020						autoScrolling: true,
19021						fitToSection: true,
19022						fitToSectionDelay: 1000,
19023						easing: 'easeInOutCubic',
19024						easingcss3: 'ease',
19025						loopBottom: false,
19026						loopTop: false,
19027						loopHorizontal: true,
19028						continuousVertical: false,
19029						continuousHorizontal: false,
19030						scrollHorizontally: false,
19031						interlockedSlides: false,
19032						dragAndMove: false,
19033						offsetSections: false,
19034						resetSliders: false,
19035						fadingEffect: false,
19036						normalScrollElements: null,
19037						scrollOverflow: false,
19038						scrollOverflowReset: false,
19039						scrollOverflowHandler: iscrollHandler,
19040						scrollOverflowOptions: null,
19041						touchSensitivity: 5,
19042						normalScrollElementTouchThreshold: 5,
19043						bigSectionsDestination: null,
19044
19045						//Accessibility
19046						keyboardScrolling: true,
19047						animateAnchor: true,
19048						recordHistory: true,
19049
19050						//design
19051						controlArrows: true,
19052						controlArrowColor: '#fff',
19053						verticalCentered: true,
19054						sectionsColor : [],
19055						paddingTop: 0,
19056						paddingBottom: 0,
19057						fixedElements: null,
19058						responsive: 0, //backwards compabitility with responsiveWiddth
19059						responsiveWidth: 0,
19060						responsiveHeight: 0,
19061						responsiveSlides: false,
19062						parallax: false,
19063						parallaxOptions: {
19064								type: 'reveal',
19065								percentage: 62,
19066								property: 'translate'
19067						},
19068
19069						//Custom selectors
19070						sectionSelector: SECTION_DEFAULT_SEL,
19071						slideSelector: SLIDE_DEFAULT_SEL,
19072
19073						//events
19074						afterLoad: null,
19075						onLeave: null,
19076						afterRender: null,
19077						afterResize: null,
19078						afterReBuild: null,
19079						afterSlideLoad: null,
19080						onSlideLeave: null,
19081						afterResponsive: null,
19082
19083						lazyLoading: true
19084				}, options);
19085
19086				//flag to avoid very fast sliding for landscape sliders
19087				var slideMoving = false;
19088
19089				var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
19090				var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
19091				var container = $(this);
19092				var windowsHeight = $window.height();
19093				var isResizing = false;
19094				var isWindowFocused = true;
19095				var lastScrolledDestiny;
19096				var lastScrolledSlide;
19097				var canScroll = true;
19098				var scrollings = [];
19099				var controlPressed;
19100				var startingSection;
19101				var isScrollAllowed = {};
19102				isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
19103				isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
19104				var MSPointer = getMSPointer();
19105				var events = {
19106						touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
19107						touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
19108				};
19109
19110				//timeouts
19111				var resizeId;
19112				var afterSectionLoadsId;
19113				var afterSlideLoadsId;
19114				var scrollId;
19115				var scrollId2;
19116				var keydownId;
19117				var originals = $.extend(true, {}, options); //deep copy
19118
19119				//Uncode addition
19120				var $masthead = $('#masthead');
19121				var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
19122				var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
19123				var bodyBorder = UNCODE.bodyBorder;
19124				var adminBarHeight = UNCODE.adminBarHeight;
19125
19126				displayWarnings();
19127
19128				//fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
19129				iscrollOptions.click = isTouch; // see #2035
19130
19131				//extending iScroll options with the user custom ones
19132				iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
19133
19134				//easeInOutCubic animation included in the plugin
19135				$.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;}});
19136
19137				/**
19138				* Sets the autoScroll option.
19139				* It changes the scroll bar visibility and the history of the site as a result.
19140				*/
19141				function setAutoScrolling(value, type){
19142						//removing the transformation
19143						if(!value){
19144								silentScroll(0);
19145						}
19146
19147						setVariableState('autoScrolling', value, type);
19148
19149						var element = $(SECTION_ACTIVE_SEL);
19150
19151						if(options.autoScrolling && !options.scrollBar){
19152								$htmlBody.css({
19153										'overflow' : 'hidden !important',
19154										'height' : '100%'
19155								});
19156
19157								//Uncode addition
19158								//setRecordHistory(originals.recordHistory, 'internal');
19159
19160								//for IE touch devices
19161								container.css({
19162										'-ms-touch-action': 'none',
19163										'touch-action': 'none'
19164								});
19165
19166								if(element.length){
19167										//moving the container up
19168										silentScroll(element.position().top);
19169								}
19170
19171						}else{
19172								$htmlBody.css({
19173										'overflow' : 'visible !important',
19174										'height' : 'initial'
19175								});
19176
19177								//Uncode addition
19178								//setRecordHistory(false, 'internal');
19179
19180								//for IE touch devices
19181								container.css({
19182										'-ms-touch-action': '',
19183										'touch-action': ''
19184								});
19185
19186								//scrolling the page to the section with no animation
19187								if (element.length) {
19188										$htmlBody.scrollTop(element.position().top);
19189								}
19190						}
19191				}
19192
19193				/**
19194				* Defines wheter to record the history for each hash change in the URL.
19195				*/
19196				function setRecordHistory(value, type){
19197						setVariableState('recordHistory', value, type);
19198				}
19199
19200				/**
19201				* Defines the scrolling speed
19202				*/
19203				function setScrollingSpeed(value, type){
19204						setVariableState('scrollingSpeed', value, type);
19205				}
19206
19207				/**
19208				* Sets fitToSection
19209				*/
19210				function setFitToSection(value, type){
19211						setVariableState('fitToSection', value, type);
19212				}
19213
19214				/**
19215				* Sets lockAnchors
19216				*/
19217				function setLockAnchors(value){
19218						options.lockAnchors = value;
19219				}
19220
19221				/**
19222				* Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
19223				*/
19224				function setMouseWheelScrolling(value){
19225						if(value){
19226								addMouseWheelHandler();
19227								addMiddleWheelHandler();
19228						}else{
19229								removeMouseWheelHandler();
19230								removeMiddleWheelHandler();
19231						}
19232				}
19233
19234				/**
19235				* Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
19236				* Optionally a second parameter can be used to specify the direction for which the action will be applied.
19237				*
19238				* @param directions string containing the direction or directions separated by comma.
19239				*/
19240				function setAllowScrolling(value, directions){
19241						if(typeof directions !== 'undefined'){
19242								directions = directions.replace(/ /g,'').split(',');
19243
19244								$.each(directions, function (index, direction){
19245										setIsScrollAllowed(value, direction, 'm');
19246								});
19247						}
19248						else if(value){
19249								setMouseWheelScrolling(true);
19250								addTouchHandler();
19251						}else{
19252								setMouseWheelScrolling(false);
19253								removeTouchHandler();
19254						}
19255				}
19256
19257				/**
19258				* Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
19259				*/
19260				function setKeyboardScrolling(value, directions){
19261						if(typeof directions !== 'undefined'){
19262								directions = directions.replace(/ /g,'').split(',');
19263
19264								$.each(directions, function (index, direction){
19265										setIsScrollAllowed(value, direction, 'k');
19266								});
19267						}else{
19268								options.keyboardScrolling = value;
19269						}
19270				}
19271
19272				/**
19273				* Moves the page up one section.
19274				*/
19275				function moveSectionUp(){
19276						var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
19277
19278						//looping to the bottom if there's no more sections above
19279						if (!prev.length && (options.loopTop || options.continuousVertical)) {
19280								prev = $(SECTION_SEL).last();
19281						}
19282
19283						if (prev.length) {
19284								scrollPage(prev, null, true);
19285						}
19286				}
19287
19288				/**
19289				* Moves the page down one section.
19290				*/
19291				function moveSectionDown(){
19292						var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
19293
19294						//looping to the top if there's no more sections below
19295						if(!next.length &&
19296								(options.loopBottom || options.continuousVertical)){
19297								next = $(SECTION_SEL).first();
19298						}
19299
19300						if(next.length){
19301								scrollPage(next, null, false);
19302						}
19303				}
19304
19305				/**
19306				* Moves the page to the given section and slide with no animation.
19307				* Anchors or index positions can be used as params.
19308				*/
19309				function silentMoveTo(sectionAnchor, slideAnchor){
19310						setScrollingSpeed (0, 'internal');
19311						moveTo(sectionAnchor, slideAnchor);
19312						setScrollingSpeed (originals.scrollingSpeed, 'internal');
19313				}
19314
19315				/**
19316				* Moves the page to the given section and slide.
19317				* Anchors or index positions can be used as params.
19318				*/
19319				function moveTo(sectionAnchor, slideAnchor){
19320						var destiny = getSectionByAnchor(sectionAnchor);
19321
19322						if (typeof slideAnchor !== 'undefined'){
19323								scrollPageAndSlide(sectionAnchor, slideAnchor);
19324						}else if(destiny.length > 0){
19325								scrollPage(destiny);
19326						}
19327				}
19328
19329				/**
19330				* Slides right the slider of the active section.
19331				* Optional `section` param.
19332				*/
19333				function moveSlideRight(section){
19334						moveSlide('right', section);
19335				}
19336
19337				/**
19338				* Slides left the slider of the active section.
19339				* Optional `section` param.
19340				*/
19341				function moveSlideLeft(section){
19342						moveSlide('left', section);
19343				}
19344
19345				/**
19346				 * When resizing is finished, we adjust the slides sizes and positions
19347				 */
19348				function reBuild(resizing){
19349						if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
19350
19351						isResizing = true;
19352
19353						windowsHeight = $window.height();  //updating global var
19354
19355						$(SECTION_SEL).each(function(){
19356								var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
19357								var slides = $(this).find(SLIDE_SEL);
19358
19359								//adjusting the height of the table-cell for IE and Firefox
19360								if(options.verticalCentered){
19361										$(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
19362								}
19363
19364								$(this).css('height', windowsHeight + 'px');
19365
19366								//resizing the scrolling divs
19367								if(options.scrollOverflow){
19368										if(slides.length){
19369												slides.each(function(){
19370														createScrollBar($(this));
19371												});
19372										}else{
19373												createScrollBar($(this));
19374										}
19375								}
19376
19377								//adjusting the position fo the FULL WIDTH slides...
19378								if (slides.length > 1) {
19379										landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
19380								}
19381						});
19382
19383						var activeSection = $(SECTION_ACTIVE_SEL);
19384						var sectionIndex = activeSection.index(SECTION_SEL);
19385
19386						//isn't it the first section?
19387						if(sectionIndex){
19388								//adjusting the position for the current section
19389								silentMoveTo(sectionIndex + 1);
19390						}
19391
19392						isResizing = false;
19393						$.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
19394						$.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
19395				}
19396
19397				/**
19398				* Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
19399				* are smaller than the set limit values.
19400				*/
19401				function setResponsive(active){
19402						var isResponsive = $body.hasClass(RESPONSIVE);
19403
19404						if(active){
19405								if(!isResponsive){
19406										setAutoScrolling(false, 'internal');
19407										setFitToSection(false, 'internal');
19408										$(SECTION_NAV_SEL).hide();
19409										$body.addClass(RESPONSIVE);
19410										$.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
19411								}
19412						}
19413						else if(isResponsive){
19414								setAutoScrolling(originals.autoScrolling, 'internal');
19415								setFitToSection(originals.autoScrolling, 'internal');
19416								$(SECTION_NAV_SEL).show();
19417								$body.removeClass(RESPONSIVE);
19418								$.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
19419						}
19420				}
19421
19422				if($(this).length){
19423						//public functions
19424						FP.setAutoScrolling = setAutoScrolling;
19425						FP.setRecordHistory = setRecordHistory;
19426						FP.setScrollingSpeed = setScrollingSpeed;
19427						FP.setFitToSection = setFitToSection;
19428						FP.setLockAnchors = setLockAnchors;
19429						FP.setMouseWheelScrolling = setMouseWheelScrolling;
19430						FP.setAllowScrolling = setAllowScrolling;
19431						FP.setKeyboardScrolling = setKeyboardScrolling;
19432						FP.moveSectionUp = moveSectionUp;
19433						FP.moveSectionDown = moveSectionDown;
19434						FP.silentMoveTo = silentMoveTo;
19435						FP.moveTo = moveTo;
19436						FP.moveSlideRight = moveSlideRight;
19437						FP.moveSlideLeft = moveSlideLeft;
19438						FP.fitToSection = fitToSection;
19439						FP.reBuild = reBuild;
19440						FP.setResponsive = setResponsive;
19441						FP.destroy = destroy;
19442
19443						init();
19444
19445						bindEvents();
19446				}
19447
19448				function init(){
19449						//if css3 is not supported, it will use jQuery animations
19450						if(options.css3){
19451								options.css3 = support3d();
19452						}
19453
19454						options.scrollBar = options.scrollBar || options.hybrid;
19455
19456						setOptionsFromDOM();
19457						prepareDom();
19458						setAllowScrolling(true);
19459						setAutoScrolling(options.autoScrolling, 'internal');
19460						responsive();
19461
19462						//setting the class for the body element
19463						setBodyClass();
19464
19465						//Uncode addition
19466						// if(document.readyState === 'complete'){
19467						//     scrollToAnchor();
19468						// }
19469						// $window.on('load', scrollToAnchor);
19470				}
19471
19472				function bindEvents(){
19473						$window
19474								//when scrolling...
19475								//.on('scroll', scrollHandler)
19476
19477								//detecting any change on the URL to scroll to the given anchor link
19478								//(a way to detect back history button as we play with the hashes on the URL)
19479								.on('hashchange', hashChangeHandler)
19480
19481								//when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
19482								.blur(blurHandler)
19483
19484								//when resizing the site, we adjust the heights of the sections, slimScroll...
19485								.resize(resizeHandler);
19486
19487						$document
19488								//Sliding with arrow keys, both, vertical and horizontal
19489								.keydown(keydownHandler)
19490
19491								//to prevent scrolling while zooming
19492								.keyup(keyUpHandler)
19493
19494								//Scrolls to the section when clicking the navigation bullet
19495								.on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
19496
19497								//Scrolls the slider to the given slide destination for the given section
19498								.on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
19499
19500								.on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
19501
19502						//Scrolling horizontally when clicking on the slider controls.
19503						$(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
19504
19505						/**
19506						* Applying normalScroll elements.
19507						* Ignoring the scrolls over the specified selectors.
19508						*/
19509						if(options.normalScrollElements){
19510								$document.on('mouseenter', options.normalScrollElements, function () {
19511										setMouseWheelScrolling(false);
19512								});
19513
19514								$document.on('mouseleave', options.normalScrollElements, function(){
19515										setMouseWheelScrolling(true);
19516								});
19517						}
19518				}
19519
19520				/**
19521				* Setting options from DOM elements if they are not provided.
19522				*/
19523				function setOptionsFromDOM(){
19524						var sections = container.find(options.sectionSelector);
19525
19526						//no anchors option? Checking for them in the DOM attributes
19527						if(!options.anchors.length){
19528								options.anchors = sections.filter('[data-anchor]').map(function(){
19529										return $(this).data('anchor').toString();
19530								}).get();
19531						}
19532
19533						//no tooltips option? Checking for them in the DOM attributes
19534						if(!options.navigationTooltips.length){
19535								options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
19536										return $(this).data('tooltip').toString();
19537								}).get();
19538						}
19539				}
19540
19541				/**
19542				* Works over the DOM structure to set it up for the current fullpage options.
19543				*/
19544				function prepareDom(){
19545						container.css({
19546								'height': '100%',
19547								'position': 'relative'
19548						});
19549
19550						//adding a class to recognize the container internally in the code
19551						container.addClass(WRAPPER);
19552						$('html').addClass(ENABLED);
19553
19554						windowsHeight = $window.height();
19555
19556						container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
19557
19558						addInternalSelectors();
19559
19560						 //styling the sections / slides / menu
19561						$(SECTION_SEL).each(function(index){
19562								var section = $(this);
19563								var slides = section.find(SLIDE_SEL);
19564								var numSlides = slides.length;
19565
19566								styleSection(section, index);
19567								styleMenu(section, index);
19568
19569								// if there's any slide
19570								if (numSlides > 0) {
19571										styleSlides(section, slides, numSlides);
19572								}else{
19573										if(options.verticalCentered){
19574												addTableClass(section);
19575										}
19576								}
19577						});
19578
19579						//fixed elements need to be moved out of the plugin container due to problems with CSS3.
19580						if(options.fixedElements && options.css3){
19581								$(options.fixedElements).appendTo($body);
19582						}
19583
19584						//vertical centered of the navigation + active bullet
19585						if(options.navigation){
19586								addVerticalNavigation();
19587						}
19588
19589						enableYoutubeAPI();
19590
19591						if(options.scrollOverflow){
19592								if(document.readyState === 'complete'){
19593										createScrollBarHandler();
19594								}
19595								//after DOM and images are loaded
19596								$window.on('load', createScrollBarHandler);
19597						}else{
19598								afterRenderActions();
19599						}
19600				}
19601
19602				/**
19603				* Styles the horizontal slides for a section.
19604				*/
19605				function styleSlides(section, slides, numSlides){
19606						var sliderWidth = numSlides * 100;
19607						var slideWidth = 100 / numSlides;
19608
19609						slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
19610						slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
19611
19612						section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
19613
19614						if(numSlides > 1){
19615								if(options.controlArrows){
19616										createSlideArrows(section);
19617								}
19618
19619								if(options.slidesNavigation){
19620										addSlidesNavigation(section, numSlides);
19621								}
19622						}
19623
19624						slides.each(function(index) {
19625								$(this).css('width', slideWidth + '%');
19626
19627								if(options.verticalCentered){
19628										addTableClass($(this));
19629								}
19630						});
19631
19632						var startingSlide = section.find(SLIDE_ACTIVE_SEL);
19633
19634						//if the slide won't be an starting point, the default will be the first one
19635						//the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
19635ide by default.
19636						if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
19637								silentLandscapeScroll(startingSlide, 'internal');
19638						}else{
19639								slides.eq(0).addClass(ACTIVE);
19640						}
19641				}
19642
19643				/**
19644				* Styling vertical sections
19645				*/
19646				function styleSection(section, index){
19647						//if no active section is defined, the 1st one will be the default one
19648						if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
19649								section.addClass(ACTIVE);
19650						}
19651						startingSection = $(SECTION_ACTIVE_SEL);
19652
19653						section.css('height', windowsHeight + 'px');
19654
19655						if(options.paddingTop){
19656								section.css('padding-top', options.paddingTop);
19657						}
19658
19659						if(options.paddingBottom){
19660								section.css('padding-bottom', options.paddingBottom);
19661						}
19662
19663						if (typeof options.sectionsColor[index] !==  'undefined') {
19664								section.css('background-color', options.sectionsColor[index]);
19665						}
19666
19667						if (typeof options.anchors[index] !== 'undefined') {
19668								section.attr('data-anchor', options.anchors[index]);
19669						}
19670				}
19671
19672				/**
19673				* Sets the data-anchor attributes to the menu elements and activates the current one.
19674				*/
19675				function styleMenu(section, index){
19676						if (typeof options.anchors[index] !== 'undefined') {
19677								//activating the menu / nav element on load
19678								if(section.hasClass(ACTIVE)){
19679										activateMenuAndNav(options.anchors[index], index);
19680								}
19681						}
19682
19683						//moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
19684						if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
19685								$(options.menu).appendTo($body);
19686						}
19687				}
19688
19689				/**
19690				* Adds internal classes to be able to provide customizable selectors
19691				* keeping the link with the style sheet.
19692				*/
19693				function addInternalSelectors(){
19694						container.find(options.sectionSelector).addClass(SECTION);
19695						container.find(options.slideSelector).addClass(SLIDE);
19696				}
19697
19698				/**
19699				* Creates the control arrows for the given section
19700				*/
19701				function createSlideArrows(section){
19702						section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
19703
19704						if(options.controlArrowColor!='#fff'){
19705								section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
19706								section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
19707						}
19708
19709						if(!options.loopHorizontal){
19710								section.find(SLIDES_ARROW_PREV_SEL).hide();
19711						}
19712				}
19713
19714				/**
19715				* Creates a vertical navigation bar.
19716				*/
19717				function addVerticalNavigation(){
19718						$body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
19719						var nav = $(SECTION_NAV_SEL);
19720
19721						nav.addClass(function() {
19722								return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
19723						});
19724
19725						for (var i = 0; i < $(SECTION_SEL).length; i++) {
19726								var link = '';
19727								if (options.anchors.length) {
19728										link = options.anchors[i];
19729								}
19730
19731								var li = '<li><a href="#' + link + '"><span></span></a>';
19732
19733								// Only add tooltip if needed (defined by user)
19734								var tooltip = options.navigationTooltips[i];
19735
19736								if (typeof tooltip !== 'undefined' && tooltip !== '') {
19737										li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
19738								}
19739
19740								li += '</li>';
19741
19742								nav.find('ul').append(li);
19743						}
19744
19745						//centering it vertically
19746						$(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
19747
19748						//activating the current active section
19749						$(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
19750				}
19751
19752				/**
19753				* Creates the slim scroll scrollbar for the sections and slides inside them.
19754				*/
19755				function createScrollBarHandler(){
19756						$(SECTION_SEL).each(function(){
19757								var slides = $(this).find(SLIDE_SEL);
19758
19759								if(slides.length){
19760										slides.each(function(){
19761												createScrollBar($(this));
19762										});
19763								}else{
19764										createScrollBar($(this));
19765								}
19766
19767						});
19768						afterRenderActions();
19769				}
19770
19771				/*
19772				* Enables the Youtube videos API so we can control their flow if necessary.
19773				*/
19774				function enableYoutubeAPI(){
19775						container.find('iframe[src*="youtube.com/embed/"]').each(function(){
19776								addURLParam($(this), 'enablejsapi=1');
19777						});
19778				}
19779
19780				/**
19781				* Adds a new parameter and its value to the `src` of a given element
19782				*/
19783				function addURLParam(element, newParam){
19784						var originalSrc = element.attr('src');
19785						element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
19786				}
19787
19788				/*
19789				* Returns the prefix sign to use for a new parameter in an existen URL.
19790				*
19791				* @return {String}  ? | &
19792				*/
19793				function getUrlParamSign(url){
19794						return ( !/\?/.test( url ) ) ? '?' : '&';
19795				}
19796
19797				/**
19798				* Actions and callbacks to fire afterRender
19799				*/
19800				function afterRenderActions(){
19801						var section = $(SECTION_ACTIVE_SEL);
19802
19803						section.addClass(COMPLETELY);
19804
19805						if(options.scrollOverflowHandler.afterRender){
19806								options.scrollOverflowHandler.afterRender(section);
19807						}
19808						lazyLoad(section);
19809						playMedia(section);
19810						options.scrollOverflowHandler.afterLoad();
19811
19812						if(isDestinyTheStartingSection()){
19813								$.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
19814						}
19815
19816						$.isFunction( options.afterRender ) && options.afterRender.call(container);
19817				}
19818
19819				/**
19820				* Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
19821				*/
19822				function isDestinyTheStartingSection(){
19823						var anchors =  window.location.hash.replace('#', '').split('/');
19824						var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
19825
19826						return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
19827				}
19828
19829
19830				var isScrolling = false;
19831				var lastScroll = 0;
19832
19833				//when scrolling...
19834				function scrollHandler(){
19835						var currentSection;
19836
19837						if(!options.autoScrolling || options.scrollBar){
19838								var currentScroll = $window.scrollTop();
19839								var scrollDirection = getScrollDirection(currentScroll);
19840								var visibleSectionIndex = 0;
19841								var screen_mid = currentScroll + ($window.height() / 2.0);
19842								var isAtBottom = $body.height() - $window.height() === currentScroll;
19843								var sections =  document.querySelectorAll(SECTION_SEL);
19844
19845								//when using `auto-height` for a small last section it won't be centered in the viewport
19846								if(isAtBottom){
19847										visibleSectionIndex = sections.length - 1;
19848								}
19849								//is at top? when using `auto-height` for a small first section it won't be centered in the viewport
19850								else if(!currentScroll){
19851										visibleSectionIndex = 0;
19852								}
19853
19854								//taking the section which is showing more content in the viewport
19855								else{
19856										for (var i = 0; i < sections.length; ++i) {
19857												var section = sections[i];
19858
19859												// Pick the the last section which passes the middle line of the screen.
19860												if (section.offsetTop <= screen_mid)
19861												{
19862														visibleSectionIndex = i;
19863												}
19864										}
19865								}
19866
19867								if(isCompletelyInViewPort(scrollDirection)){
19868										if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
19869												$(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
19870										}
19871								}
19872
19873								//geting the last one, the current one on the screen
19874								currentSection = $(sections).eq(visibleSectionIndex);
19875
19876								//setting the visible section as active when manually scrolling
19877								//executing only once the first time we reach the section
19878								if(!currentSection.hasClass(ACTIVE)){
19879										isScrolling = true;
19880										var leavingSection = $(SECTION_ACTIVE_SEL);
19881										var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
19882										var yMovement = getYmovement(currentSection);
19883										var anchorLink  = currentSection.data('anchor');
19884										var sectionIndex = currentSection.index(SECTION_SEL) + 1;
19885										var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
19886										var slideIndex;
19887										var slideAnchorLink;
19888
19889										if(activeSlide.length){
19890												slideAnchorLink = activeSlide.data('anchor');
19891												slideIndex = activeSlide.index();
19892										}
19893
19894										if(canScroll){
19895												currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
19896
19897												$.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
19898												$.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
19899
19900												stopMedia(leavingSection);
19901												lazyLoad(currentSection);
19902												playMedia(currentSection);
19903
19904												activateMenuAndNav(anchorLink, sectionIndex - 1);
19905
19906												if(options.anchors.length){
19907														//needed to enter in hashChange event when using the menu with anchor links
19908														lastScrolledDestiny = anchorLink;
19909												}
19910												setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
19911										}
19912
19913										//small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
19914										clearTimeout(scrollId);
19915										scrollId = setTimeout(function(){
19916												isScrolling = false;
19917										}, 100);
19918								}
19919
19920								if(options.fitToSection){
19921										//for the auto adjust of the viewport to fit a whole section
19922										clearTimeout(scrollId2);
19923
19924										scrollId2 = setTimeout(function(){
19925												//checking it again in case it changed during the delay
19926												if(options.fitToSection){
19927														fitToSection();
19928												}
19929										}, options.fitToSectionDelay);
19930								}
19931						}
19932				}
19933
19934				/**
19935				* Fits the site to the nearest active section
19936				*/
19937				function fitToSection(){
19938						//checking fitToSection again in case it was set to false before the timeout delay
19939						if(canScroll){
19940								//allows to scroll to an active section and
19941								//if the section is already active, we prevent firing callbacks
19942								isResizing = true;
19943
19944								scrollPage($(SECTION_ACTIVE_SEL));
19945								isResizing = false;
19946						}
19947				}
19948
19949				/**
19950				* Determines whether the active section has seen in its whole or not.
19951				*/
19952				function isCompletelyInViewPort(movement){
19953						var top = $(SECTION_ACTIVE_SEL).position().top;
19954						var bottom = top + $window.height();
19955
19956						if(movement == 'up'){
19957								return bottom >= ($window.scrollTop() + $window.height());
19958						}
19959						return top <= $window.scrollTop();
19960				}
19961
19962				/**
19963				* Gets the directon of the the scrolling fired by the scroll event.
19964				*/
19965				function getScrollDirection(currentScroll){
19966						var direction = currentScroll > lastScroll ? 'down' : 'up';
19967
19968						lastScroll = currentScroll;
19969
19970						//needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
19971						previousDestTop = currentScroll;
19972
19973						return direction;
19974				}
19975
19976				/**
19977				* Determines the way of scrolling up or down:
19978				* by 'automatically' scrolling a section or by using the default and normal scrolling.
19979				*/
19980				function scrolling(type, scrollable){
19981						if (!isScrollAllowed.m[type]){
19982								return;
19983						}
19984						var check = (type === 'down') ? 'bottom' : 'top';
19985						var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
19986
19987						if(scrollable.length > 0 ){
19988								//is the scrollbar at the start/end of the scroll?
19989								if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
19990										scrollSection();
19991								}else{
19992										return true;
19993								}
19994						}else{
19995								// moved up/down
19996								scrollSection();
19997						}
19998				}
19999
20000				/*
20001				* Preventing bouncing in iOS #2285
20002				*/
20003				function preventBouncing(event){
20004						var e = event.originalEvent;
20005						if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e)){
20006								//preventing the easing on iOS devices
20007								event.preventDefault();
20008						}
20009				}
20010
20011				var touchStartY = 0;
20012				var touchStartX = 0;
20013				var touchEndY = 0;
20014				var touchEndX = 0;
20015
20016				/* Detecting touch events
20017
20018				* As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
20019				* This way, the touchstart and the touch moves shows an small difference between them which is the
20020				* used one to determine the direction.
20021				*/
20022				function touchMoveHandler(event){
20023						var e = event.originalEvent;
20024						var activeSection = $(e.target).closest(SECTION_SEL);
20025
20026						// additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
20027						if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
20028
20029								if(options.autoScrolling){
20030										//preventing the easing on iOS devices
20031										event.preventDefault();
20032								}
20033
20034								var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
20035								var touchEvents = getEventsPage(e);
20036
20037								touchEndY = touchEvents.y;
20038								touchEndX = touchEvents.x;
20039
20040								//if movement in the X axys is greater than in the Y and the currect section has slides...
20041								if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
20042
20043										//is the movement greater than the minimum resistance to scroll?
20044										if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
20045												if (touchStartX > touchEndX) {
20046														if(isScrollAllowed.m.right){
20047																moveSlideRight(activeSection); //next
20048														}
20049												} else {
20050														if(isScrollAllowed.m.left){
20051																moveSlideLeft(activeSection); //prev
20052														}
20053												}
20054										}
20055								}
20056
20057								//vertical scrolling (only when autoScrolling is enabled)
20058								else if(options.autoScrolling && canScroll){
20059
20060										//is the movement greater than the minimum resistance to scroll?
20061										if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
20062												if (touchStartY > touchEndY) {
20063														scrolling('down', scrollable);
20064												} else if (touchEndY > touchStartY) {
20065														scrolling('up', scrollable);
20066												}
20067										}
20068								}
20069						}
20070				}
20071
20072				/**
20073				 * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
20074				 * Currently works well for iOS - Android might need some testing
20075				 * @param  {Element} el  target element / jquery selector (in subsequent nodes)
20076				 * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
20077				 * @return {boolean} true if there is a match to options.normalScrollElements
20078				 */
20079				function checkParentForNormalScrollElement (el, hop) {
20080						hop = hop || 0;
20081						var parent = $(el).parent();
20082
20083						if (hop < options.normalScrollElementTouchThreshold &&
20084								parent.is(options.normalScrollElements) ) {
20085								return true;
20086						} else if (hop == options.normalScrollElementTouchThreshold) {
20087								return false;
20088						} else {
20089								return checkParentForNormalScrollElement(parent, ++hop);
20090						}
20091				}
20092
20093				/**
20094				* As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
20095				* this way we make sure that is really a touch event what IE is detecting.
20096				*/
20097				function isReallyTouch(e){
20098						//if is not IE   ||  IE is detecting `touch` or `pen`
20099						return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
20100				}
20101
20102				/**
20103				* Handler for the touch start event.
20104				*/
20105				function touchStartHandler(event){
20106						var e = event.originalEvent;
20107
20108						//stopping the auto scroll to adjust to a section
20109						if(options.fitToSection){
20110								$htmlBody.stop();
20111						}
20112
20113						if(isReallyTouch(e)){
20114								var touchEvents = getEventsPage(e);
20115								touchStartY = touchEvents.y;
20116								touchStartX = touchEvents.x;
20117						}
20118				}
20119
20120				/**
20121				* Gets the average of the last `number` elements of the given array.
20122				*/
20123				function getAverage(elements, number){
20124						var sum = 0;
20125
20126						//taking `number` elements from the end to make the average, if there are not enought, 1
20127						var lastElements = elements.slice(Math.max(elements.length - number, 1));
20128
20129						for(var i = 0; i < lastElements.length; i++){
20130								sum = sum + lastElements[i];
20131						}
20132
20133						return Math.ceil(sum/number);
20134				}
20135
20136				/**
20137				 * Detecting mousewheel scrolling
20138				 *
20139				 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
20140				 * http://www.sitepoint.com/html5-javascript-mouse-wheel/
20141				 */
20142				var prevTime = new Date().getTime();
20143
20144				function MouseWheelHandler(e) {
20145						var curTime = new Date().getTime();
20146						var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
20147
20148						//autoscrolling and not zooming?
20149						if(options.autoScrolling && !controlPressed && !isNormalScroll){
20150								// cross-browser wheel delta
20151								e = e || window.event;
20152								var value = e.wheelDelta || -e.deltaY || -e.detail;
20153								var delta = Math.max(-1, Math.min(1, value));
20154
20155								var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
20156								var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
20157
20158								//Limiting the array to 150 (lets not waste memory!)
20159								if(scrollings.length > 149){
20160										scrollings.shift();
20161								}
20162
20163								//keeping record of the previous scrollings
20164								scrollings.push(Math.abs(value));
20165
20166								//preventing to scroll the site on mouse wheel when scrollbar is present
20167								if(options.scrollBar){
20168										e.preventDefault ? e.preventDefault() : e.returnValue = false;
20169								}
20170
20171								var activeSection = $(SECTION_ACTIVE_SEL);
20172								var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
20173
20174								//time difference between the last scroll and the current one
20175								var timeDiff = curTime-prevTime;
20176								prevTime = curTime;
20177
20178								//haven't they scrolled in a while?
20179								//(enough to be consider a different scrolling action to scroll another section)
20180								if(timeDiff > 200){
20181										//emptying the array, we dont care about old scrollings for our averages
20182										scrollings = [];
20183								}
20184
20185								if(canScroll){
20186										var averageEnd = getAverage(scrollings, 10);
20187										var averageMiddle = getAverage(scrollings, 70);
20188										var isAccelerating = averageEnd >= averageMiddle;
20189
20190										//to avoid double swipes...
20191										if(isAccelerating && isScrollingVertically){
20192												//scrolling down?
20193												if (delta < 0) {
20194														scrolling('down', scrollable);
20195
20196												//scrolling up?
20197												}else {
20198														scrolling('up', scrollable);
20199												}
20200										}
20201								}
20202
20203								return false;
20204						}
20205
20206						if(options.fitToSection){
20207								//stopping the auto scroll to adjust to a section
20208								$htmlBody.stop();
20209						}
20210				}
20211
20212				/**
20213				* Slides a slider to the given direction.
20214				* Optional `section` param.
20215				*/
20216				function moveSlide(direction, section){
20217						var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
20218						var slides = activeSection.find(SLIDES_WRAPPER_SEL);
20219						var numSlides = slides.find(SLIDE_SEL).length;
20220
20221						// more than one slide needed and nothing should be sliding
20222						if (!slides.length || slideMoving || numSlides < 2) {
20223								return;
20224						}
20225
20226						var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
20227						var destiny = null;
20228
20229						if(direction === 'left'){
20230								destiny = currentSlide.prev(SLIDE_SEL);
20231						}else{
20232								destiny = currentSlide.next(SLIDE_SEL);
20233						}
20234
20235						//isn't there a next slide in the secuence?
20236						if(!destiny.length){
20237								//respect loopHorizontal settin
20238								if (!options.loopHorizontal) return;
20239
20240								if(direction === 'left'){
20241										destiny = currentSlide.siblings(':last');
20242								}else{
20243										destiny = currentSlide.siblings(':first');
20244								}
20245						}
20246
20247						slideMoving = true;
20248
20249						landscapeScroll(slides, destiny, direction);
20250				}
20251
20252				/**
20253				* Maintains the active slides in the viewport
20254				* (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
20255				*/
20256				function keepSlidesPosition(){
20257						$(SLIDE_ACTIVE_SEL).each(function(){
20258								silentLandscapeScroll($(this), 'internal');
20259						});
20260				}
20261
20262				var previousDestTop = 0;
20263				/**
20264				* Returns the destination Y position based on the scrolling direction and
20265				* the height of the section.
20266				*/
20267				function getDestinationPosition(element){
20268						var elemPosition = element.position();
20269
20270						//top of the desination will be at the top of the viewport
20271						var position = elemPosition.top;
20272						var isScrollingDown =  elemPosition.top > previousDestTop;
20273						var sectionBottom = position - windowsHeight + element.outerHeight();
20274						var bigSectionsDestination = options.bigSectionsDestination;
20275
20276						//Uncode addition
20277						var containerH = container.outerHeight();
20278						var containerPosition = container.offset();
20279
20280						//########### Commented by Uncode - START ###########
20281						//is the destination element bigger than the viewport?
20282						// if(element.outerHeight() > windowsHeight){
20283						//     //scrolling up?
20284						//     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
20285						//         position = sectionBottom;
20286						//     }
20287						// }
20288
20289						// //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
20290						// else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
20291						//     //The bottom of the destination will be at the bottom of the viewport
20292						//     position = sectionBottom;
20293						// }
20294						//########### Commented by Uncode - END ###########
20295
20296						//Uncode addition
20297						if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
20298								position += 18;
20299						if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
20300								position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
20301						}
20302
20303						/*
20304						Keeping record of the last scrolled position to determine the scrolling direction.
20305						No conventional methods can be used as the scroll bar might not be present
20306						AND the section might not be active if it is auto-height and didnt reach the middle
20307						of the viewport.
20308						*/
20309						previousDestTop = position;
20310						return position;
20311				}
20312
20313				/**
20314				* Scrolls the site to the given element and scrolls to the slide if a callback is given.
20315				*/
20316				function scrollPage(element, callback, isMovementUp){
20317						if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
20318
20319						var dtop = getDestinationPosition(element);
20320						var slideAnchorLink;
20321						var slideIndex;
20322
20323						//local variables
20324						var v = {
20325								element: element,
20326								callback: callback,
20327								isMovementUp: isMovementUp,
20328								dtop: dtop,
20329								yMovement: getYmovement(element),
20330								anchorLink: element.data('anchor'),
20331								sectionIndex: element.index(SECTION_SEL),
20332								activeSlide: element.find(SLIDE_ACTIVE_SEL),
20333								activeSection: $(SECTION_ACTIVE_SEL),
20334								leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
20335
20336								//caching the value of isResizing at the momment the function is called
20337								//because it will be checked later inside a setTimeout and the value might change
20338								localIsResizing: isResizing
20339						};
20340
20341						//quiting when destination scroll is the same as the current one
20342						if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
20343
20344						if(v.activeSlide.length){
20345								slideAnchorLink = v.activeSlide.data('anchor');
20346								slideIndex = v.activeSlide.index();
20347						}
20348
20349						// If continuousVertical && we need to wrap around
20350						if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
20351								((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
20352								(v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
20353
20354								v = createInfiniteSections(v);
20355						}
20356
20357						//callback (onLeave) if the site is not just resizing and readjusting the slides
20358						if($.isFunction(options.onLeave) && !v.localIsResizing){
20359								if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
20360										return;
20361								}
20362						}
20363
20364						//pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
20365						if(!v.localIsResizing){
20366								stopMedia(v.activeSection);
20367						}
20368
20369						options.scrollOverflowHandler.beforeLeave();
20370						element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
20371						lazyLoad(element);
20372						options.scrollOverflowHandler.onLeave();
20373
20374
20375						//preventing from activating the MouseWheelHandler event
20376						//more than once if the page is scrolling
20377						canScroll = false;
20378
20379						setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
20380
20381						performMovement(v);
20382
20383						//flag to avoid callingn `scrollPage()` twice in case of using anchor links
20384						lastScrolledDestiny = v.anchorLink;
20385
20386						//avoid firing it twice (as it does also on scroll)
20387						activateMenuAndNav(v.anchorLink, v.sectionIndex);
20388				}
20389
20390				/**
20391				* Performs the vertical movement (by CSS3 or by jQuery)
20392				*/
20393				function performMovement(v){
20394						// using CSS3 translate functionality
20395						if (options.css3 && options.autoScrolling && !options.scrollBar) {
20396
20397								// The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
20398								// that's why we round it to 0.
20399								var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
20400								transformContainer(translate3d, true);
20401
20402								//even when the scrollingSpeed is 0 there's a little delay, which might cause the
20403								//scrollingSpeed to change in case of using silentMoveTo();
20404								if(options.scrollingSpeed){
20405										clearTimeout(afterSectionLoadsId);
20406										afterSectionLoadsId = setTimeout(function () {
20407												afterSectionLoads(v);
20408										}, options.scrollingSpeed);
20409								}else{
20410										afterSectionLoads(v);
20411								}
20412						}
20413
20414						// using jQuery animate
20415						else{
20416								var scrollSettings = getScrollSettings(v);
20417
20418								$(scrollSettings.element).animate(
20419										scrollSettings.options,
20420								options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
20421										if(options.scrollBar){
20422
20423												/* Hack!
20424												The timeout prevents setting the most dominant section in the viewport as "active" when the user
20425												scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
20426
20427												When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
20428												*/
20429												setTimeout(function(){
20430														afterSectionLoads(v);
20431												},30);
20432										}else{
20433												afterSectionLoads(v);
20434										}
20435								});
20436						}
20437				}
20438
20439				/**
20440				* Gets the scrolling settings depending on the plugin autoScrolling option
20441				*/
20442				function getScrollSettings(v){
20443						var scroll = {};
20444
20445						if(options.autoScrolling && !options.scrollBar){
20446								scroll.options = { 'top': -v.dtop};
20447								scroll.element = WRAPPER_SEL;
20448						}else{
20449								scroll.options = { 'scrollTop': v.dtop};
20450								scroll.element = 'html, body';
20451						}
20452
20453						return scroll;
20454				}
20455
20456				/**
20457				* Adds sections before or after the current one to create the infinite effect.
20458				*/
20459				function createInfiniteSections(v){
20460						// Scrolling down
20461						if (!v.isMovementUp) {
20462								// Move all previous sections to after the active section
20463								$(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
20464						}
20465						else { // Scrolling up
20466								// Move all next sections to before the active section
20467								$(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
20468						}
20469
20470						// Maintain the displayed position (now that we changed the element order)
20471						silentScroll($(SECTION_ACTIVE_SEL).position().top);
20472
20473						// Maintain the active slides visible in the viewport
20474						keepSlidesPosition();
20475
20476						// save for later the elements that still need to be reordered
20477						v.wrapAroundElements = v.activeSection;
20478
20479						// Recalculate animation variables
20480						v.dtop = v.element.position().top;
20481						v.yMovement = getYmovement(v.element);
20482
20483						return v;
20484				}
20485
20486				/**
20487				* Fix section order after continuousVertical changes have been animated
20488				*/
20489				function continuousVerticalFixSectionOrder (v) {
20490						// If continuousVertical is in effect (and autoScrolling would also be in effect then),
20491						// finish moving the elements around so the direct navigation will function more simply
20492						if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
20493								return;
20494						}
20495
20496						if (v.isMovementUp) {
20497								$(SECTION_FIRST_SEL).before(v.wrapAroundElements);
20498						}
20499						else {
20500								$(SECTION_LAST_SEL).after(v.wrapAroundElements);
20501						}
20502
20503						silentScroll($(SECTION_ACTIVE_SEL).position().top);
20504
20505						// Maintain the active slides visible in the viewport
20506						keepSlidesPosition();
20507				}
20508
20509
20510				/**
20511				* Actions to do once the section is loaded.
20512				*/
20513				function afterSectionLoads (v){
20514						continuousVerticalFixSectionOrder(v);
20515
20516						//callback (afterLoad) if the site is not just resizing and readjusting the slides
20517						$.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
20518						options.scrollOverflowHandler.afterLoad();
20519
20520						if(!v.localIsResizing){
20521								playMedia(v.element);
20522						}
20523
20524						v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
20525
20526						canScroll = true;
20527
20528						$.isFunction(v.callback) && v.callback.call(this);
20529				}
20530
20531				/**
20532				* Sets the value for the given attribute from the `data-` attribute with the same suffix
20533				* ie: data-srcset ==> srcset  |  data-src ==> src
20534				*/
20535				function setSrc(element, attribute){
20536						element
20537								.attr(attribute, element.data(attribute))
20538								.removeAttr('data-' + attribute);
20539				}
20540
20541				/**
20542				* Lazy loads image, video and audio elements.
20543				*/
20544				function lazyLoad(destiny){
20545						if (!options.lazyLoading){
20546								return;
20547						}
20548
20549						var panel = getSlideOrSection(destiny);
20550						var element;
20551
20552						panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
20553								element = $(this);
20554
20555								$.each(['src', 'srcset'], function(index, type){
20556										var attribute = element.attr('data-' + type);
20557										if(typeof attribute !== 'undefined' && attribute){
20558												setSrc(element, type);
20559										}
20560								});
20561
20562								if(element.is('source')){
20563										element.closest('video').get(0).load();
20564								}
20565						});
20566				}
20567
20568				/**
20569				* Plays video and audio elements.
20570				*/
20571				function playMedia(destiny){
20572						var panel = getSlideOrSection(destiny);
20573
20574						//playing HTML5 media elements
20575						panel.find('video, audio').each(function(){
20576								var element = $(this).get(0);
20577
20578								if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
20579										element.play();
20580								}
20581						});
20582
20583						//youtube videos
20584						panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
20585								var element = $(this).get(0);
20586
20587								if ( element.hasAttribute('data-autoplay') ){
20588										playYoutube(element);
20589								}
20590
20591								//in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
20592								element.onload = function() {
20593										if ( element.hasAttribute('data-autoplay') ){
20594												playYoutube(element);
20595										}
20596								};
20597						});
20598				}
20599
20600				/**
20601				* Plays a youtube video
20602				*/
20603				function playYoutube(element){
20604						element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
20605				}
20606
20607				/**
20608				* Stops video and audio elements.
20609				*/
20610				function stopMedia(destiny){
20611						var panel = getSlideOrSection(destiny);
20612
20613						//stopping HTML5 media elements
20614						panel.find('video, audio').each(function(){
20615								var element = $(this).get(0);
20616
20617								if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
20618										element.pause();
20619								}
20620						});
20621
20622						//youtube videos
20623						panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
20624								var element = $(this).get(0);
20625
20626								if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
20627										$(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
20628								}
20629						});
20630				}
20631
20632				/**
20633				* Gets the active slide (or section) for the given section
20634				*/
20635				function getSlideOrSection(destiny){
20636						var slide = destiny.find(SLIDE_ACTIVE_SEL);
20637						if( slide.length ) {
20638								destiny = $(slide);
20639						}
20640
20641						return destiny;
20642				}
20643
20644				/**
20645				* Scrolls to the anchor in the URL when loading the site
20646				*/
20647				function scrollToAnchor(){
20648						//getting the anchor link in the URL and deleting the `#`
20649						var value =  window.location.hash.replace('#', '').split('/');
20650						var sectionAnchor = decodeURIComponent(value[0]);
20651						var slideAnchor = decodeURIComponent(value[1]);
20652
20653						if(sectionAnchor){  //if theres any #
20654								if(options.animateAnchor){
20655										scrollPageAndSlide(sectionAnchor, slideAnchor);
20656								}else{
20657										silentMoveTo(sectionAnchor, slideAnchor);
20658								}
20659						}
20660				}
20661
20662				/**
20663				* Detecting any change on the URL to scroll to the given anchor link
20664				* (a way to detect back history button as we play with the hashes on the URL)
20665				*/
20666				function hashChangeHandler(){
20667						if(!isScrolling && !options.lockAnchors){
20668								var value =  window.location.hash.replace('#', '').split('/');
20669								var sectionAnchor = decodeURIComponent(value[0]);
20670								var slideAnchor = decodeURIComponent(value[1]);
20671
20672										//when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
20673										var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
20674										var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
20675
20676
20677								if(sectionAnchor.length){
20678										/*in order to call scrollpage() only once for each destination at a time
20679										It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
20680										event is fired on every scroll too.*/
20681										if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
20682												scrollPageAndSlide(sectionAnchor, slideAnchor);
20683										}
20684								}
20685						}
20686				}
20687
20688				//Sliding with arrow keys, both, vertical and horizontal
20689				function keydownHandler(e) {
20690
20691						clearTimeout(keydownId);
20692
20693						var activeElement = $(':focus');
20694
20695						if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
20696								activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
20697								options.keyboardScrolling && options.autoScrolling){
20698								var keyCode = e.which;
20699
20700								//preventing the scroll with arrow keys & spacebar & Page Up & Down keys
20701								var keyControls = [40, 38, 32, 33, 34];
20702								if($.inArray(keyCode, keyControls) > -1){
20703										e.preventDefault();
20704								}
20705
20706								controlPressed = e.ctrlKey;
20707
20708								keydownId = setTimeout(function(){
20709										onkeydown(e);
20710								},150);
20711						}
20712				}
20713
20714				function tooltipTextHandler(){
20715						$(this).prev().trigger('click');
20716				}
20717
20718				//to prevent scrolling while zooming
20719				function keyUpHandler(e){
20720						if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
20721								controlPressed = e.ctrlKey;
20722						}
20723				}
20724
20725				//binding the mousemove when the mouse's middle button is released
20726				function mouseDownHandler(e){
20727						//middle button
20728						if (e.which == 2){
20729								oldPageY = e.pageY;
20730								container.on('mousemove', mouseMoveHandler);
20731						}
20732				}
20733
20734				//unbinding the mousemove when the mouse's middle button is released
20735				function mouseUpHandler(e){
20736						//middle button
20737						if (e.which == 2){
20738								container.off('mousemove');
20739						}
20740				}
20741
20742				//Scrolling horizontally when clicking on the slider controls.
20743				function slideArrowHandler(){
20744						var section = $(this).closest(SECTION_SEL);
20745
20746						if ($(this).hasClass(SLIDES_PREV)) {
20747								if(isScrollAllowed.m.left){
20748										moveSlideLeft(section);
20749								}
20750						} else {
20751								if(isScrollAllowed.m.right){
20752										moveSlideRight(section);
20753								}
20754						}
20755				}
20756
20757				//when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
20758				function blurHandler(){
20759						isWindowFocused = false;
20760						controlPressed = false;
20761				}
20762
20763				//Scrolls to the section when clicking the navigation bullet
20764				function sectionBulletHandler(e){
20765						e.preventDefault();
20766						var index = $(this).parent().index();
20767						scrollPage($(SECTION_SEL).eq(index));
20768				}
20769
20770				//Scrolls the slider to the given slide destination for the given section
20771				function slideBulletHandler(e){
20772						e.preventDefault();
20773						var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
20774						var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
20775
20776						landscapeScroll(slides, destiny);
20777				}
20778
20779				/**
20780				* Keydown event
20781				*/
20782				function onkeydown(e){
20783						var shiftPressed = e.shiftKey;
20784
20785						//do nothing if we can not scroll or we are not using horizotnal key arrows.
20786						if(!canScroll && [37,39].indexOf(e.which) < 0){
20787								return;
20788						}
20789
20790						switch (e.which) {
20791								//up
20792								case 38:
20793								case 33:
20794										if(isScrollAllowed.k.up){
20795												moveSectionUp();
20796										}
20797										break;
20798
20799								//down
20800								case 32: //spacebar
20801										if(shiftPressed && isScrollAllowed.k.up){
20802												moveSectionUp();
20803												break;
20804										}
20805								/* falls through */
20806								case 40:
20807								case 34:
20808										if(isScrollAllowed.k.down){
20809												moveSectionDown();
20810										}
20811										break;
20812
20813								//Home
20814								case 36:
20815										if(isScrollAllowed.k.up){
20816												moveTo(1);
20817										}
20818										break;
20819
20820								//End
20821								case 35:
20822										 if(isScrollAllowed.k.down){
20823												moveTo( $(SECTION_SEL).length );
20824										}
20825										break;
20826
20827								//left
20828								case 37:
20829										if(isScrollAllowed.k.left){
20830												moveSlideLeft();
20831										}
20832										break;
20833
20834								//right
20835								case 39:
20836										if(isScrollAllowed.k.right){
20837												moveSlideRight();
20838										}
20839										break;
20840
20841								default:
20842										return; // exit this handler for other keys
20843						}
20844				}
20845
20846				/**
20847				* Detecting the direction of the mouse movement.
20848				* Used only for the middle button of the mouse.
20849				*/
20850				var oldPageY = 0;
20851				function mouseMoveHandler(e){
20852						if(canScroll){
20853								// moving up
20854								if (e.pageY < oldPageY && isScrollAllowed.m.up){
20855										moveSectionUp();
20856								}
20857
20858								// moving down
20859								else if(e.pageY > oldPageY && isScrollAllowed.m.down){
20860										moveSectionDown();
20861								}
20862						}
20863						oldPageY = e.pageY;
20864				}
20865
20866				/**
20867				* Scrolls horizontal sliders.
20868				*/
20869				function landscapeScroll(slides, destiny, direction){
20870						var section = slides.closest(SECTION_SEL);
20871						var v = {
20872								slides: slides,
20873								destiny: destiny,
20874								direction: direction,
20875								destinyPos: destiny.position(),
20876								slideIndex: destiny.index(),
20877								section: section,
20878								sectionIndex: section.index(SECTION_SEL),
20879								anchorLink: section.data('anchor'),
20880								slidesNav: section.find(SLIDES_NAV_SEL),
20881								slideAnchor:  getAnchor(destiny),
20882								prevSlide: section.find(SLIDE_ACTIVE_SEL),
20883								prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
20884
20885								//caching the value of isResizing at the momment the function is called
20886								//because it will be checked later inside a setTimeout and the value might change
20887								localIsResizing: isResizing
20888						};
20889						v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
20890
20891						//important!! Only do it when not resizing
20892						if(!v.localIsResizing){
20893								//preventing from scrolling to the next/prev section when using scrollHorizontally
20894								canScroll = false;
20895						}
20896
20897						if(options.onSlideLeave){
20898
20899								//if the site is not just resizing and readjusting the slides
20900								if(!v.localIsResizing && v.xMovement!=='none'){
20901										if($.isFunction( options.onSlideLeave )){
20902												if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
20903														slideMoving = false;
20904														return;
20905												}
20906										}
20907								}
20908						}
20909
20910						destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
20911
20912						if(!v.localIsResizing){
20913								stopMedia(v.prevSlide);
20914								lazyLoad(destiny);
20915						}
20916
20917						if(!options.loopHorizontal && options.controlArrows){
20918								//hidding it for the fist slide, showing for the rest
20919								section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
20920
20921								//hidding it for the last slide, showing for the rest
20922								section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
20923						}
20924
20925						//only changing the URL if the slides are in the current section (not for resize re-adjusting)
20926						if(section.hasClass(ACTIVE) && !v.localIsResizing){
20927								setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
20928						}
20929
20930						performHorizontalMove(slides, v, true);
20931				}
20932
20933
20934				function afterSlideLoads(v){
20935						activeSlidesNavigation(v.slidesNav, v.slideIndex);
20936
20937						//if the site is not just resizing and readjusting the slides
20938						if(!v.localIsResizing){
20939								$.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
20940
20941								//needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
20942								//and to prevent double scroll right after a windows resize
20943								canScroll = true;
20944
20945								playMedia(v.destiny);
20946						}
20947
20948						//letting them slide again
20949						slideMoving = false;
20950				}
20951
20952				/**
20953				* Performs the horizontal movement. (CSS3 or jQuery)
20954				*
20955				* @param fireCallback {Bool} - determines whether or not to fire the callback
20956				*/
20957				function performHorizontalMove(slides, v, fireCallback){
20958						var destinyPos = v.destinyPos;
20959
20960						if(options.css3){
20961								var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
20962
20963								addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
20964
20965								afterSlideLoadsId = setTimeout(function(){
20966										fireCallback && afterSlideLoads(v);
20967								}, options.scrollingSpeed, options.easing);
20968						}else{
20969								slides.animate({
20970										scrollLeft : Math.round(destinyPos.left)
20971								}, options.scrollingSpeed, options.easing, function() {
20972
20973										fireCallback && afterSlideLoads(v);
20974								});
20975						}
20976				}
20977
20978				/**
20979				* Sets the state for the horizontal bullet navigations.
20980				*/
20981				function activeSlidesNavigation(slidesNav, slideIndex){
20982						slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
20983						slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
20984				}
20985
20986				var previousHeight = windowsHeight;
20987
20988				//when resizing the site, we adjust the heights of the sections, slimScroll...
20989				function resizeHandler(){
20990						//checking if it needs to get responsive
20991						responsive();
20992
20993						// rebuild immediately on touch devices
20994						if (isTouchDevice) {
20995								var activeElement = $(document.activeElement);
20996
20997								//if the keyboard is NOT visible
20998								if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
20999										var currentHeight = $window.height();
21000
21001										//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)
21002										if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
21003												reBuild(true);
21004												previousHeight = currentHeight;
21005										}
21006								}
21007						}else{
21008								//in order to call the functions only when the resize is finished
21009								//http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
21010								clearTimeout(resizeId);
21011
21012								resizeId = setTimeout(function(){
21013										reBuild(true);
21014								}, 350);
21015						}
21016				}
21017
21018				/**
21019				* Checks if the site needs to get responsive and disables autoScrolling if so.
21020				* A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
21021				*/
21022				function responsive(){
21023						var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
21024						var heightLimit = options.responsiveHeight;
21025
21026						//only calculating what we need. Remember its called on the resize event.
21027						var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
21028						var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
21029
21030						if(widthLimit && heightLimit){
21031								setResponsive(isBreakingPointWidth || isBreakingPointHeight);
21032						}
21033						else if(widthLimit){
21034								setResponsive(isBreakingPointWidth);
21035						}
21036						else if(heightLimit){
21037								setResponsive(isBreakingPointHeight);
21038						}
21039				}
21040
21041				/**
21042				* Adds transition animations for the given element
21043				*/
21044				function addAnimation(container, element){
21045						var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
21046
21047						container.removeClass(NO_TRANSITION);
21048						return container.css({
21049								'-webkit-transition': transition,
21050								'transition': transition
21051						});
21052				}
21053
21054				/**
21055				* Remove transition animations for the given element
21056				*/
21057				function removeAnimation(element){
21058						return element.addClass(NO_TRANSITION);
21059				}
21060
21061				/**
21062				* Activating the vertical navigation bullets according to the given slide name.
21063				*/
21064				function activateNavDots(name, sectionIndex){
21065						if(options.navigation){
21066								$(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
21067								if(name){
21068										$(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
21069								}else{
21070										$(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
21071								}
21072						}
21073				}
21074
21075				/**
21076				* Activating the website main menu elements according to the given slide name.
21077				*/
21078				function activateMenuElement(name){
21079						if(options.menu){
21080								$(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
21081								$(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
21082						}
21083				}
21084
21085				/**
21086				* Sets to active the current menu and vertical nav items.
21087				*/
21088				function activateMenuAndNav(anchor, index){
21089						activateMenuElement(anchor);
21090						activateNavDots(anchor, index);
21091				}
21092
21093				/**
21094				* Retuns `up` or `down` depending on the scrolling movement to reach its destination
21095				* from the current section.
21096				*/
21097				function getYmovement(destiny){
21098						var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
21099						var toIndex = destiny.index(SECTION_SEL);
21100						if( fromIndex == toIndex){
21101								return 'none';
21102						}
21103						if(fromIndex > toIndex){
21104								return 'up';
21105						}
21106						return 'down';
21107				}
21108
21109				/**
21110				* Retuns `right` or `left` depending on the scrolling movement to reach its destination
21111				* from the current slide.
21112				*/
21113				function getXmovement(fromIndex, toIndex){
21114						if( fromIndex == toIndex){
21115								return 'none';
21116						}
21117						if(fromIndex > toIndex){
21118								return 'left';
21119						}
21120						return 'right';
21121				}
21122
21123				/**
21124				* Checks if the element needs scrollbar and if the user wants to apply it.
21125				* If so it creates it.
21126				*
21127				* @param {Object} element   jQuery object of the section or slide
21128				*/
21129				function createScrollBar(element){
21130						//User doesn't want scrollbar here? Sayonara baby!
21131						if(element.hasClass('fp-noscroll')) return;
21132
21133						//needed to make `scrollHeight` work under Opera 12
21134						element.css('overflow', 'hidden');
21135
21136						var scrollOverflowHandler = options.scrollOverflowHandler;
21137						var wrap = scrollOverflowHandler.wrapContent();
21138						//in case element is a slide
21139						var section = element.closest(SECTION_SEL);
21140						var scrollable = scrollOverflowHandler.scrollable(element);
21141						var contentHeight;
21142
21143						//if there was scroll, the contentHeight will be the one in the scrollable section
21144						if(scrollable.length){
21145								contentHeight = scrollOverflowHandler.scrollHeight(element);
21146						}else{
21147								contentHeight = element.get(0).scrollHeight;
21148								if(options.verticalCentered){
21149										contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
21150								}
21151						}
21152
21153						var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
21154						//Uncode addition
21155						scrollHeight -= UNCODE.bodyBorder*2 + UNCODE.adminBarHeight;
21156
21157						//needs scroll?
21158						if ( contentHeight > scrollHeight) {
21159								//did we already have an scrollbar ? Updating it
21160								if(scrollable.length){
21161										scrollOverflowHandler.update(element, scrollHeight);
21162								}
21163								//creating the scrolling
21164								else{
21165										if(options.verticalCentered){
21166												element.find(TABLE_CELL_SEL).wrapInner(wrap);
21167										}else{
21168												element.wrapInner(wrap);
21169										}
21170										scrollOverflowHandler.create(element, scrollHeight);
21171								}
21172						}
21173						//removing the scrolling when it is not necessary anymore
21174						else{
21175								scrollOverflowHandler.remove(element);
21176						}
21177
21178						//undo
21179						element.css('overflow', '');
21180				}
21181
21182				function addTableClass(element){
21183						//In case we are styling for the 2nd time as in with reponsiveSlides
21184						if(!element.hasClass(TABLE)){
21185								element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
21186						}
21187				}
21188
21189				function getTableHeight(element){
21190						var sectionHeight = windowsHeight;
21191
21192						if(options.paddingTop || options.paddingBottom){
21193								var section = element;
21194								if(!section.hasClass(SECTION)){
21195										section = element.closest(SECTION_SEL);
21196								}
21197
21198								var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
21199								sectionHeight = (windowsHeight - paddings);
21200						}
21201
21202						return sectionHeight;
21203				}
21204
21205				/**
21206				* Adds a css3 transform property to the container class with or without animation depending on the animated param.
21207				*/
21208				function transformContainer(translate3d, animated){
21209						if(animated){
21210								addAnimation(container);
21211						}else{
21212								removeAnimation(container);
21213						}
21214
21215						container.css(getTransforms(translate3d));
21216
21217						//syncronously removing the class after the animation has been applied.
21218						setTimeout(function(){
21219								container.removeClass(NO_TRANSITION);
21220						},10);
21221				}
21222
21223				/**
21224				* Gets a section by its anchor / index
21225				*/
21226				function getSectionByAnchor(sectionAnchor){
21227						if(!sectionAnchor) return [];
21228
21229						var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
21230						if(!section.length){
21231								section = $(SECTION_SEL).eq( sectionAnchor -1);
21232						}
21233
21234						return section;
21235				}
21236
21237				/**
21238				* Gets a slide inside a given section by its anchor / index
21239				*/
21240				function getSlideByAnchor(slideAnchor, section){
21241						var slides = section.find(SLIDES_WRAPPER_SEL);
21242						var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
21243
21244						if(!slide.length){
21245								slide = slides.find(SLIDE_SEL).eq(slideAnchor);
21246						}
21247
21248						return slide;
21249				}
21250
21251				/**
21252				* Scrolls to the given section and slide anchors
21253				*/
21254				function scrollPageAndSlide(destiny, slide){
21255						var section = getSectionByAnchor(destiny);
21256
21257						//do nothing if there's no section with the given anchor name
21258						if(!section.length) return;
21259
21260						//default slide
21261						if (typeof slide === 'undefined') {
21262								slide = 0;
21263						}
21264
21265						//we need to scroll to the section and then to the slide
21266						if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
21267								scrollPage(section, function(){
21268										scrollSlider(section, slide);
21269								});
21270						}
21271						//if we were already in the section
21272						else{
21273								scrollSlider(section, slide);
21274						}
21275				}
21276
21277				/**
21278				* Scrolls the slider to the given slide destination for the given section
21279				*/
21280				function scrollSlider(section, slideAnchor){
21281						if(typeof slideAnchor !== 'undefined'){
21282								var slides = section.find(SLIDES_WRAPPER_SEL);
21283								var destiny =  getSlideByAnchor(slideAnchor, section);
21284
21285								if(destiny.length){
21286										landscapeScroll(slides, destiny);
21287								}
21288						}
21289				}
21290
21291				/**
21292				* Creates a landscape navigation bar with dots for horizontal sliders.
21293				*/
21294				function addSlidesNavigation(section, numSlides){
21295						section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
21296						var nav = section.find(SLIDES_NAV_SEL);
21297
21298						//top or bottom
21299						nav.addClass(options.slidesNavPosition);
21300
21301						for(var i=0; i< numSlides; i++){
21302								nav.find('ul').append('<li><a href="#"><span></span></a></li>');
21303						}
21304
21305						//centering it
21306						nav.css('margin-left', '-' + (nav.width()/2) + 'px');
21307
21308						nav.find('li').first().find('a').addClass(ACTIVE);
21309				}
21310
21311
21312				/**
21313				* Sets the state of the website depending on the active section/slide.
21314				* It changes the URL hash when needed and updates the body class.
21315				*/
21316				function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
21317						var sectionHash = '';
21318
21319						if(options.anchors.length && !options.lockAnchors){
21320
21321								//isn't it the first slide?
21322								if(slideIndex){
21323										if(typeof anchorLink !== 'undefined'){
21324												sectionHash = anchorLink;
21325										}
21326
21327										//slide without anchor link? We take the index instead.
21328										if(typeof slideAnchor === 'undefined'){
21329												slideAnchor = slideIndex;
21330										}
21331
21332										lastScrolledSlide = slideAnchor;
21333										setUrlHash(sectionHash + '/' + slideAnchor);
21334
21335								//first slide won't have slide anchor, just the section one
21336								}else if(typeof slideIndex !== 'undefined'){
21337										lastScrolledSlide = slideAnchor;
21338										setUrlHash(anchorLink);
21339								}
21340
21341								//section without slides
21342								else{
21343										setUrlHash(anchorLink);
21344								}
21345						}
21346
21347						setBodyClass();
21348				}
21349
21350				/**
21351				* Sets the URL hash.
21352				*/
21353				function setUrlHash(url){
21354						//Uncode addition
21355						if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
21356								return false;
21357
21358						if(options.recordHistory){
21359								location.hash = url;
21360						}else{
21361								//Uncode addition
21362								//Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
21363								// if(isTouchDevice || isTouch){
21364								//     window.history.replaceState(undefined, undefined, '#' + url);
21365								// }else{
21366								//     var baseUrl = window.location.href.split('#')[0];
21367								//     window.location.replace( baseUrl + '#' + url );
21368								// }
21369								return false;
21370						}
21371				}
21372
21373				/**
21374				* Gets the anchor for the given slide / section. Its index will be used if there's none.
21375				*/
21376				function getAnchor(element){
21377						var anchor = element.data('anchor');
21378						var index = element.index();
21379
21380						//Slide without anchor link? We take the index instead.
21381						if(typeof anchor === 'undefined'){
21382								anchor = index;
21383						}
21384
21385						return anchor;
21386				}
21387
21388				/**
21389				* Sets a class for the body of the page depending on the active section / slide
21390				*/
21391				function setBodyClass(){
21392						var section = $(SECTION_ACTIVE_SEL);
21393						var slide = section.find(SLIDE_ACTIVE_SEL);
21394
21395						var sectionAnchor = getAnchor(section);
21396						var slideAnchor = getAnchor(slide);
21397
21398						var text = String(sectionAnchor);
21399
21400						if(slide.length){
21401								text = text + '-' + slideAnchor;
21402						}
21403
21404						//changing slash for dash to make it a valid CSS style
21405						text = text.replace('/', '-').replace('#','');
21406
21407						//removing previous anchor classes
21408						var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
21409						$body[0].className = $body[0].className.replace(classRe, '');
21410
21411						//adding the current anchor
21412						$body.addClass(VIEWING_PREFIX + '-' + text);
21413				}
21414
21415				/**
21416				* Checks for translate3d support
21417				* @return boolean
21418				* http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
21419				*/
21420				function support3d() {
21421						var el = document.createElement('p'),
21422								has3d,
21423								transforms = {
21424										'webkitTransform':'-webkit-transform',
21425										'OTransform':'-o-transform',
21426										'msTransform':'-ms-transform',
21427										'MozTransform':'-moz-transform',
21428										'transform':'transform'
21429								};
21430
21431						// Add it to the body to get the computed style.
21432						document.body.insertBefore(el, null);
21433
21434						for (var t in transforms) {
21435								if (el.style[t] !== undefined) {
21436										el.style[t] = 'translate3d(1px,1px,1px)';
21437										has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
21438								}
21439						}
21440
21441						document.body.removeChild(el);
21442
21443						return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
21444				}
21445
21446				/**
21447				* Removes the auto scrolling action fired by the mouse wheel and trackpad.
21448				* After this function is called, the mousewheel and trackpad movements won't scroll through sections.
21449				*/
21450				function removeMouseWheelHandler(){
21451						if (document.addEventListener) {
21452								document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
21453								document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
21454								document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
21455						} else {
21456								document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
21457						}
21458				}
21459
21460				/**
21461				* Adds the auto scrolling action for the mouse wheel and trackpad.
21462				* After this function is called, the mousewheel and trackpad movements will scroll through sections
21463				* https://developer.mozilla.org/en-US/docs/Web/Events/wheel
21464				*/
21465				function addMouseWheelHandler(){
21466						var prefix = '';
21467						var _addEventListener;
21468
21469						if (window.addEventListener){
21470								_addEventListener = "addEventListener";
21471						}else{
21472								_addEventListener = "attachEvent";
21473								prefix = 'on';
21474						}
21475
21476						 // detect available wheel event
21477						var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
21478											document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
21479											'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
21480
21481
21482						if(support == 'DOMMouseScroll'){
21483								document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false);
21484						}
21485
21486						//handle MozMousePixelScroll in older Firefox
21487						else{
21488								document[ _addEventListener ](prefix + support, MouseWheelHandler, false);
21489						}
21490				}
21491
21492				/**
21493				* Binding the mousemove when the mouse's middle button is pressed
21494				*/
21495				function addMiddleWheelHandler(){
21496						container
21497								.on('mousedown', mouseDownHandler)
21498								.on('mouseup', mouseUpHandler);
21499				}
21500
21501				/**
21502				* Unbinding the mousemove when the mouse's middle button is released
21503				*/
21504				function removeMiddleWheelHandler(){
21505						container
21506								.off('mousedown', mouseDownHandler)
21507								.off('mouseup', mouseUpHandler);
21508				}
21509
21510				/**
21511				* Adds the possibility to auto scroll through sections on touch devices.
21512				*/
21513				function addTouchHandler(){
21514						if(isTouchDevice || isTouch){
21515								if(options.autoScrolling){
21516										$body.off(events.touchmove).on(events.touchmove, preventBouncing);
21517								}
21518
21519								$(WRAPPER_SEL)
21520										.off(events.touchstart).on(events.touchstart, touchStartHandler)
21521										.off(events.touchmove).on(events.touchmove, touchMoveHandler);
21522						}
21523				}
21524
21525				/**
21526				* Removes the auto scrolling for touch devices.
21527				*/
21528				function removeTouchHandler(){
21529						if(isTouchDevice || isTouch){
21530								$(WRAPPER_SEL)
21531										.off(events.touchstart)
21532										.off(events.touchmove);
21533						}
21534				}
21535
21536				/*
21537				* Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
21538				* http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
21539				*/
21540				function getMSPointer(){
21541						var pointer;
21542
21543						//IE >= 11 & rest of browsers
21544						if(window.PointerEvent){
21545								pointer = { down: 'pointerdown', move: 'pointermove'};
21546						}
21547
21548						//IE < 11
21549						else{
21550								pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
21551						}
21552
21553						return pointer;
21554				}
21555
21556				/**
21557				* Gets the pageX and pageY properties depending on the browser.
21558				* https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
21559				*/
21560				function getEventsPage(e){
21561						var events = [];
21562
21563						events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
21564						events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
21565
21566						//in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
21567						if(isTouch && isReallyTouch(e) && options.scrollBar){
21568								events.y = e.touches[0].pageY;
21569								events.x = e.touches[0].pageX;
21570						}
21571
21572						return events;
21573				}
21574
21575				/**
21576				* Slides silently (with no animation) the active slider to the given slide.
21577				* @param noCallback {bool} true or defined -> no callbacks
21578				*/
21579				function silentLandscapeScroll(activeSlide, noCallbacks){
21580						setScrollingSpeed (0, 'internal');
21581
21582						if(typeof noCallbacks !== 'undefined'){
21583								//preventing firing callbacks afterSlideLoad etc.
21584								isResizing = true;
21585						}
21586
21587						landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
21588
21589						if(typeof noCallbacks !== 'undefined'){
21590								isResizing = false;
21591						}
21592
21593						setScrollingSpeed(originals.scrollingSpeed, 'internal');
21594				}
21595
21596				/**
21597				* Scrolls silently (with no animation) the page to the given Y position.
21598				*/
21599				function silentScroll(top){
21600						// The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
21601						// that's why we round it to 0.
21602						var roundedTop = Math.round(top);
21603
21604						if (options.css3 && options.autoScrolling && !options.scrollBar){
21605								var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
21606								transformContainer(translate3d, false);
21607						}
21608						else if(options.autoScrolling && !options.scrollBar){
21609								container.css('top', -roundedTop);
21610						}
21611						else{
21612								$htmlBody.scrollTop(roundedTop);
21613						}
21614				}
21615
21616				/**
21617				* Returns the cross-browser transform string.
21618				*/
21619				function getTransforms(translate3d){
21620						return {
21621								'-webkit-transform': translate3d,
21622								'-moz-transform': translate3d,
21623								'-ms-transform':translate3d,
21624								'transform': translate3d
21625						};
21626				}
21627
21628				/**
21629				* Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
21630				* @type  m (mouse) or k (keyboard)
21631				*/
21632				function setIsScrollAllowed(value, direction, type){
21633						switch (direction){
21634								case 'up': isScrollAllowed[type].up = value; break;
21635								case 'down': isScrollAllowed[type].down = value; break;
21636								case 'left': isScrollAllowed[type].left = value; break;
21637								case 'right': isScrollAllowed[type].right = value; break;
21638								case 'all':
21639										if(type == 'm'){
21640												setAllowScrolling(value);
21641										}else{
21642												setKeyboardScrolling(value);
21643										}
21644						}
21645				}
21646
21647				/*
21648				* Destroys fullpage.js plugin events and optinally its html markup and styles
21649				*/
21650				function destroy(all){
21651						setAutoScrolling(false, 'internal');
21652						setAllowScrolling(false);
21653						setKeyboardScrolling(false);
21654						container.addClass(DESTROYED);
21655
21656						clearTimeout(afterSlideLoadsId);
21657						clearTimeout(afterSectionLoadsId);
21658						clearTimeout(resizeId);
21659						clearTimeout(scrollId);
21660						clearTimeout(scrollId2);
21661
21662						$window
21663								.off('scroll', scrollHandler)
21664								.off('hashchange', hashChangeHandler)
21665								.off('resize', resizeHandler);
21666
21667						$document
21668								.off('click touchstart', SECTION_NAV_SEL + ' a')
21669								.off('mouseenter', SECTION_NAV_SEL + ' li')
21670								.off('mouseleave', SECTION_NAV_SEL + ' li')
21671								.off('click touchstart', SLIDES_NAV_LINK_SEL)
21672								.off('mouseover', options.normalScrollElements)
21673								.off('mouseout', options.normalScrollElements);
21674
21675						$(SECTION_SEL)
21676								.off('click touchstart', SLIDES_ARROW_SEL);
21677
21678						clearTimeout(afterSlideLoadsId);
21679						clearTimeout(afterSectionLoadsId);
21680
21681						//lets make a mess!
21682						if(all){
21683								destroyStructure();
21684						}
21685				}
21686
21687				/*
21688				* Removes inline styles added by fullpage.js
21689				*/
21690				function destroyStructure(){
21691						//reseting the `top` or `translate` properties to 0
21692						silentScroll(0);
21693
21694						//loading all the lazy load content
21695						container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
21696								setSrc($(this), 'src');
21697						});
21698
21699						container.find('img[data-srcset]').each(function(){
21700								setSrc($(this), 'srcset');
21701						});
21702
21703						$(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
21704
21705						//removing inline styles
21706						$(SECTION_SEL).css( {
21707								'height': '',
21708								'background-color' : '',
21709								'padding': ''
21710						});
21711
21712						$(SLIDE_SEL).css( {
21713								'width': ''
21714						});
21715
21716						container.css({
21717								'height': '',
21718								'position': '',
21719								'-ms-touch-action': '',
21720								'touch-action': ''
21721						});
21722
21723						$htmlBody.css({
21724								'overflow': '',
21725								'height': ''
21726						});
21727
21728						// remove .fp-enabled class
21729						$('html').removeClass(ENABLED);
21730
21731						// remove .fp-responsive class
21732						$body.removeClass(RESPONSIVE);
21733
21734						// remove all of the .fp-viewing- classes
21735						$.each($body.get(0).className.split(/\s+/), function (index, className) {
21736								if (className.indexOf(VIEWING_PREFIX) === 0) {
21737										$body.removeClass(className);
21738								}
21739						});
21740
21741						//removing added classes
21742						$(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
21743								options.scrollOverflowHandler.remove($(this));
21744								$(this).removeClass(TABLE + ' ' + ACTIVE);
21745						});
21746
21747						removeAnimation(container);
21748
21749						//Unwrapping content
21750						container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
21751								//unwrap not being use in case there's no child element inside and its just text
21752								$(this).replaceWith(this.childNodes);
21753						});
21754
21755						//removing the applied transition from the fullpage wrapper
21756						container.css({
21757								'-webkit-transition': 'none',
21758								'transition': 'none'
21759						});
21760
21761						//scrolling the page to the top with no animation
21762						$htmlBody.scrollTop(0);
21763
21764						//removing selectors
21765						var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
21766						$.each(usedSelectors, function(index, value){
21767								$('.' + value).removeClass(value);
21768						});
21769				}
21770
21771				/*
21772				* Sets the state for a variable with multiple states (original, and temporal)
21773				* Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
21774				* This function is used to keep track of both states, the original and the temporal one.
21775				* If type is not 'internal', then we assume the user is globally changing the variable.
21776				*/
21777				function setVariableState(variable, value, type){
21778						options[variable] = value;
21779						if(type !== 'internal'){
21780								originals[variable] = value;
21781						}
21782				}
21783
21784				/**
21785				* Displays warnings
21786				*/
21787				function displayWarnings(){
21788						var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
21789						//UNCODE.addition
21790						// if($('html').hasClass(ENABLED)){
21791						//     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
21792						//     return;
21793						// }
21794
21795						// Disable mutually exclusive settings
21796						//UNCODE.addition
21797						// if (options.continuousVertical &&
21798						//     (options.loopTop || options.loopBottom)) {
21799						//     options.continuousVertical = false;
21800						//     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
21801						// }
21802
21803						// if(options.scrollBar && options.scrollOverflow){
21804						//     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
21805						// }
21806
21807						// if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
21808						//     options.continuousVertical = false;
21809						//     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
21810						// }
21811
21812						//using extensions? Wrong file!
21813						$.each(extensions, function(index, extension){
21814								//is the option set to true?
21815								if(options[extension]){
21816										showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
21817								}
21818						});
21819
21820						//anchors can not have the same value as any element ID or NAME
21821						$.each(options.anchors, function(index, name){
21822
21823								//case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
21824								var nameAttr = $document.find('[name]').filter(function() {
21825										return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
21826								});
21827
21828								var idAttr = $document.find('[id]').filter(function() {
21829										return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
21830								});
21831
21832								if(idAttr.length || nameAttr.length ){
21833										showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
21834										idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
21835										nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
21836								}
21837						});
21838				}
21839
21840				/**
21841				* Shows a message in the console of the given type.
21842				*/
21843				function showError(type, text){
21844						console && console[type] && console[type]('fullPage: ' + text);
21845				}
21846
21847		}; //end of $.fn.fullpage
21848
21849		if(typeof IScroll !== 'undefined'){
21850				/*
21851				* Turns iScroll `mousewheel` option off dynamically
21852				* https://github.com/cubiq/iscroll/issues/1036
21853				*/
21854				IScroll.prototype.wheelOn = function () {
21855						this.wrapper.addEventListener('wheel', this);
21856						this.wrapper.addEventListener('mousewheel', this);
21857						this.wrapper.addEventListener('DOMMouseScroll', this);
21858				};
21859
21860				/*
21861				* Turns iScroll `mousewheel` option on dynamically
21862				* https://github.com/cubiq/iscroll/issues/1036
21863				*/
21864				IScroll.prototype.wheelOff = function () {
21865						this.wrapper.removeEventListener('wheel', this);
21866						this.wrapper.removeEventListener('mousewheel', this);
21867						this.wrapper.removeEventListener('DOMMouseScroll', this);
21868				};
21869		}
21870
21871		/**
21872		 * An object to handle overflow scrolling.
21873		 * This uses jquery.slimScroll to accomplish overflow scrolling.
21874		 * It is possible to pass in an alternate scrollOverflowHandler
21875		 * to the fullpage.js option that implements the same functions
21876		 * as this handler.
21877		 *
21878		 * @type {Object}
21879		 */
21880		var iscrollHandler = {
21881				refreshId: null,
21882				iScrollInstances: [],
21883
21884				// Enables or disables the mouse wheel for the active section or all slides in it
21885				toggleWheel: function(value){
21886						var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
21887						scrollable.each(function(){
21888								var iScrollInstance = $(this).data('iscrollInstance');
21889								if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
21890										if(value){
21891												iScrollInstance.wheelOn();
21892										}
21893										else{
21894												iScrollInstance.wheelOff();
21895										}
21896								}
21897						});
21898				},
21899
21900				/**
21901				* Turns off iScroll for the destination section.
21902				* When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
21903				* scroll the destination section/slide before the sections animations ends.
21904				*/
21905				onLeave: function(){
21906						iscrollHandler.toggleWheel(false);
21907				},
21908
21909				// Turns off iScroll for the leaving section
21910				beforeLeave: function(){
21911						iscrollHandler.onLeave()
21912				},
21913
21914				// Turns on iScroll on section load
21915				afterLoad: function(){
21916						iscrollHandler.toggleWheel(true);
21917				},
21918
21919				/**
21920				 * Called when overflow scrolling is needed for a section.
21921				 *
21922				 * @param  {Object} element      jQuery object containing current section
21923				 * @param  {Number} scrollHeight Current window height in pixels
21924				 */
21925				create: function(element, scrollHeight) {
21926						var scrollable = element.find(SCROLLABLE_SEL);
21927
21928						scrollable.height(scrollHeight);
21929						scrollable.each(function() {
21930								var $this = $(this);
21931								var iScrollInstance = $this.data('iscrollInstance');
21932								if (iScrollInstance) {
21933										$.each(iscrollHandler.iScrollInstances, function(){
21934												$(this).destroy();
21935										});
21936								}
21937
21938								iScrollInstance = new IScroll($this.get(0), iscrollOptions);
21939								iscrollHandler.iScrollInstances.push(iScrollInstance);
21940
21941								//off by default until the section gets active
21942								iScrollInstance.wheelOff();
21943
21944								$this.data('iscrollInstance', iScrollInstance);
21945						});
21946				},
21947
21948				/**
21949				 * Return a boolean depending on whether the scrollable element is a
21950				 * the end or at the start of the scrolling depending on the given type.
21951				 *
21952				 * @param  {String}  type       Either 'top' or 'bottom'
21953				 * @param  {Object}  scrollable jQuery object for the scrollable element
21954				 * @return {Boolean}
21955				 */
21956				isScrolled: function(type, scrollable) {
21957						var scroller = scrollable.data('iscrollInstance');
21958
21959						//no scroller?
21960						if (!scroller) {
21961								return true;
21962						}
21963
21964						if (type === 'top') {
21965								return scroller.y >= 0 && !scrollable.scrollTop();
21966						} else if (type === 'bottom') {
21967								return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHe
21967ight() >= scrollable[0].scrollHeight;
21968						}
21969				},
21970
21971				/**
21972				 * Returns the scrollable element for the given section.
21973				 * If there are landscape slides, will only return a scrollable element
21974				 * if it is in the active slide.
21975				 *
21976				 * @param  {Object}  activeSection jQuery object containing current section
21977				 * @return {Boolean}
21978				 */
21979				scrollable: function(activeSection){
21980						// if there are landscape slides, we check if the scrolling bar is in the current one or not
21981						if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
21982								return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
21983						}
21984						return activeSection.find(SCROLLABLE_SEL);
21985				},
21986
21987				/**
21988				 * Returns the scroll height of the wrapped content.
21989				 * If this is larger than the window height minus section padding,
21990				 * overflow scrolling is needed.
21991				 *
21992				 * @param  {Object} element jQuery object containing current section
21993				 * @return {Number}
21994				 */
21995				scrollHeight: function(element) {
21996						return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
21997				},
21998
21999				/**
22000				 * Called when overflow scrolling is no longer needed for a section.
22001				 *
22002				 * @param  {Object} element      jQuery object containing current section
22003				 */
22004				remove: function(element) {
22005						var scrollable = element.find(SCROLLABLE_SEL);
22006						if (scrollable.length) {
22007								var iScrollInstance = scrollable.data('iscrollInstance');
22008								iScrollInstance.destroy();
22009
22010								scrollable.data('iscrollInstance', null);
22011						}
22012						element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
22013				},
22014
22015				/**
22016				 * Called when overflow scrolling has already been setup but the
22017				 * window height has potentially changed.
22018				 *
22019				 * @param  {Object} element      jQuery object containing current section
22020				 * @param  {Number} scrollHeight Current window height in pixels
22021				 */
22022				update: function(element, scrollHeight) {
22023						//using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
22024						//short period of time.
22025						//it also comes on handy because iScroll requires the use of timeout when using `refresh`.
22026						clearTimeout(iscrollHandler.refreshId);
22027						iscrollHandler.refreshId = setTimeout(function(){
22028								$.each(iscrollHandler.iScrollInstances, function(){
22029										$(this).get(0).refresh();
22030								});
22031						}, 150);
22032
22033						//updating the wrappers height
22034						element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
22035				},
22036
22037				/**
22038				 * Called to get any additional elements needed to wrap the section
22039				 * content in order to facilitate overflow scrolling.
22040				 *
22041				 * @return {String|Object} Can be a string containing HTML,
22042				 *                         a DOM element, or jQuery object.
22043				 */
22044				wrapContent: function() {
22045						return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
22046				}
22047		};
22048});
22049
22050
22051
22052/* ========================================================================
22053 * Bootstrap: collapse.js v3.1.1
22054 * http://getbootstrap.com/javascript/#collapse
22055 * ========================================================================
22056 * Copyright 2011-2014 Twitter, Inc.
22057 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22058 * ======================================================================== */
22059
22060
22061+function ($) {
22062	'use strict';
22063
22064	// COLLAPSE PUBLIC CLASS DEFINITION
22065	// ================================
22066
22067	var Collapse = function (element, options) {
22068		this.$element      = $(element)
22069		this.options       = $.extend({}, Collapse.DEFAULTS, options)
22070		this.transitioning = null
22071
22072		if (this.options.parent) this.$parent = $(this.options.parent)
22073		if (this.options.toggle) this.toggle()
22074	}
22075
22076	Collapse.DEFAULTS = {
22077		toggle: true
22078	}
22079
22080	Collapse.prototype.dimension = function () {
22081		var hasWidth = this.$element.hasClass('width')
22082		return hasWidth ? 'width' : 'height'
22083	}
22084
22085	Collapse.prototype.show = function () {
22086		if (this.transitioning || this.$element.hasClass('in')) return
22087
22088		var startEvent = $.Event('show.bs.collapse')
22089		this.$element.trigger(startEvent)
22090		if (startEvent.isDefaultPrevented()) return
22091
22092		var actives = this.$parent && this.$parent.find('> .panel > .in')
22093
22094		if (actives && actives.length) {
22095			var hasData = actives.data('bs.collapse')
22096			if (hasData && hasData.transitioning) return
22097			actives.collapse('hide')
22098			hasData || actives.data('bs.collapse', null)
22099		}
22100
22101		var dimension = this.dimension()
22102
22103		this.$element
22104			.removeClass('collapse')
22105			.addClass('collapsing')[dimension](0)
22106
22107		this.transitioning = 1
22108
22109		var complete = function (e) {
22110			if (e && e.target != this.$element[0]) return
22111			this.$element
22112				.removeClass('collapsing')
22113				.addClass('collapse in')[dimension]('auto')
22114			this.transitioning = 0
22115			this.$element.trigger('shown.bs.collapse')
22116		}
22117
22118		if (!$.support.transition) return complete.call(this)
22119
22120		var scrollSize = $.camelCase(['scroll', dimension].join('-'))
22121
22122		this.$element
22123			.one($.support.transition.end, $.proxy(complete, this))
22124			.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
22125	}
22126
22127	Collapse.prototype.hide = function () {
22128		if (this.transitioning || !this.$element.hasClass('in')) return
22129
22130		var startEvent = $.Event('hide.bs.collapse')
22131		this.$element.trigger(startEvent)
22132		if (startEvent.isDefaultPrevented()) return
22133
22134		var dimension = this.dimension()
22135
22136		this.$element[dimension](this.$element[dimension]())[0].offsetHeight
22137
22138		this.$element
22139			.addClass('collapsing')
22140			.removeClass('collapse')
22141			.removeClass('in')
22142
22143		this.transitioning = 1
22144
22145		var complete = function (e) {
22146			if (e && e.target != this.$element[0]) return
22147			this.transitioning = 0
22148			this.$element
22149				.trigger('hidden.bs.collapse')
22150				.removeClass('collapsing')
22151				.addClass('collapse')
22152		}
22153
22154		if (!$.support.transition) return complete.call(this)
22155
22156		this.$element
22157			[dimension](0)
22158			.one($.support.transition.end, $.proxy(complete, this))
22159			.emulateTransitionEnd(350)
22160	}
22161
22162	Collapse.prototype.toggle = function () {
22163		this[this.$element.hasClass('in') ? 'hide' : 'show']()
22164	}
22165
22166
22167	// COLLAPSE PLUGIN DEFINITION
22168	// ==========================
22169
22170	var old = $.fn.collapse
22171
22172	$.fn.collapse = function (option) {
22173		return this.each(function () {
22174			var $this   = $(this)
22175			var data    = $this.data('bs.collapse')
22176			var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
22177
22178			if (!data && options.toggle && option == 'show') option = !option
22179			if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
22180			if (typeof option == 'string') data[option]()
22181		})
22182	}
22183
22184	$.fn.collapse.Constructor = Collapse
22185
22186
22187	// COLLAPSE NO CONFLICT
22188	// ====================
22189
22190	$.fn.collapse.noConflict = function () {
22191		$.fn.collapse = old
22192		return this
22193	}
22194
22195
22196	// COLLAPSE DATA-API
22197	// =================
22198
22199	$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
22200		var $this   = $(this), href
22201		var target  = $this.attr('data-target')
22202				|| e.preventDefault()
22203				|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
22204		//Edited by Uncode to replace ID in panel [START]
22205		var _target = href.replace(/^#/, "");
22206		if ( $('[data-id="' + _target + '"]').length ) {
22207			var $target = $('[data-id="' + _target + '"]')
22208		} else {
22209			var $target = $(target)
22210		}
22211		//Edited by Uncode to replace ID in panel [END]
22212		var data    = $target.data('bs.collapse')
22213		var option  = data ? 'toggle' : $this.data()
22214		var parent  = $this.attr('data-parent')
22215		var $parent = parent && $(parent)
22216
22217		if (!data || !data.transitioning) {
22218			if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
22219			$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
22220		}
22221
22222		$target.collapse(option)
22223	})
22224
22225}(jQuery);
22226
22227
22228/* ========================================================================
22229 * Bootstrap: tab.js v3.1.1
22230 * http://getbootstrap.com/javascript/#tabs
22231 * ========================================================================
22232 * Copyright 2011-2014 Twitter, Inc.
22233 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22234 * ======================================================================== */
22235
22236
22237+function ($) {
22238	'use strict';
22239
22240	// TAB CLASS DEFINITION
22241	// ====================
22242
22243	var Tab = function (element) {
22244		this.element = $(element)
22245	}
22246
22247	Tab.prototype.show = function () {
22248		var $this    = this.element
22249		var $ul      = $this.closest('ul:not(.dropdown-menu)')
22250		var selector = $this.data('target')
22251
22252		if (!selector) {
22253			selector = $this.attr('href')
22254			selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
22255		}
22256
22257		if ($this.parent('li').hasClass('active')) return
22258
22259		var previous = $ul.find('.active:last a')[0]
22260		var e        = $.Event('show.bs.tab', {
22261			relatedTarget: previous
22262		})
22263
22264		$this.trigger(e)
22265
22266		if (e.isDefaultPrevented()) return
22267
22268		//Edited by Uncode to replace ID in panel [START]
22269		var _target = selector.replace(/^#/, "");
22270		if ( $('[data-id="' + _target + '"]').length )
22271			var $target = $('[data-id="' + _target + '"]')
22272		else
22273			var $target = $(selector)
22274		//Edited by Uncode to replace ID in panel [END]
22275
22276		this.activate($this.parent('li'), $ul)
22277		this.activate($target, $target.parent(), function () {
22278			$this.trigger({
22279				type: 'shown.bs.tab',
22280				relatedTarget: previous
22281			})
22282		})
22283	}
22284
22285	Tab.prototype.activate = function (element, container, callback) {
22286		var $active    = container.find('> .active')
22287		var transition = callback
22288			&& $.support.transition
22289			&& $active.hasClass('fade')
22290
22291		function next() {
22292			$active
22293				.removeClass('active')
22294				.find('> .dropdown-menu > .active')
22295				.removeClass('active')
22296
22297			element.addClass('active')
22298
22299			if (transition) {
22300				element[0].offsetWidth // reflow for transition
22301				element.addClass('in')
22302			} else {
22303				element.removeClass('fade')
22304			}
22305
22306			if (element.parent('.dropdown-menu')) {
22307				element.closest('li.dropdown').addClass('active')
22308			}
22309
22310			callback && callback()
22311		}
22312
22313		transition ?
22314			$active
22315				.one($.support.transition.end, next)
22316				.emulateTransitionEnd(150) :
22317			next()
22318
22319		$active.removeClass('in')
22320	}
22321
22322
22323	// TAB PLUGIN DEFINITION
22324	// =====================
22325
22326	var old = $.fn.tab
22327
22328	$.fn.tab = function ( option ) {
22329		return this.each(function () {
22330			var $this = $(this)
22331			var data  = $this.data('bs.tab')
22332
22333			if (!data) $this.data('bs.tab', (data = new Tab(this)))
22334			if (typeof option == 'string') data[option]()
22335		})
22336	}
22337
22338	$.fn.tab.Constructor = Tab
22339
22340
22341	// TAB NO CONFLICT
22342	// ===============
22343
22344	$.fn.tab.noConflict = function () {
22345		$.fn.tab = old
22346		return this
22347	}
22348
22349
22350	// TAB DATA-API
22351	// ============
22352
22353	$(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
22354		e.preventDefault()
22355		$(this).tab('show')
22356	})
22357
22358}(jQuery);
22359
22360
22361/* ========================================================================
22362 * Bootstrap: tooltip.js v3.1.1
22363 * http://getbootstrap.com/javascript/#tooltip
22364 * Inspired by the original jQuery.tipsy by Jason Frame
22365 * ========================================================================
22366 * Copyright 2011-2014 Twitter, Inc.
22367 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22368 * ======================================================================== */
22369
22370
22371+function ($) {
22372	'use strict';
22373
22374	// TOOLTIP PUBLIC CLASS DEFINITION
22375	// ===============================
22376
22377	var Tooltip = function (element, options) {
22378		this.type       =
22379		this.options    =
22380		this.enabled    =
22381		this.timeout    =
22382		this.hoverState =
22383		this.$element   = null
22384
22385		this.init('tooltip', element, options)
22386	}
22387
22388	Tooltip.DEFAULTS = {
22389		animation: true,
22390		placement: 'top',
22391		selector: false,
22392		template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
22393		trigger: 'hover focus',
22394		title: '',
22395		delay: 0,
22396		html: false,
22397		container: false,
22398		viewport: {
22399			selector: 'body',
22400			padding: 0
22401		}
22402	}
22403
22404	Tooltip.prototype.init = function (type, element, options) {
22405		this.enabled   = true
22406		this.type      = type
22407		this.$element  = $(element)
22408		this.options   = this.getOptions(options)
22409		this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
22410
22411		var triggers = this.options.trigger.split(' ')
22412
22413		for (var i = triggers.length; i--;) {
22414			var trigger = triggers[i]
22415
22416			if (trigger == 'click') {
22417				this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
22418			} else if (trigger != 'manual') {
22419				var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
22420				var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
22421
22422				this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
22423				this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
22424			}
22425		}
22426
22427		this.options.selector ?
22428			(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
22429			this.fixTitle()
22430	}
22431
22432	Tooltip.prototype.getDefaults = function () {
22433		return Tooltip.DEFAULTS
22434	}
22435
22436	Tooltip.prototype.getOptions = function (options) {
22437		options = $.extend({}, this.getDefaults(), this.$element.data(), options)
22438
22439		if (options.delay && typeof options.delay == 'number') {
22440			options.delay = {
22441				show: options.delay,
22442				hide: options.delay
22443			}
22444		}
22445
22446		return options
22447	}
22448
22449	Tooltip.prototype.getDelegateOptions = function () {
22450		var options  = {}
22451		var defaults = this.getDefaults()
22452
22453		this._options && $.each(this._options, function (key, value) {
22454			if (defaults[key] != value) options[key] = value
22455		})
22456
22457		return options
22458	}
22459
22460	Tooltip.prototype.enter = function (obj) {
22461		var self = obj instanceof this.constructor ?
22462			obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
22463
22464		clearTimeout(self.timeout)
22465
22466		self.hoverState = 'in'
22467
22468		if (!self.options.delay || !self.options.delay.show) return self.show()
22469
22470		self.timeout = setTimeout(function () {
22471			if (self.hoverState == 'in') self.show()
22472		}, self.options.delay.show)
22473	}
22474
22475	Tooltip.prototype.leave = function (obj) {
22476		var self = obj instanceof this.constructor ?
22477			obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
22478
22479		clearTimeout(self.timeout)
22480
22481		self.hoverState = 'out'
22482
22483		if (!self.options.delay || !self.options.delay.hide) return self.hide()
22484
22485		self.timeout = setTimeout(function () {
22486			if (self.hoverState == 'out') self.hide()
22487		}, self.options.delay.hide)
22488	}
22489
22490	Tooltip.prototype.show = function () {
22491		var e = $.Event('show.bs.' + this.type)
22492
22493		if (this.hasContent() && this.enabled) {
22494			this.$element.trigger(e)
22495
22496			if (e.isDefaultPrevented()) return
22497			var that = this;
22498
22499			var $tip = this.tip()
22500
22501			this.setContent()
22502
22503			if (this.options.animation) $tip.addClass('fade')
22504
22505			var placement = typeof this.options.placement == 'function' ?
22506				this.options.placement.call(this, $tip[0], this.$element[0]) :
22507				this.options.placement
22508
22509			var autoToken = /\s?auto?\s?/i
22510			var autoPlace = autoToken.test(placement)
22511			if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
22512
22513			$tip
22514				.detach()
22515				.css({ top: 0, left: 0, display: 'block' })
22516				.addClass(placement)
22517
22518			this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
22519
22520			var pos          = this.getPosition()
22521			var actualWidth  = $tip[0].offsetWidth
22522			var actualHeight = $tip[0].offsetHeight
22523
22524			if (autoPlace) {
22525				var orgPlacement = placement
22526				var $parent      = this.$element.parent()
22527				var parentDim    = this.getPosition($parent)
22528
22529				placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
22530										placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
22531										placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
22532										placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
22533										placement
22534
22535				$tip
22536					.removeClass(orgPlacement)
22537					.addClass(placement)
22538			}
22539
22540			var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
22541
22542			this.applyPlacement(calculatedOffset, placement)
22543			this.hoverState = null
22544
22545			var complete = function() {
22546				that.$element.trigger('shown.bs.' + that.type)
22547			}
22548
22549			$.support.transition && this.$tip.hasClass('fade') ?
22550				$tip
22551					.one($.support.transition.end, complete)
22552					.emulateTransitionEnd(150) :
22553				complete()
22554		}
22555	}
22556
22557	Tooltip.prototype.applyPlacement = function (offset, placement) {
22558		var $tip   = this.tip()
22559		var width  = $tip[0].offsetWidth
22560		var height = $tip[0].offsetHeight
22561
22562		// manually read margins because getBoundingClientRect includes difference
22563		var marginTop = parseInt($tip.css('margin-top'), 10)
22564		var marginLeft = parseInt($tip.css('margin-left'), 10)
22565
22566		// we must check for NaN for ie 8/9
22567		if (isNaN(marginTop))  marginTop  = 0
22568		if (isNaN(marginLeft)) marginLeft = 0
22569
22570		offset.top  = offset.top  + marginTop
22571		offset.left = offset.left + marginLeft
22572
22573		// $.fn.offset doesn't round pixel values
22574		// so we use setOffset directly with our own function B-0
22575		$.offset.setOffset($tip[0], $.extend({
22576			using: function (props) {
22577				$tip.css({
22578					top: Math.round(props.top),
22579					left: Math.round(props.left)
22580				})
22581			}
22582		}, offset), 0)
22583
22584		$tip.addClass('in')
22585
22586		// check to see if placing tip in new offset caused the tip to resize itself
22587		var actualWidth  = $tip[0].offsetWidth
22588		var actualHeight = $tip[0].offsetHeight
22589
22590		if (placement == 'top' && actualHeight != height) {
22591			offset.top = offset.top + height - actualHeight
22592		}
22593
22594		var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
22595
22596		if (delta.left) offset.left += delta.left
22597		else offset.top += delta.top
22598
22599		var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
22600		var arrowPosition       = delta.left ? 'left'        : 'top'
22601		var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
22602
22603		$tip.offset(offset)
22604		this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
22605	}
22606
22607	Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
22608		this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
22609	}
22610
22611	Tooltip.prototype.setContent = function () {
22612		var $tip  = this.tip()
22613		var title = this.getTitle()
22614
22615		$tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
22616		$tip.removeClass('fade in top bottom left right')
22617	}
22618
22619	Tooltip.prototype.hide = function () {
22620		var that = this
22621		var $tip = this.tip()
22622		var e    = $.Event('hide.bs.' + this.type)
22623
22624		function complete() {
22625			if (that.hoverState != 'in') $tip.detach()
22626			that.$element.trigger('hidden.bs.' + that.type)
22627		}
22628
22629		this.$element.trigger(e)
22630
22631		if (e.isDefaultPrevented()) return
22632
22633		$tip.removeClass('in')
22634
22635		$.support.transition && this.$tip.hasClass('fade') ?
22636			$tip
22637				.one($.support.transition.end, complete)
22638				.emulateTransitionEnd(150) :
22639			complete()
22640
22641		this.hoverState = null
22642
22643		return this
22644	}
22645
22646	Tooltip.prototype.fixTitle = function () {
22647		var $e = this.$element
22648		if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
22649			$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
22650		}
22651	}
22652
22653	Tooltip.prototype.hasContent = function () {
22654		return this.getTitle()
22655	}
22656
22657	Tooltip.prototype.getPosition = function ($element) {
22658		$element   = $element || this.$element
22659		var el     = $element[0]
22660		var isBody = el.tagName == 'BODY'
22661		return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
22662			scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
22663			width:  isBody ? $(window).width()  : $element.outerWidth(),
22664			height: isBody ? $(window).height() : $element.outerHeight()
22665		}, isBody ? {top: 0, left: 0} : $element.offset())
22666	}
22667
22668	Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
22669		return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
22670					 placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
22671					 placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
22672				/* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
22673
22674	}
22675
22676	Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
22677		var delta = { top: 0, left: 0 }
22678		if (!this.$viewport) return delta
22679
22680		var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
22681		var viewportDimensions = this.getPosition(this.$viewport)
22682
22683		if (/right|left/.test(placement)) {
22684			var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
22685			var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
22686			if (topEdgeOffset < viewportDimensions.top) { // top overflow
22687				delta.top = viewportDimensions.top - topEdgeOffset
22688			} else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
22689				delta.top = viewportDimensions.top + viewportDimensions.height - bottom
22689EdgeOffset
22690			}
22691		} else {
22692			var leftEdgeOffset  = pos.left - viewportPadding
22693			var rightEdgeOffset = pos.left + viewportPadding + actualWidth
22694			if (leftEdgeOffset < viewportDimensions.left) { // left overflow
22695				delta.left = viewportDimensions.left - leftEdgeOffset
22696			} else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
22697				delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
22698			}
22699		}
22700
22701		return delta
22702	}
22703
22704	Tooltip.prototype.getTitle = function () {
22705		var title
22706		var $e = this.$element
22707		var o  = this.options
22708
22709		title = $e.attr('data-original-title')
22710			|| (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
22711
22712		return title
22713	}
22714
22715	Tooltip.prototype.tip = function () {
22716		return this.$tip = this.$tip || $(this.options.template)
22717	}
22718
22719	Tooltip.prototype.arrow = function () {
22720		return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
22721	}
22722
22723	Tooltip.prototype.validate = function () {
22724		if (!this.$element[0].parentNode) {
22725			this.hide()
22726			this.$element = null
22727			this.options  = null
22728		}
22729	}
22730
22731	Tooltip.prototype.enable = function () {
22732		this.enabled = true
22733	}
22734
22735	Tooltip.prototype.disable = function () {
22736		this.enabled = false
22737	}
22738
22739	Tooltip.prototype.toggleEnabled = function () {
22740		this.enabled = !this.enabled
22741	}
22742
22743	Tooltip.prototype.toggle = function (e) {
22744		var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
22745		self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
22746	}
22747
22748	Tooltip.prototype.destroy = function () {
22749		clearTimeout(this.timeout)
22750		this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
22751	}
22752
22753
22754	// TOOLTIP PLUGIN DEFINITION
22755	// =========================
22756
22757	var old = $.fn.tooltip
22758
22759	$.fn.tooltip = function (option) {
22760		return this.each(function () {
22761			var $this   = $(this)
22762			var data    = $this.data('bs.tooltip')
22763			var options = typeof option == 'object' && option
22764
22765			if (!data && option == 'destroy') return
22766			if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
22767			if (typeof option == 'string') data[option]()
22768		})
22769	}
22770
22771	$.fn.tooltip.Constructor = Tooltip
22772
22773
22774	// TOOLTIP NO CONFLICT
22775	// ===================
22776
22777	$.fn.tooltip.noConflict = function () {
22778		$.fn.tooltip = old
22779		return this
22780	}
22781
22782}(jQuery);
22783
22784
22785/* ========================================================================
22786 * Bootstrap: transition.js v3.1.1
22787 * http://getbootstrap.com/javascript/#transitions
22788 * ========================================================================
22789 * Copyright 2011-2014 Twitter, Inc.
22790 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
22791 * ======================================================================== */
22792
22793
22794+function ($) {
22795	'use strict';
22796
22797	// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
22798	// ============================================================
22799
22800	function transitionEnd() {
22801		var el = document.createElement('bootstrap')
22802
22803		var transEndEventNames = {
22804			WebkitTransition : 'webkitTransitionEnd',
22805			MozTransition    : 'transitionend',
22806			OTransition      : 'oTransitionEnd otransitionend',
22807			transition       : 'transitionend'
22808		}
22809
22810		for (var name in transEndEventNames) {
22811			if (el.style[name] !== undefined) {
22812				return { end: transEndEventNames[name] }
22813			}
22814		}
22815
22816		return false // explicit for ie8 (  ._.)
22817	}
22818
22819	// http://blog.alexmaccaw.com/css-transitions
22820	$.fn.emulateTransitionEnd = function (duration) {
22821		var called = false, $el = this
22822		$(this).one($.support.transition.end, function () { called = true })
22823		var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
22824		setTimeout(callback, duration)
22825		return this
22826	}
22827
22828	$(function () {
22829		$.support.transition = transitionEnd()
22830	})
22831
22832}(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.