balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

owl.js (89992B)


      1 /**
      2  * Owl Carousel v2.3.4
      3  * Copyright 2013-2018 David Deutsch
      4  * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
      5  */
      6 /**
      7  * Owl carousel
      8  * @version 2.3.4
      9  * @author Bartosz Wojciechowski
     10  * @author David Deutsch
     11  * @license The MIT License (MIT)
     12  * @todo Lazy Load Icon
     13  * @todo prevent animationend bubling
     14  * @todo itemsScaleUp
     15  * @todo Test Zepto
     16  * @todo stagePadding calculate wrong active classes
     17  */
     18 ;(function($, window, document, undefined) {
     19 
     20 	/**
     21 	 * Creates a carousel.
     22 	 * @class The Owl Carousel.
     23 	 * @public
     24 	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
     25 	 * @param {Object} [options] - The options
     26 	 */
     27 	function Owl(element, options) {
     28 
     29 		/**
     30 		 * Current settings for the carousel.
     31 		 * @public
     32 		 */
     33 		this.settings = null;
     34 
     35 		/**
     36 		 * Current options set by the caller including defaults.
     37 		 * @public
     38 		 */
     39 		this.options = $.extend({}, Owl.Defaults, options);
     40 
     41 		/**
     42 		 * Plugin element.
     43 		 * @public
     44 		 */
     45 		this.$element = $(element);
     46 
     47 		/**
     48 		 * Proxied event handlers.
     49 		 * @protected
     50 		 */
     51 		this._handlers = {};
     52 
     53 		/**
     54 		 * References to the running plugins of this carousel.
     55 		 * @protected
     56 		 */
     57 		this._plugins = {};
     58 
     59 		/**
     60 		 * Currently suppressed events to prevent them from being retriggered.
     61 		 * @protected
     62 		 */
     63 		this._supress = {};
     64 
     65 		/**
     66 		 * Absolute current position.
     67 		 * @protected
     68 		 */
     69 		this._current = null;
     70 
     71 		/**
     72 		 * Animation speed in milliseconds.
     73 		 * @protected
     74 		 */
     75 		this._speed = null;
     76 
     77 		/**
     78 		 * Coordinates of all items in pixel.
     79 		 * @todo The name of this member is missleading.
     80 		 * @protected
     81 		 */
     82 		this._coordinates = [];
     83 
     84 		/**
     85 		 * Current breakpoint.
     86 		 * @todo Real media queries would be nice.
     87 		 * @protected
     88 		 */
     89 		this._breakpoint = null;
     90 
     91 		/**
     92 		 * Current width of the plugin element.
     93 		 */
     94 		this._width = null;
     95 
     96 		/**
     97 		 * All real items.
     98 		 * @protected
     99 		 */
    100 		this._items = [];
    101 
    102 		/**
    103 		 * All cloned items.
    104 		 * @protected
    105 		 */
    106 		this._clones = [];
    107 
    108 		/**
    109 		 * Merge values of all items.
    110 		 * @todo Maybe this could be part of a plugin.
    111 		 * @protected
    112 		 */
    113 		this._mergers = [];
    114 
    115 		/**
    116 		 * Widths of all items.
    117 		 */
    118 		this._widths = [];
    119 
    120 		/**
    121 		 * Invalidated parts within the update process.
    122 		 * @protected
    123 		 */
    124 		this._invalidated = {};
    125 
    126 		/**
    127 		 * Ordered list of workers for the update process.
    128 		 * @protected
    129 		 */
    130 		this._pipe = [];
    131 
    132 		/**
    133 		 * Current state information for the drag operation.
    134 		 * @todo #261
    135 		 * @protected
    136 		 */
    137 		this._drag = {
    138 			time: null,
    139 			target: null,
    140 			pointer: null,
    141 			stage: {
    142 				start: null,
    143 				current: null
    144 			},
    145 			direction: null
    146 		};
    147 
    148 		/**
    149 		 * Current state information and their tags.
    150 		 * @type {Object}
    151 		 * @protected
    152 		 */
    153 		this._states = {
    154 			current: {},
    155 			tags: {
    156 				'initializing': [ 'busy' ],
    157 				'animating': [ 'busy' ],
    158 				'dragging': [ 'interacting' ]
    159 			}
    160 		};
    161 
    162 		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
    163 			this._handlers[handler] = $.proxy(this[handler], this);
    164 		}, this));
    165 
    166 		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
    167 			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
    168 				= new plugin(this);
    169 		}, this));
    170 
    171 		$.each(Owl.Workers, $.proxy(function(priority, worker) {
    172 			this._pipe.push({
    173 				'filter': worker.filter,
    174 				'run': $.proxy(worker.run, this)
    175 			});
    176 		}, this));
    177 
    178 		this.setup();
    179 		this.initialize();
    180 	}
    181 
    182 	/**
    183 	 * Default options for the carousel.
    184 	 * @public
    185 	 */
    186 	Owl.Defaults = {
    187 		items: 3,
    188 		loop: false,
    189 		center: false,
    190 		rewind: false,
    191 		checkVisibility: true,
    192 
    193 		mouseDrag: true,
    194 		touchDrag: true,
    195 		pullDrag: true,
    196 		freeDrag: false,
    197 
    198 		margin: 0,
    199 		stagePadding: 0,
    200 
    201 		merge: false,
    202 		mergeFit: true,
    203 		autoWidth: false,
    204 
    205 		startPosition: 0,
    206 		rtl: false,
    207 
    208 		smartSpeed: 250,
    209 		fluidSpeed: false,
    210 		dragEndSpeed: false,
    211 
    212 		responsive: {},
    213 		responsiveRefreshRate: 200,
    214 		responsiveBaseElement: window,
    215 
    216 		fallbackEasing: 'swing',
    217 		slideTransition: '',
    218 
    219 		info: false,
    220 
    221 		nestedItemSelector: false,
    222 		itemElement: 'div',
    223 		stageElement: 'div',
    224 
    225 		refreshClass: 'owl-refresh',
    226 		loadedClass: 'owl-loaded',
    227 		loadingClass: 'owl-loading',
    228 		rtlClass: 'owl-rtl',
    229 		responsiveClass: 'owl-responsive',
    230 		dragClass: 'owl-drag',
    231 		itemClass: 'owl-item',
    232 		stageClass: 'owl-stage',
    233 		stageOuterClass: 'owl-stage-outer',
    234 		grabClass: 'owl-grab'
    235 	};
    236 
    237 	/**
    238 	 * Enumeration for width.
    239 	 * @public
    240 	 * @readonly
    241 	 * @enum {String}
    242 	 */
    243 	Owl.Width = {
    244 		Default: 'default',
    245 		Inner: 'inner',
    246 		Outer: 'outer'
    247 	};
    248 
    249 	/**
    250 	 * Enumeration for types.
    251 	 * @public
    252 	 * @readonly
    253 	 * @enum {String}
    254 	 */
    255 	Owl.Type = {
    256 		Event: 'event',
    257 		State: 'state'
    258 	};
    259 
    260 	/**
    261 	 * Contains all registered plugins.
    262 	 * @public
    263 	 */
    264 	Owl.Plugins = {};
    265 
    266 	/**
    267 	 * List of workers involved in the update process.
    268 	 */
    269 	Owl.Workers = [ {
    270 		filter: [ 'width', 'settings' ],
    271 		run: function() {
    272 			this._width = this.$element.width();
    273 		}
    274 	}, {
    275 		filter: [ 'width', 'items', 'settings' ],
    276 		run: function(cache) {
    277 			cache.current = this._items && this._items[this.relative(this._current)];
    278 		}
    279 	}, {
    280 		filter: [ 'items', 'settings' ],
    281 		run: function() {
    282 			this.$stage.children('.cloned').remove();
    283 		}
    284 	}, {
    285 		filter: [ 'width', 'items', 'settings' ],
    286 		run: function(cache) {
    287 			var margin = this.settings.margin || '',
    288 				grid = !this.settings.autoWidth,
    289 				rtl = this.settings.rtl,
    290 				css = {
    291 					'width': 'auto',
    292 					'margin-left': rtl ? margin : '',
    293 					'margin-right': rtl ? '' : margin
    294 				};
    295 
    296 			!grid && this.$stage.children().css(css);
    297 
    298 			cache.css = css;
    299 		}
    300 	}, {
    301 		filter: [ 'width', 'items', 'settings' ],
    302 		run: function(cache) {
    303 			var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
    304 				merge = null,
    305 				iterator = this._items.length,
    306 				grid = !this.settings.autoWidth,
    307 				widths = [];
    308 
    309 			cache.items = {
    310 				merge: false,
    311 				width: width
    312 			};
    313 
    314 			while (iterator--) {
    315 				merge = this._mergers[iterator];
    316 				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
    317 
    318 				cache.items.merge = merge > 1 || cache.items.merge;
    319 
    320 				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
    321 			}
    322 
    323 			this._widths = widths;
    324 		}
    325 	}, {
    326 		filter: [ 'items', 'settings' ],
    327 		run: function() {
    328 			var clones = [],
    329 				items = this._items,
    330 				settings = this.settings,
    331 				// TODO: Should be computed from number of min width items in stage
    332 				view = Math.max(settings.items * 2, 4),
    333 				size = Math.ceil(items.length / 2) * 2,
    334 				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
    335 				append = '',
    336 				prepend = '';
    337 
    338 			repeat /= 2;
    339 
    340 			while (repeat > 0) {
    341 				// Switch to only using appended clones
    342 				clones.push(this.normalize(clones.length / 2, true));
    343 				append = append + items[clones[clones.length - 1]][0].outerHTML;
    344 				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
    345 				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
    346 				repeat -= 1;
    347 			}
    348 
    349 			this._clones = clones;
    350 
    351 			$(append).addClass('cloned').appendTo(this.$stage);
    352 			$(prepend).addClass('cloned').prependTo(this.$stage);
    353 		}
    354 	}, {
    355 		filter: [ 'width', 'items', 'settings' ],
    356 		run: function() {
    357 			var rtl = this.settings.rtl ? 1 : -1,
    358 				size = this._clones.length + this._items.length,
    359 				iterator = -1,
    360 				previous = 0,
    361 				current = 0,
    362 				coordinates = [];
    363 
    364 			while (++iterator < size) {
    365 				previous = coordinates[iterator - 1] || 0;
    366 				current = this._widths[this.relative(iterator)] + this.settings.margin;
    367 				coordinates.push(previous + current * rtl);
    368 			}
    369 
    370 			this._coordinates = coordinates;
    371 		}
    372 	}, {
    373 		filter: [ 'width', 'items', 'settings' ],
    374 		run: function() {
    375 			var padding = this.settings.stagePadding,
    376 				coordinates = this._coordinates,
    377 				css = {
    378 					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
    379 					'padding-left': padding || '',
    380 					'padding-right': padding || ''
    381 				};
    382 
    383 			this.$stage.css(css);
    384 		}
    385 	}, {
    386 		filter: [ 'width', 'items', 'settings' ],
    387 		run: function(cache) {
    388 			var iterator = this._coordinates.length,
    389 				grid = !this.settings.autoWidth,
    390 				items = this.$stage.children();
    391 
    392 			if (grid && cache.items.merge) {
    393 				while (iterator--) {
    394 					cache.css.width = this._widths[this.relative(iterator)];
    395 					items.eq(iterator).css(cache.css);
    396 				}
    397 			} else if (grid) {
    398 				cache.css.width = cache.items.width;
    399 				items.css(cache.css);
    400 			}
    401 		}
    402 	}, {
    403 		filter: [ 'items' ],
    404 		run: function() {
    405 			this._coordinates.length < 1 && this.$stage.removeAttr('style');
    406 		}
    407 	}, {
    408 		filter: [ 'width', 'items', 'settings' ],
    409 		run: function(cache) {
    410 			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
    411 			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
    412 			this.reset(cache.current);
    413 		}
    414 	}, {
    415 		filter: [ 'position' ],
    416 		run: function() {
    417 			this.animate(this.coordinates(this._current));
    418 		}
    419 	}, {
    420 		filter: [ 'width', 'position', 'items', 'settings' ],
    421 		run: function() {
    422 			var rtl = this.settings.rtl ? 1 : -1,
    423 				padding = this.settings.stagePadding * 2,
    424 				begin = this.coordinates(this.current()) + padding,
    425 				end = begin + this.width() * rtl,
    426 				inner, outer, matches = [], i, n;
    427 
    428 			for (i = 0, n = this._coordinates.length; i < n; i++) {
    429 				inner = this._coordinates[i - 1] || 0;
    430 				outer = Math.abs(this._coordinates[i]) + padding * rtl;
    431 
    432 				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
    433 					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
    434 					matches.push(i);
    435 				}
    436 			}
    437 
    438 			this.$stage.children('.active').removeClass('active');
    439 			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
    440 
    441 			this.$stage.children('.center').removeClass('center');
    442 			if (this.settings.center) {
    443 				this.$stage.children().eq(this.current()).addClass('center');
    444 			}
    445 		}
    446 	} ];
    447 
    448 	/**
    449 	 * Create the stage DOM element
    450 	 */
    451 	Owl.prototype.initializeStage = function() {
    452 		this.$stage = this.$element.find('.' + this.settings.stageClass);
    453 
    454 		// if the stage is already in the DOM, grab it and skip stage initialization
    455 		if (this.$stage.length) {
    456 			return;
    457 		}
    458 
    459 		this.$element.addClass(this.options.loadingClass);
    460 
    461 		// create stage
    462 		this.$stage = $('<' + this.settings.stageElement + '>', {
    463 			"class": this.settings.stageClass
    464 		}).wrap( $( '<div/>', {
    465 			"class": this.settings.stageOuterClass
    466 		}));
    467 
    468 		// append stage
    469 		this.$element.append(this.$stage.parent());
    470 	};
    471 
    472 	/**
    473 	 * Create item DOM elements
    474 	 */
    475 	Owl.prototype.initializeItems = function() {
    476 		var $items = this.$element.find('.owl-item');
    477 
    478 		// if the items are already in the DOM, grab them and skip item initialization
    479 		if ($items.length) {
    480 			this._items = $items.get().map(function(item) {
    481 				return $(item);
    482 			});
    483 
    484 			this._mergers = this._items.map(function() {
    485 				return 1;
    486 			});
    487 
    488 			this.refresh();
    489 
    490 			return;
    491 		}
    492 
    493 		// append content
    494 		this.replace(this.$element.children().not(this.$stage.parent()));
    495 
    496 		// check visibility
    497 		if (this.isVisible()) {
    498 			// update view
    499 			this.refresh();
    500 		} else {
    501 			// invalidate width
    502 			this.invalidate('width');
    503 		}
    504 
    505 		this.$element
    506 			.removeClass(this.options.loadingClass)
    507 			.addClass(this.options.loadedClass);
    508 	};
    509 
    510 	/**
    511 	 * Initializes the carousel.
    512 	 * @protected
    513 	 */
    514 	Owl.prototype.initialize = function() {
    515 		this.enter('initializing');
    516 		this.trigger('initialize');
    517 
    518 		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
    519 
    520 		if (this.settings.autoWidth && !this.is('pre-loading')) {
    521 			var imgs, nestedSelector, width;
    522 			imgs = this.$element.find('img');
    523 			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
    524 			width = this.$element.children(nestedSelector).width();
    525 
    526 			if (imgs.length && width <= 0) {
    527 				this.preloadAutoWidthImages(imgs);
    528 			}
    529 		}
    530 
    531 		this.initializeStage();
    532 		this.initializeItems();
    533 
    534 		// register event handlers
    535 		this.registerEventHandlers();
    536 
    537 		this.leave('initializing');
    538 		this.trigger('initialized');
    539 	};
    540 
    541 	/**
    542 	 * @returns {Boolean} visibility of $element
    543 	 *                    if you know the carousel will always be visible you can set `checkVisibility` to `false` to
    544 	 *                    prevent the expensive browser layout forced reflow the $element.is(':visible') does
    545 	 */
    546 	Owl.prototype.isVisible = function() {
    547 		return this.settings.checkVisibility
    548 			? this.$element.is(':visible')
    549 			: true;
    550 	};
    551 
    552 	/**
    553 	 * Setups the current settings.
    554 	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
    555 	 * @todo Support for media queries by using `matchMedia` would be nice.
    556 	 * @public
    557 	 */
    558 	Owl.prototype.setup = function() {
    559 		var viewport = this.viewport(),
    560 			overwrites = this.options.responsive,
    561 			match = -1,
    562 			settings = null;
    563 
    564 		if (!overwrites) {
    565 			settings = $.extend({}, this.options);
    566 		} else {
    567 			$.each(overwrites, function(breakpoint) {
    568 				if (breakpoint <= viewport && breakpoint > match) {
    569 					match = Number(breakpoint);
    570 				}
    571 			});
    572 
    573 			settings = $.extend({}, this.options, overwrites[match]);
    574 			if (typeof settings.stagePadding === 'function') {
    575 				settings.stagePadding = settings.stagePadding();
    576 			}
    577 			delete settings.responsive;
    578 
    579 			// responsive class
    580 			if (settings.responsiveClass) {
    581 				this.$element.attr('class',
    582 					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
    583 				);
    584 			}
    585 		}
    586 
    587 		this.trigger('change', { property: { name: 'settings', value: settings } });
    588 		this._breakpoint = match;
    589 		this.settings = settings;
    590 		this.invalidate('settings');
    591 		this.trigger('changed', { property: { name: 'settings', value: this.settings } });
    592 	};
    593 
    594 	/**
    595 	 * Updates option logic if necessery.
    596 	 * @protected
    597 	 */
    598 	Owl.prototype.optionsLogic = function() {
    599 		if (this.settings.autoWidth) {
    600 			this.settings.stagePadding = false;
    601 			this.settings.merge = false;
    602 		}
    603 	};
    604 
    605 	/**
    606 	 * Prepares an item before add.
    607 	 * @todo Rename event parameter `content` to `item`.
    608 	 * @protected
    609 	 * @returns {jQuery|HTMLElement} - The item container.
    610 	 */
    611 	Owl.prototype.prepare = function(item) {
    612 		var event = this.trigger('prepare', { content: item });
    613 
    614 		if (!event.data) {
    615 			event.data = $('<' + this.settings.itemElement + '/>')
    616 				.addClass(this.options.itemClass).append(item)
    617 		}
    618 
    619 		this.trigger('prepared', { content: event.data });
    620 
    621 		return event.data;
    622 	};
    623 
    624 	/**
    625 	 * Updates the view.
    626 	 * @public
    627 	 */
    628 	Owl.prototype.update = function() {
    629 		var i = 0,
    630 			n = this._pipe.length,
    631 			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
    632 			cache = {};
    633 
    634 		while (i < n) {
    635 			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
    636 				this._pipe[i].run(cache);
    637 			}
    638 			i++;
    639 		}
    640 
    641 		this._invalidated = {};
    642 
    643 		!this.is('valid') && this.enter('valid');
    644 	};
    645 
    646 	/**
    647 	 * Gets the width of the view.
    648 	 * @public
    649 	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
    650 	 * @returns {Number} - The width of the view in pixel.
    651 	 */
    652 	Owl.prototype.width = function(dimension) {
    653 		dimension = dimension || Owl.Width.Default;
    654 		switch (dimension) {
    655 			case Owl.Width.Inner:
    656 			case Owl.Width.Outer:
    657 				return this._width;
    658 			default:
    659 				return this._width - this.settings.stagePadding * 2 + this.settings.margin;
    660 		}
    661 	};
    662 
    663 	/**
    664 	 * Refreshes the carousel primarily for adaptive purposes.
    665 	 * @public
    666 	 */
    667 	Owl.prototype.refresh = function() {
    668 		this.enter('refreshing');
    669 		this.trigger('refresh');
    670 
    671 		this.setup();
    672 
    673 		this.optionsLogic();
    674 
    675 		this.$element.addClass(this.options.refreshClass);
    676 
    677 		this.update();
    678 
    679 		this.$element.removeClass(this.options.refreshClass);
    680 
    681 		this.leave('refreshing');
    682 		this.trigger('refreshed');
    683 	};
    684 
    685 	/**
    686 	 * Checks window `resize` event.
    687 	 * @protected
    688 	 */
    689 	Owl.prototype.onThrottledResize = function() {
    690 		window.clearTimeout(this.resizeTimer);
    691 		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
    692 	};
    693 
    694 	/**
    695 	 * Checks window `resize` event.
    696 	 * @protected
    697 	 */
    698 	Owl.prototype.onResize = function() {
    699 		if (!this._items.length) {
    700 			return false;
    701 		}
    702 
    703 		if (this._width === this.$element.width()) {
    704 			return false;
    705 		}
    706 
    707 		if (!this.isVisible()) {
    708 			return false;
    709 		}
    710 
    711 		this.enter('resizing');
    712 
    713 		if (this.trigger('resize').isDefaultPrevented()) {
    714 			this.leave('resizing');
    715 			return false;
    716 		}
    717 
    718 		this.invalidate('width');
    719 
    720 		this.refresh();
    721 
    722 		this.leave('resizing');
    723 		this.trigger('resized');
    724 	};
    725 
    726 	/**
    727 	 * Registers event handlers.
    728 	 * @todo Check `msPointerEnabled`
    729 	 * @todo #261
    730 	 * @protected
    731 	 */
    732 	Owl.prototype.registerEventHandlers = function() {
    733 		if ($.support.transition) {
    734 			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
    735 		}
    736 
    737 		if (this.settings.responsive !== false) {
    738 			this.on(window, 'resize', this._handlers.onThrottledResize);
    739 		}
    740 
    741 		if (this.settings.mouseDrag) {
    742 			this.$element.addClass(this.options.dragClass);
    743 			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
    744 			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
    745 		}
    746 
    747 		if (this.settings.touchDrag){
    748 			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
    749 			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
    750 		}
    751 	};
    752 
    753 	/**
    754 	 * Handles `touchstart` and `mousedown` events.
    755 	 * @todo Horizontal swipe threshold as option
    756 	 * @todo #261
    757 	 * @protected
    758 	 * @param {Event} event - The event arguments.
    759 	 */
    760 	Owl.prototype.onDragStart = function(event) {
    761 		var stage = null;
    762 
    763 		if (event.which === 3) {
    764 			return;
    765 		}
    766 
    767 		if ($.support.transform) {
    768 			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
    769 			stage = {
    770 				x: stage[stage.length === 16 ? 12 : 4],
    771 				y: stage[stage.length === 16 ? 13 : 5]
    772 			};
    773 		} else {
    774 			stage = this.$stage.position();
    775 			stage = {
    776 				x: this.settings.rtl ?
    777 					stage.left + this.$stage.width() - this.width() + this.settings.margin :
    778 					stage.left,
    779 				y: stage.top
    780 			};
    781 		}
    782 
    783 		if (this.is('animating')) {
    784 			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
    785 			this.invalidate('position');
    786 		}
    787 
    788 		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
    789 
    790 		this.speed(0);
    791 
    792 		this._drag.time = new Date().getTime();
    793 		this._drag.target = $(event.target);
    794 		this._drag.stage.start = stage;
    795 		this._drag.stage.current = stage;
    796 		this._drag.pointer = this.pointer(event);
    797 
    798 		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
    799 
    800 		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
    801 			var delta = this.difference(this._drag.pointer, this.pointer(event));
    802 
    803 			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
    804 
    805 			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
    806 				return;
    807 			}
    808 
    809 			event.preventDefault();
    810 
    811 			this.enter('dragging');
    812 			this.trigger('drag');
    813 		}, this));
    814 	};
    815 
    816 	/**
    817 	 * Handles the `touchmove` and `mousemove` events.
    818 	 * @todo #261
    819 	 * @protected
    820 	 * @param {Event} event - The event arguments.
    821 	 */
    822 	Owl.prototype.onDragMove = function(event) {
    823 		var minimum = null,
    824 			maximum = null,
    825 			pull = null,
    826 			delta = this.difference(this._drag.pointer, this.pointer(event)),
    827 			stage = this.difference(this._drag.stage.start, delta);
    828 
    829 		if (!this.is('dragging')) {
    830 			return;
    831 		}
    832 
    833 		event.preventDefault();
    834 
    835 		if (this.settings.loop) {
    836 			minimum = this.coordinates(this.minimum());
    837 			maximum = this.coordinates(this.maximum() + 1) - minimum;
    838 			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
    839 		} else {
    840 			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
    841 			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
    842 			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
    843 			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
    844 		}
    845 
    846 		this._drag.stage.current = stage;
    847 
    848 		this.animate(stage.x);
    849 	};
    850 
    851 	/**
    852 	 * Handles the `touchend` and `mouseup` events.
    853 	 * @todo #261
    854 	 * @todo Threshold for click event
    855 	 * @protected
    856 	 * @param {Event} event - The event arguments.
    857 	 */
    858 	Owl.prototype.onDragEnd = function(event) {
    859 		var delta = this.difference(this._drag.pointer, this.pointer(event)),
    860 			stage = this._drag.stage.current,
    861 			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
    862 
    863 		$(document).off('.owl.core');
    864 
    865 		this.$element.removeClass(this.options.grabClass);
    866 
    867 		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
    868 			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
    869 			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
    870 			this.invalidate('position');
    871 			this.update();
    872 
    873 			this._drag.direction = direction;
    874 
    875 			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
    876 				this._drag.target.one('click.owl.core', function() { return false; });
    877 			}
    878 		}
    879 
    880 		if (!this.is('dragging')) {
    881 			return;
    882 		}
    883 
    884 		this.leave('dragging');
    885 		this.trigger('dragged');
    886 	};
    887 
    888 	/**
    889 	 * Gets absolute position of the closest item for a coordinate.
    890 	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
    891 	 * @protected
    892 	 * @param {Number} coordinate - The coordinate in pixel.
    893 	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
    894 	 * @return {Number} - The absolute position of the closest item.
    895 	 */
    896 	Owl.prototype.closest = function(coordinate, direction) {
    897 		var position = -1,
    898 			pull = 30,
    899 			width = this.width(),
    900 			coordinates = this.coordinates();
    901 
    902 		if (!this.settings.freeDrag) {
    903 			// check closest item
    904 			$.each(coordinates, $.proxy(function(index, value) {
    905 				// on a left pull, check on current index
    906 				if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
    907 					position = index;
    908 				// on a right pull, check on previous index
    909 				// to do so, subtract width from value and set position = index + 1
    910 				} else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
    911 					position = index + 1;
    912 				} else if (this.op(coordinate, '<', value)
    913 					&& this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
    914 					position = direction === 'left' ? index + 1 : index;
    915 				}
    916 				return position === -1;
    917 			}, this));
    918 		}
    919 
    920 		if (!this.settings.loop) {
    921 			// non loop boundries
    922 			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
    923 				position = coordinate = this.minimum();
    924 			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
    925 				position = coordinate = this.maximum();
    926 			}
    927 		}
    928 
    929 		return position;
    930 	};
    931 
    932 	/**
    933 	 * Animates the stage.
    934 	 * @todo #270
    935 	 * @public
    936 	 * @param {Number} coordinate - The coordinate in pixels.
    937 	 */
    938 	Owl.prototype.animate = function(coordinate) {
    939 		var animate = this.speed() > 0;
    940 
    941 		this.is('animating') && this.onTransitionEnd();
    942 
    943 		if (animate) {
    944 			this.enter('animating');
    945 			this.trigger('translate');
    946 		}
    947 
    948 		if ($.support.transform3d && $.support.transition) {
    949 			this.$stage.css({
    950 				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
    951 				transition: (this.speed() / 1000) + 's' + (
    952 					this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
    953 				)
    954 			});
    955 		} else if (animate) {
    956 			this.$stage.animate({
    957 				left: coordinate + 'px'
    958 			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
    959 		} else {
    960 			this.$stage.css({
    961 				left: coordinate + 'px'
    962 			});
    963 		}
    964 	};
    965 
    966 	/**
    967 	 * Checks whether the carousel is in a specific state or not.
    968 	 * @param {String} state - The state to check.
    969 	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
    970 	 */
    971 	Owl.prototype.is = function(state) {
    972 		return this._states.current[state] && this._states.current[state] > 0;
    973 	};
    974 
    975 	/**
    976 	 * Sets the absolute position of the current item.
    977 	 * @public
    978 	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
    979 	 * @returns {Number} - The absolute position of the current item.
    980 	 */
    981 	Owl.prototype.current = function(position) {
    982 		if (position === undefined) {
    983 			return this._current;
    984 		}
    985 
    986 		if (this._items.length === 0) {
    987 			return undefined;
    988 		}
    989 
    990 		position = this.normalize(position);
    991 
    992 		if (this._current !== position) {
    993 			var event = this.trigger('change', { property: { name: 'position', value: position } });
    994 
    995 			if (event.data !== undefined) {
    996 				position = this.normalize(event.data);
    997 			}
    998 
    999 			this._current = position;
   1000 
   1001 			this.invalidate('position');
   1002 
   1003 			this.trigger('changed', { property: { name: 'position', value: this._current } });
   1004 		}
   1005 
   1006 		return this._current;
   1007 	};
   1008 
   1009 	/**
   1010 	 * Invalidates the given part of the update routine.
   1011 	 * @param {String} [part] - The part to invalidate.
   1012 	 * @returns {Array.<String>} - The invalidated parts.
   1013 	 */
   1014 	Owl.prototype.invalidate = function(part) {
   1015 		if ($.type(part) === 'string') {
   1016 			this._invalidated[part] = true;
   1017 			this.is('valid') && this.leave('valid');
   1018 		}
   1019 		return $.map(this._invalidated, function(v, i) { return i });
   1020 	};
   1021 
   1022 	/**
   1023 	 * Resets the absolute position of the current item.
   1024 	 * @public
   1025 	 * @param {Number} position - The absolute position of the new item.
   1026 	 */
   1027 	Owl.prototype.reset = function(position) {
   1028 		position = this.normalize(position);
   1029 
   1030 		if (position === undefined) {
   1031 			return;
   1032 		}
   1033 
   1034 		this._speed = 0;
   1035 		this._current = position;
   1036 
   1037 		this.suppress([ 'translate', 'translated' ]);
   1038 
   1039 		this.animate(this.coordinates(position));
   1040 
   1041 		this.release([ 'translate', 'translated' ]);
   1042 	};
   1043 
   1044 	/**
   1045 	 * Normalizes an absolute or a relative position of an item.
   1046 	 * @public
   1047 	 * @param {Number} position - The absolute or relative position to normalize.
   1048 	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
   1049 	 * @returns {Number} - The normalized position.
   1050 	 */
   1051 	Owl.prototype.normalize = function(position, relative) {
   1052 		var n = this._items.length,
   1053 			m = relative ? 0 : this._clones.length;
   1054 
   1055 		if (!this.isNumeric(position) || n < 1) {
   1056 			position = undefined;
   1057 		} else if (position < 0 || position >= n + m) {
   1058 			position = ((position - m / 2) % n + n) % n + m / 2;
   1059 		}
   1060 
   1061 		return position;
   1062 	};
   1063 
   1064 	/**
   1065 	 * Converts an absolute position of an item into a relative one.
   1066 	 * @public
   1067 	 * @param {Number} position - The absolute position to convert.
   1068 	 * @returns {Number} - The converted position.
   1069 	 */
   1070 	Owl.prototype.relative = function(position) {
   1071 		position -= this._clones.length / 2;
   1072 		return this.normalize(position, true);
   1073 	};
   1074 
   1075 	/**
   1076 	 * Gets the maximum position for the current item.
   1077 	 * @public
   1078 	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
   1079 	 * @returns {Number}
   1080 	 */
   1081 	Owl.prototype.maximum = function(relative) {
   1082 		var settings = this.settings,
   1083 			maximum = this._coordinates.length,
   1084 			iterator,
   1085 			reciprocalItemsWidth,
   1086 			elementWidth;
   1087 
   1088 		if (settings.loop) {
   1089 			maximum = this._clones.length / 2 + this._items.length - 1;
   1090 		} else if (settings.autoWidth || settings.merge) {
   1091 			iterator = this._items.length;
   1092 			if (iterator) {
   1093 				reciprocalItemsWidth = this._items[--iterator].width();
   1094 				elementWidth = this.$element.width();
   1095 				while (iterator--) {
   1096 					reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
   1097 					if (reciprocalItemsWidth > elementWidth) {
   1098 						break;
   1099 					}
   1100 				}
   1101 			}
   1102 			maximum = iterator + 1;
   1103 		} else if (settings.center) {
   1104 			maximum = this._items.length - 1;
   1105 		} else {
   1106 			maximum = this._items.length - settings.items;
   1107 		}
   1108 
   1109 		if (relative) {
   1110 			maximum -= this._clones.length / 2;
   1111 		}
   1112 
   1113 		return Math.max(maximum, 0);
   1114 	};
   1115 
   1116 	/**
   1117 	 * Gets the minimum position for the current item.
   1118 	 * @public
   1119 	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
   1120 	 * @returns {Number}
   1121 	 */
   1122 	Owl.prototype.minimum = function(relative) {
   1123 		return relative ? 0 : this._clones.length / 2;
   1124 	};
   1125 
   1126 	/**
   1127 	 * Gets an item at the specified relative position.
   1128 	 * @public
   1129 	 * @param {Number} [position] - The relative position of the item.
   1130 	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
   1131 	 */
   1132 	Owl.prototype.items = function(position) {
   1133 		if (position === undefined) {
   1134 			return this._items.slice();
   1135 		}
   1136 
   1137 		position = this.normalize(position, true);
   1138 		return this._items[position];
   1139 	};
   1140 
   1141 	/**
   1142 	 * Gets an item at the specified relative position.
   1143 	 * @public
   1144 	 * @param {Number} [position] - The relative position of the item.
   1145 	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
   1146 	 */
   1147 	Owl.prototype.mergers = function(position) {
   1148 		if (position === undefined) {
   1149 			return this._mergers.slice();
   1150 		}
   1151 
   1152 		position = this.normalize(position, true);
   1153 		return this._mergers[position];
   1154 	};
   1155 
   1156 	/**
   1157 	 * Gets the absolute positions of clones for an item.
   1158 	 * @public
   1159 	 * @param {Number} [position] - The relative position of the item.
   1160 	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
   1161 	 */
   1162 	Owl.prototype.clones = function(position) {
   1163 		var odd = this._clones.length / 2,
   1164 			even = odd + this._items.length,
   1165 			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
   1166 
   1167 		if (position === undefined) {
   1168 			return $.map(this._clones, function(v, i) { return map(i) });
   1169 		}
   1170 
   1171 		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
   1172 	};
   1173 
   1174 	/**
   1175 	 * Sets the current animation speed.
   1176 	 * @public
   1177 	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
   1178 	 * @returns {Number} - The current animation speed in milliseconds.
   1179 	 */
   1180 	Owl.prototype.speed = function(speed) {
   1181 		if (speed !== undefined) {
   1182 			this._speed = speed;
   1183 		}
   1184 
   1185 		return this._speed;
   1186 	};
   1187 
   1188 	/**
   1189 	 * Gets the coordinate of an item.
   1190 	 * @todo The name of this method is missleanding.
   1191 	 * @public
   1192 	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
   1193 	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
   1194 	 */
   1195 	Owl.prototype.coordinates = function(position) {
   1196 		var multiplier = 1,
   1197 			newPosition = position - 1,
   1198 			coordinate;
   1199 
   1200 		if (position === undefined) {
   1201 			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
   1202 				return this.coordinates(index);
   1203 			}, this));
   1204 		}
   1205 
   1206 		if (this.settings.center) {
   1207 			if (this.settings.rtl) {
   1208 				multiplier = -1;
   1209 				newPosition = position + 1;
   1210 			}
   1211 
   1212 			coordinate = this._coordinates[position];
   1213 			coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
   1214 		} else {
   1215 			coordinate = this._coordinates[newPosition] || 0;
   1216 		}
   1217 
   1218 		coordinate = Math.ceil(coordinate);
   1219 
   1220 		return coordinate;
   1221 	};
   1222 
   1223 	/**
   1224 	 * Calculates the speed for a translation.
   1225 	 * @protected
   1226 	 * @param {Number} from - The absolute position of the start item.
   1227 	 * @param {Number} to - The absolute position of the target item.
   1228 	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
   1229 	 * @returns {Number} - The time in milliseconds for the translation.
   1230 	 */
   1231 	Owl.prototype.duration = function(from, to, factor) {
   1232 		if (factor === 0) {
   1233 			return 0;
   1234 		}
   1235 
   1236 		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
   1237 	};
   1238 
   1239 	/**
   1240 	 * Slides to the specified item.
   1241 	 * @public
   1242 	 * @param {Number} position - The position of the item.
   1243 	 * @param {Number} [speed] - The time in milliseconds for the transition.
   1244 	 */
   1245 	Owl.prototype.to = function(position, speed) {
   1246 		var current = this.current(),
   1247 			revert = null,
   1248 			distance = position - this.relative(current),
   1249 			direction = (distance > 0) - (distance < 0),
   1250 			items = this._items.length,
   1251 			minimum = this.minimum(),
   1252 			maximum = this.maximum();
   1253 
   1254 		if (this.settings.loop) {
   1255 			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
   1256 				distance += direction * -1 * items;
   1257 			}
   1258 
   1259 			position = current + distance;
   1260 			revert = ((position - minimum) % items + items) % items + minimum;
   1261 
   1262 			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
   1263 				current = revert - distance;
   1264 				position = revert;
   1265 				this.reset(current);
   1266 			}
   1267 		} else if (this.settings.rewind) {
   1268 			maximum += 1;
   1269 			position = (position % maximum + maximum) % maximum;
   1270 		} else {
   1271 			position = Math.max(minimum, Math.min(maximum, position));
   1272 		}
   1273 
   1274 		this.speed(this.duration(current, position, speed));
   1275 		this.current(position);
   1276 
   1277 		if (this.isVisible()) {
   1278 			this.update();
   1279 		}
   1280 	};
   1281 
   1282 	/**
   1283 	 * Slides to the next item.
   1284 	 * @public
   1285 	 * @param {Number} [speed] - The time in milliseconds for the transition.
   1286 	 */
   1287 	Owl.prototype.next = function(speed) {
   1288 		speed = speed || false;
   1289 		this.to(this.relative(this.current()) + 1, speed);
   1290 	};
   1291 
   1292 	/**
   1293 	 * Slides to the previous item.
   1294 	 * @public
   1295 	 * @param {Number} [speed] - The time in milliseconds for the transition.
   1296 	 */
   1297 	Owl.prototype.prev = function(speed) {
   1298 		speed = speed || false;
   1299 		this.to(this.relative(this.current()) - 1, speed);
   1300 	};
   1301 
   1302 	/**
   1303 	 * Handles the end of an animation.
   1304 	 * @protected
   1305 	 * @param {Event} event - The event arguments.
   1306 	 */
   1307 	Owl.prototype.onTransitionEnd = function(event) {
   1308 
   1309 		// if css2 animation then event object is undefined
   1310 		if (event !== undefined) {
   1311 			event.stopPropagation();
   1312 
   1313 			// Catch only owl-stage transitionEnd event
   1314 			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
   1315 				return false;
   1316 			}
   1317 		}
   1318 
   1319 		this.leave('animating');
   1320 		this.trigger('translated');
   1321 	};
   1322 
   1323 	/**
   1324 	 * Gets viewport width.
   1325 	 * @protected
   1326 	 * @return {Number} - The width in pixel.
   1327 	 */
   1328 	Owl.prototype.viewport = function() {
   1329 		var width;
   1330 		if (this.options.responsiveBaseElement !== window) {
   1331 			width = $(this.options.responsiveBaseElement).width();
   1332 		} else if (window.innerWidth) {
   1333 			width = window.innerWidth;
   1334 		} else if (document.documentElement && document.documentElement.clientWidth) {
   1335 			width = document.documentElement.clientWidth;
   1336 		} else {
   1337 			console.warn('Can not detect viewport width.');
   1338 		}
   1339 		return width;
   1340 	};
   1341 
   1342 	/**
   1343 	 * Replaces the current content.
   1344 	 * @public
   1345 	 * @param {HTMLElement|jQuery|String} content - The new content.
   1346 	 */
   1347 	Owl.prototype.replace = function(content) {
   1348 		this.$stage.empty();
   1349 		this._items = [];
   1350 
   1351 		if (content) {
   1352 			content = (content instanceof jQuery) ? content : $(content);
   1353 		}
   1354 
   1355 		if (this.settings.nestedItemSelector) {
   1356 			content = content.find('.' + this.settings.nestedItemSelector);
   1357 		}
   1358 
   1359 		content.filter(function() {
   1360 			return this.nodeType === 1;
   1361 		}).each($.proxy(function(index, item) {
   1362 			item = this.prepare(item);
   1363 			this.$stage.append(item);
   1364 			this._items.push(item);
   1365 			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
   1366 		}, this));
   1367 
   1368 		this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
   1369 
   1370 		this.invalidate('items');
   1371 	};
   1372 
   1373 	/**
   1374 	 * Adds an item.
   1375 	 * @todo Use `item` instead of `content` for the event arguments.
   1376 	 * @public
   1377 	 * @param {HTMLElement|jQuery|String} content - The item content to add.
   1378 	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
   1379 	 */
   1380 	Owl.prototype.add = function(content, position) {
   1381 		var current = this.relative(this._current);
   1382 
   1383 		position = position === undefined ? this._items.length : this.normalize(position, true);
   1384 		content = content instanceof jQuery ? content : $(content);
   1385 
   1386 		this.trigger('add', { content: content, position: position });
   1387 
   1388 		content = this.prepare(content);
   1389 
   1390 		if (this._items.length === 0 || position === this._items.length) {
   1391 			this._items.length === 0 && this.$stage.append(content);
   1392 			this._items.length !== 0 && this._items[position - 1].after(content);
   1393 			this._items.push(content);
   1394 			this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
   1395 		} else {
   1396 			this._items[position].before(content);
   1397 			this._items.splice(position, 0, content);
   1398 			this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
   1399 		}
   1400 
   1401 		this._items[current] && this.reset(this._items[current].index());
   1402 
   1403 		this.invalidate('items');
   1404 
   1405 		this.trigger('added', { content: content, position: position });
   1406 	};
   1407 
   1408 	/**
   1409 	 * Removes an item by its position.
   1410 	 * @todo Use `item` instead of `content` for the event arguments.
   1411 	 * @public
   1412 	 * @param {Number} position - The relative position of the item to remove.
   1413 	 */
   1414 	Owl.prototype.remove = function(position) {
   1415 		position = this.normalize(position, true);
   1416 
   1417 		if (position === undefined) {
   1418 			return;
   1419 		}
   1420 
   1421 		this.trigger('remove', { content: this._items[position], position: position });
   1422 
   1423 		this._items[position].remove();
   1424 		this._items.splice(position, 1);
   1425 		this._mergers.splice(position, 1);
   1426 
   1427 		this.invalidate('items');
   1428 
   1429 		this.trigger('removed', { content: null, position: position });
   1430 	};
   1431 
   1432 	/**
   1433 	 * Preloads images with auto width.
   1434 	 * @todo Replace by a more generic approach
   1435 	 * @protected
   1436 	 */
   1437 	Owl.prototype.preloadAutoWidthImages = function(images) {
   1438 		images.each($.proxy(function(i, element) {
   1439 			this.enter('pre-loading');
   1440 			element = $(element);
   1441 			$(new Image()).one('load', $.proxy(function(e) {
   1442 				element.attr('src', e.target.src);
   1443 				element.css('opacity', 1);
   1444 				this.leave('pre-loading');
   1445 				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
   1446 			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
   1447 		}, this));
   1448 	};
   1449 
   1450 	/**
   1451 	 * Destroys the carousel.
   1452 	 * @public
   1453 	 */
   1454 	Owl.prototype.destroy = function() {
   1455 
   1456 		this.$element.off('.owl.core');
   1457 		this.$stage.off('.owl.core');
   1458 		$(document).off('.owl.core');
   1459 
   1460 		if (this.settings.responsive !== false) {
   1461 			window.clearTimeout(this.resizeTimer);
   1462 			this.off(window, 'resize', this._handlers.onThrottledResize);
   1463 		}
   1464 
   1465 		for (var i in this._plugins) {
   1466 			this._plugins[i].destroy();
   1467 		}
   1468 
   1469 		this.$stage.children('.cloned').remove();
   1470 
   1471 		this.$stage.unwrap();
   1472 		this.$stage.children().contents().unwrap();
   1473 		this.$stage.children().unwrap();
   1474 		this.$stage.remove();
   1475 		this.$element
   1476 			.removeClass(this.options.refreshClass)
   1477 			.removeClass(this.options.loadingClass)
   1478 			.removeClass(this.options.loadedClass)
   1479 			.removeClass(this.options.rtlClass)
   1480 			.removeClass(this.options.dragClass)
   1481 			.removeClass(this.options.grabClass)
   1482 			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
   1483 			.removeData('owl.carousel');
   1484 	};
   1485 
   1486 	/**
   1487 	 * Operators to calculate right-to-left and left-to-right.
   1488 	 * @protected
   1489 	 * @param {Number} [a] - The left side operand.
   1490 	 * @param {String} [o] - The operator.
   1491 	 * @param {Number} [b] - The right side operand.
   1492 	 */
   1493 	Owl.prototype.op = function(a, o, b) {
   1494 		var rtl = this.settings.rtl;
   1495 		switch (o) {
   1496 			case '<':
   1497 				return rtl ? a > b : a < b;
   1498 			case '>':
   1499 				return rtl ? a < b : a > b;
   1500 			case '>=':
   1501 				return rtl ? a <= b : a >= b;
   1502 			case '<=':
   1503 				return rtl ? a >= b : a <= b;
   1504 			default:
   1505 				break;
   1506 		}
   1507 	};
   1508 
   1509 	/**
   1510 	 * Attaches to an internal event.
   1511 	 * @protected
   1512 	 * @param {HTMLElement} element - The event source.
   1513 	 * @param {String} event - The event name.
   1514 	 * @param {Function} listener - The event handler to attach.
   1515 	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
   1516 	 */
   1517 	Owl.prototype.on = function(element, event, listener, capture) {
   1518 		if (element.addEventListener) {
   1519 			element.addEventListener(event, listener, capture);
   1520 		} else if (element.attachEvent) {
   1521 			element.attachEvent('on' + event, listener);
   1522 		}
   1523 	};
   1524 
   1525 	/**
   1526 	 * Detaches from an internal event.
   1527 	 * @protected
   1528 	 * @param {HTMLElement} element - The event source.
   1529 	 * @param {String} event - The event name.
   1530 	 * @param {Function} listener - The attached event handler to detach.
   1531 	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
   1532 	 */
   1533 	Owl.prototype.off = function(element, event, listener, capture) {
   1534 		if (element.removeEventListener) {
   1535 			element.removeEventListener(event, listener, capture);
   1536 		} else if (element.detachEvent) {
   1537 			element.detachEvent('on' + event, listener);
   1538 		}
   1539 	};
   1540 
   1541 	/**
   1542 	 * Triggers a public event.
   1543 	 * @todo Remove `status`, `relatedTarget` should be used instead.
   1544 	 * @protected
   1545 	 * @param {String} name - The event name.
   1546 	 * @param {*} [data=null] - The event data.
   1547 	 * @param {String} [namespace=carousel] - The event namespace.
   1548 	 * @param {String} [state] - The state which is associated with the event.
   1549 	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
   1550 	 * @returns {Event} - The event arguments.
   1551 	 */
   1552 	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
   1553 		var status = {
   1554 			item: { count: this._items.length, index: this.current() }
   1555 		}, handler = $.camelCase(
   1556 			$.grep([ 'on', name, namespace ], function(v) { return v })
   1557 				.join('-').toLowerCase()
   1558 		), event = $.Event(
   1559 			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
   1560 			$.extend({ relatedTarget: this }, status, data)
   1561 		);
   1562 
   1563 		if (!this._supress[name]) {
   1564 			$.each(this._plugins, function(name, plugin) {
   1565 				if (plugin.onTrigger) {
   1566 					plugin.onTrigger(event);
   1567 				}
   1568 			});
   1569 
   1570 			this.register({ type: Owl.Type.Event, name: name });
   1571 			this.$element.trigger(event);
   1572 
   1573 			if (this.settings && typeof this.settings[handler] === 'function') {
   1574 				this.settings[handler].call(this, event);
   1575 			}
   1576 		}
   1577 
   1578 		return event;
   1579 	};
   1580 
   1581 	/**
   1582 	 * Enters a state.
   1583 	 * @param name - The state name.
   1584 	 */
   1585 	Owl.prototype.enter = function(name) {
   1586 		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
   1587 			if (this._states.current[name] === undefined) {
   1588 				this._states.current[name] = 0;
   1589 			}
   1590 
   1591 			this._states.current[name]++;
   1592 		}, this));
   1593 	};
   1594 
   1595 	/**
   1596 	 * Leaves a state.
   1597 	 * @param name - The state name.
   1598 	 */
   1599 	Owl.prototype.leave = function(name) {
   1600 		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
   1601 			this._states.current[name]--;
   1602 		}, this));
   1603 	};
   1604 
   1605 	/**
   1606 	 * Registers an event or state.
   1607 	 * @public
   1608 	 * @param {Object} object - The event or state to register.
   1609 	 */
   1610 	Owl.prototype.register = function(object) {
   1611 		if (object.type === Owl.Type.Event) {
   1612 			if (!$.event.special[object.name]) {
   1613 				$.event.special[object.name] = {};
   1614 			}
   1615 
   1616 			if (!$.event.special[object.name].owl) {
   1617 				var _default = $.event.special[object.name]._default;
   1618 				$.event.special[object.name]._default = function(e) {
   1619 					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
   1620 						return _default.apply(this, arguments);
   1621 					}
   1622 					return e.namespace && e.namespace.indexOf('owl') > -1;
   1623 				};
   1624 				$.event.special[object.name].owl = true;
   1625 			}
   1626 		} else if (object.type === Owl.Type.State) {
   1627 			if (!this._states.tags[object.name]) {
   1628 				this._states.tags[object.name] = object.tags;
   1629 			} else {
   1630 				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
   1631 			}
   1632 
   1633 			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
   1634 				return $.inArray(tag, this._states.tags[object.name]) === i;
   1635 			}, this));
   1636 		}
   1637 	};
   1638 
   1639 	/**
   1640 	 * Suppresses events.
   1641 	 * @protected
   1642 	 * @param {Array.<String>} events - The events to suppress.
   1643 	 */
   1644 	Owl.prototype.suppress = function(events) {
   1645 		$.each(events, $.proxy(function(index, event) {
   1646 			this._supress[event] = true;
   1647 		}, this));
   1648 	};
   1649 
   1650 	/**
   1651 	 * Releases suppressed events.
   1652 	 * @protected
   1653 	 * @param {Array.<String>} events - The events to release.
   1654 	 */
   1655 	Owl.prototype.release = function(events) {
   1656 		$.each(events, $.proxy(function(index, event) {
   1657 			delete this._supress[event];
   1658 		}, this));
   1659 	};
   1660 
   1661 	/**
   1662 	 * Gets unified pointer coordinates from event.
   1663 	 * @todo #261
   1664 	 * @protected
   1665 	 * @param {Event} - The `mousedown` or `touchstart` event.
   1666 	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
   1667 	 */
   1668 	Owl.prototype.pointer = function(event) {
   1669 		var result = { x: null, y: null };
   1670 
   1671 		event = event.originalEvent || event || window.event;
   1672 
   1673 		event = event.touches && event.touches.length ?
   1674 			event.touches[0] : event.changedTouches && event.changedTouches.length ?
   1675 				event.changedTouches[0] : event;
   1676 
   1677 		if (event.pageX) {
   1678 			result.x = event.pageX;
   1679 			result.y = event.pageY;
   1680 		} else {
   1681 			result.x = event.clientX;
   1682 			result.y = event.clientY;
   1683 		}
   1684 
   1685 		return result;
   1686 	};
   1687 
   1688 	/**
   1689 	 * Determines if the input is a Number or something that can be coerced to a Number
   1690 	 * @protected
   1691 	 * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
   1692 	 * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
   1693 	 */
   1694 	Owl.prototype.isNumeric = function(number) {
   1695 		return !isNaN(parseFloat(number));
   1696 	};
   1697 
   1698 	/**
   1699 	 * Gets the difference of two vectors.
   1700 	 * @todo #261
   1701 	 * @protected
   1702 	 * @param {Object} - The first vector.
   1703 	 * @param {Object} - The second vector.
   1704 	 * @returns {Object} - The difference.
   1705 	 */
   1706 	Owl.prototype.difference = function(first, second) {
   1707 		return {
   1708 			x: first.x - second.x,
   1709 			y: first.y - second.y
   1710 		};
   1711 	};
   1712 
   1713 	/**
   1714 	 * The jQuery Plugin for the Owl Carousel
   1715 	 * @todo Navigation plugin `next` and `prev`
   1716 	 * @public
   1717 	 */
   1718 	$.fn.owlCarousel = function(option) {
   1719 		var args = Array.prototype.slice.call(arguments, 1);
   1720 
   1721 		return this.each(function() {
   1722 			var $this = $(this),
   1723 				data = $this.data('owl.carousel');
   1724 
   1725 			if (!data) {
   1726 				data = new Owl(this, typeof option == 'object' && option);
   1727 				$this.data('owl.carousel', data);
   1728 
   1729 				$.each([
   1730 					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
   1731 				], function(i, event) {
   1732 					data.register({ type: Owl.Type.Event, name: event });
   1733 					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
   1734 						if (e.namespace && e.relatedTarget !== this) {
   1735 							this.suppress([ event ]);
   1736 							data[event].apply(this, [].slice.call(arguments, 1));
   1737 							this.release([ event ]);
   1738 						}
   1739 					}, data));
   1740 				});
   1741 			}
   1742 
   1743 			if (typeof option == 'string' && option.charAt(0) !== '_') {
   1744 				data[option].apply(data, args);
   1745 			}
   1746 		});
   1747 	};
   1748 
   1749 	/**
   1750 	 * The constructor for the jQuery Plugin
   1751 	 * @public
   1752 	 */
   1753 	$.fn.owlCarousel.Constructor = Owl;
   1754 
   1755 })(window.Zepto || window.jQuery, window, document);
   1756 
   1757 /**
   1758  * AutoRefresh Plugin
   1759  * @version 2.3.4
   1760  * @author Artus Kolanowski
   1761  * @author David Deutsch
   1762  * @license The MIT License (MIT)
   1763  */
   1764 ;(function($, window, document, undefined) {
   1765 
   1766 	/**
   1767 	 * Creates the auto refresh plugin.
   1768 	 * @class The Auto Refresh Plugin
   1769 	 * @param {Owl} carousel - The Owl Carousel
   1770 	 */
   1771 	var AutoRefresh = function(carousel) {
   1772 		/**
   1773 		 * Reference to the core.
   1774 		 * @protected
   1775 		 * @type {Owl}
   1776 		 */
   1777 		this._core = carousel;
   1778 
   1779 		/**
   1780 		 * Refresh interval.
   1781 		 * @protected
   1782 		 * @type {number}
   1783 		 */
   1784 		this._interval = null;
   1785 
   1786 		/**
   1787 		 * Whether the element is currently visible or not.
   1788 		 * @protected
   1789 		 * @type {Boolean}
   1790 		 */
   1791 		this._visible = null;
   1792 
   1793 		/**
   1794 		 * All event handlers.
   1795 		 * @protected
   1796 		 * @type {Object}
   1797 		 */
   1798 		this._handlers = {
   1799 			'initialized.owl.carousel': $.proxy(function(e) {
   1800 				if (e.namespace && this._core.settings.autoRefresh) {
   1801 					this.watch();
   1802 				}
   1803 			}, this)
   1804 		};
   1805 
   1806 		// set default options
   1807 		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
   1808 
   1809 		// register event handlers
   1810 		this._core.$element.on(this._handlers);
   1811 	};
   1812 
   1813 	/**
   1814 	 * Default options.
   1815 	 * @public
   1816 	 */
   1817 	AutoRefresh.Defaults = {
   1818 		autoRefresh: true,
   1819 		autoRefreshInterval: 500
   1820 	};
   1821 
   1822 	/**
   1823 	 * Watches the element.
   1824 	 */
   1825 	AutoRefresh.prototype.watch = function() {
   1826 		if (this._interval) {
   1827 			return;
   1828 		}
   1829 
   1830 		this._visible = this._core.isVisible();
   1831 		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
   1832 	};
   1833 
   1834 	/**
   1835 	 * Refreshes the element.
   1836 	 */
   1837 	AutoRefresh.prototype.refresh = function() {
   1838 		if (this._core.isVisible() === this._visible) {
   1839 			return;
   1840 		}
   1841 
   1842 		this._visible = !this._visible;
   1843 
   1844 		this._core.$element.toggleClass('owl-hidden', !this._visible);
   1845 
   1846 		this._visible && (this._core.invalidate('width') && this._core.refresh());
   1847 	};
   1848 
   1849 	/**
   1850 	 * Destroys the plugin.
   1851 	 */
   1852 	AutoRefresh.prototype.destroy = function() {
   1853 		var handler, property;
   1854 
   1855 		window.clearInterval(this._interval);
   1856 
   1857 		for (handler in this._handlers) {
   1858 			this._core.$element.off(handler, this._handlers[handler]);
   1859 		}
   1860 		for (property in Object.getOwnPropertyNames(this)) {
   1861 			typeof this[property] != 'function' && (this[property] = null);
   1862 		}
   1863 	};
   1864 
   1865 	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
   1866 
   1867 })(window.Zepto || window.jQuery, window, document);
   1868 
   1869 /**
   1870  * Lazy Plugin
   1871  * @version 2.3.4
   1872  * @author Bartosz Wojciechowski
   1873  * @author David Deutsch
   1874  * @license The MIT License (MIT)
   1875  */
   1876 ;(function($, window, document, undefined) {
   1877 
   1878 	/**
   1879 	 * Creates the lazy plugin.
   1880 	 * @class The Lazy Plugin
   1881 	 * @param {Owl} carousel - The Owl Carousel
   1882 	 */
   1883 	var Lazy = function(carousel) {
   1884 
   1885 		/**
   1886 		 * Reference to the core.
   1887 		 * @protected
   1888 		 * @type {Owl}
   1889 		 */
   1890 		this._core = carousel;
   1891 
   1892 		/**
   1893 		 * Already loaded items.
   1894 		 * @protected
   1895 		 * @type {Array.<jQuery>}
   1896 		 */
   1897 		this._loaded = [];
   1898 
   1899 		/**
   1900 		 * Event handlers.
   1901 		 * @protected
   1902 		 * @type {Object}
   1903 		 */
   1904 		this._handlers = {
   1905 			'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
   1906 				if (!e.namespace) {
   1907 					return;
   1908 				}
   1909 
   1910 				if (!this._core.settings || !this._core.settings.lazyLoad) {
   1911 					return;
   1912 				}
   1913 
   1914 				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
   1915 					var settings = this._core.settings,
   1916 						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
   1917 						i = ((settings.center && n * -1) || 0),
   1918 						position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
   1919 						clones = this._core.clones().length,
   1920 						load = $.proxy(function(i, v) { this.load(v) }, this);
   1921 					//TODO: Need documentation for this new option
   1922 					if (settings.lazyLoadEager > 0) {
   1923 						n += settings.lazyLoadEager;
   1924 						// If the carousel is looping also preload images that are to the "left"
   1925 						if (settings.loop) {
   1926               position -= settings.lazyLoadEager;
   1927               n++;
   1928             }
   1929 					}
   1930 
   1931 					while (i++ < n) {
   1932 						this.load(clones / 2 + this._core.relative(position));
   1933 						clones && $.each(this._core.clones(this._core.relative(position)), load);
   1934 						position++;
   1935 					}
   1936 				}
   1937 			}, this)
   1938 		};
   1939 
   1940 		// set the default options
   1941 		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
   1942 
   1943 		// register event handler
   1944 		this._core.$element.on(this._handlers);
   1945 	};
   1946 
   1947 	/**
   1948 	 * Default options.
   1949 	 * @public
   1950 	 */
   1951 	Lazy.Defaults = {
   1952 		lazyLoad: false,
   1953 		lazyLoadEager: 0
   1954 	};
   1955 
   1956 	/**
   1957 	 * Loads all resources of an item at the specified position.
   1958 	 * @param {Number} position - The absolute position of the item.
   1959 	 * @protected
   1960 	 */
   1961 	Lazy.prototype.load = function(position) {
   1962 		var $item = this._core.$stage.children().eq(position),
   1963 			$elements = $item && $item.find('.owl-lazy');
   1964 
   1965 		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
   1966 			return;
   1967 		}
   1968 
   1969 		$elements.each($.proxy(function(index, element) {
   1970 			var $element = $(element), image,
   1971                 url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset');
   1972 
   1973 			this._core.trigger('load', { element: $element, url: url }, 'lazy');
   1974 
   1975 			if ($element.is('img')) {
   1976 				$element.one('load.owl.lazy', $.proxy(function() {
   1977 					$element.css('opacity', 1);
   1978 					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
   1979 				}, this)).attr('src', url);
   1980             } else if ($element.is('source')) {
   1981                 $element.one('load.owl.lazy', $.proxy(function() {
   1982                     this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
   1983                 }, this)).attr('srcset', url);
   1984 			} else {
   1985 				image = new Image();
   1986 				image.onload = $.proxy(function() {
   1987 					$element.css({
   1988 						'background-image': 'url("' + url + '")',
   1989 						'opacity': '1'
   1990 					});
   1991 					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
   1992 				}, this);
   1993 				image.src = url;
   1994 			}
   1995 		}, this));
   1996 
   1997 		this._loaded.push($item.get(0));
   1998 	};
   1999 
   2000 	/**
   2001 	 * Destroys the plugin.
   2002 	 * @public
   2003 	 */
   2004 	Lazy.prototype.destroy = function() {
   2005 		var handler, property;
   2006 
   2007 		for (handler in this.handlers) {
   2008 			this._core.$element.off(handler, this.handlers[handler]);
   2009 		}
   2010 		for (property in Object.getOwnPropertyNames(this)) {
   2011 			typeof this[property] != 'function' && (this[property] = null);
   2012 		}
   2013 	};
   2014 
   2015 	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
   2016 
   2017 })(window.Zepto || window.jQuery, window, document);
   2018 
   2019 /**
   2020  * AutoHeight Plugin
   2021  * @version 2.3.4
   2022  * @author Bartosz Wojciechowski
   2023  * @author David Deutsch
   2024  * @license The MIT License (MIT)
   2025  */
   2026 ;(function($, window, document, undefined) {
   2027 
   2028 	/**
   2029 	 * Creates the auto height plugin.
   2030 	 * @class The Auto Height Plugin
   2031 	 * @param {Owl} carousel - The Owl Carousel
   2032 	 */
   2033 	var AutoHeight = function(carousel) {
   2034 		/**
   2035 		 * Reference to the core.
   2036 		 * @protected
   2037 		 * @type {Owl}
   2038 		 */
   2039 		this._core = carousel;
   2040 
   2041 		this._previousHeight = null;
   2042 
   2043 		/**
   2044 		 * All event handlers.
   2045 		 * @protected
   2046 		 * @type {Object}
   2047 		 */
   2048 		this._handlers = {
   2049 			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
   2050 				if (e.namespace && this._core.settings.autoHeight) {
   2051 					this.update();
   2052 				}
   2053 			}, this),
   2054 			'changed.owl.carousel': $.proxy(function(e) {
   2055 				if (e.namespace && this._core.settings.autoHeight && e.property.name === 'position'){
   2056 					this.update();
   2057 				}
   2058 			}, this),
   2059 			'loaded.owl.lazy': $.proxy(function(e) {
   2060 				if (e.namespace && this._core.settings.autoHeight
   2061 					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
   2062 					this.update();
   2063 				}
   2064 			}, this)
   2065 		};
   2066 
   2067 		// set default options
   2068 		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
   2069 
   2070 		// register event handlers
   2071 		this._core.$element.on(this._handlers);
   2072 		this._intervalId = null;
   2073 		var refThis = this;
   2074 
   2075 		// These changes have been taken from a PR by gavrochelegnou proposed in #1575
   2076 		// and have been made compatible with the latest jQuery version
   2077 		$(window).on('load', function() {
   2078 			if (refThis._core.settings.autoHeight) {
   2079 				refThis.update();
   2080 			}
   2081 		});
   2082 
   2083 		// Autoresize the height of the carousel when window is resized
   2084 		// When carousel has images, the height is dependent on the width
   2085 		// and should also change on resize
   2086 		$(window).resize(function() {
   2087 			if (refThis._core.settings.autoHeight) {
   2088 				if (refThis._intervalId != null) {
   2089 					clearTimeout(refThis._intervalId);
   2090 				}
   2091 
   2092 				refThis._intervalId = setTimeout(function() {
   2093 					refThis.update();
   2094 				}, 250);
   2095 			}
   2096 		});
   2097 
   2098 	};
   2099 
   2100 	/**
   2101 	 * Default options.
   2102 	 * @public
   2103 	 */
   2104 	AutoHeight.Defaults = {
   2105 		autoHeight: false,
   2106 		autoHeightClass: 'owl-height'
   2107 	};
   2108 
   2109 	/**
   2110 	 * Updates the view.
   2111 	 */
   2112 	AutoHeight.prototype.update = function() {
   2113 		var start = this._core._current,
   2114 			end = start + this._core.settings.items,
   2115 			lazyLoadEnabled = this._core.settings.lazyLoad,
   2116 			visible = this._core.$stage.children().toArray().slice(start, end),
   2117 			heights = [],
   2118 			maxheight = 0;
   2119 
   2120 		$.each(visible, function(index, item) {
   2121 			heights.push($(item).height());
   2122 		});
   2123 
   2124 		maxheight = Math.max.apply(null, heights);
   2125 
   2126 		if (maxheight <= 1 && lazyLoadEnabled && this._previousHeight) {
   2127 			maxheight = this._previousHeight;
   2128 		}
   2129 
   2130 		this._previousHeight = maxheight;
   2131 
   2132 		this._core.$stage.parent()
   2133 			.height(maxheight)
   2134 			.addClass(this._core.settings.autoHeightClass);
   2135 	};
   2136 
   2137 	AutoHeight.prototype.destroy = function() {
   2138 		var handler, property;
   2139 
   2140 		for (handler in this._handlers) {
   2141 			this._core.$element.off(handler, this._handlers[handler]);
   2142 		}
   2143 		for (property in Object.getOwnPropertyNames(this)) {
   2144 			typeof this[property] !== 'function' && (this[property] = null);
   2145 		}
   2146 	};
   2147 
   2148 	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
   2149 
   2150 })(window.Zepto || window.jQuery, window, document);
   2151 
   2152 /**
   2153  * Video Plugin
   2154  * @version 2.3.4
   2155  * @author Bartosz Wojciechowski
   2156  * @author David Deutsch
   2157  * @license The MIT License (MIT)
   2158  */
   2159 ;(function($, window, document, undefined) {
   2160 
   2161 	/**
   2162 	 * Creates the video plugin.
   2163 	 * @class The Video Plugin
   2164 	 * @param {Owl} carousel - The Owl Carousel
   2165 	 */
   2166 	var Video = function(carousel) {
   2167 		/**
   2168 		 * Reference to the core.
   2169 		 * @protected
   2170 		 * @type {Owl}
   2171 		 */
   2172 		this._core = carousel;
   2173 
   2174 		/**
   2175 		 * Cache all video URLs.
   2176 		 * @protected
   2177 		 * @type {Object}
   2178 		 */
   2179 		this._videos = {};
   2180 
   2181 		/**
   2182 		 * Current playing item.
   2183 		 * @protected
   2184 		 * @type {jQuery}
   2185 		 */
   2186 		this._playing = null;
   2187 
   2188 		/**
   2189 		 * All event handlers.
   2190 		 * @todo The cloned content removale is too late
   2191 		 * @protected
   2192 		 * @type {Object}
   2193 		 */
   2194 		this._handlers = {
   2195 			'initialized.owl.carousel': $.proxy(function(e) {
   2196 				if (e.namespace) {
   2197 					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
   2198 				}
   2199 			}, this),
   2200 			'resize.owl.carousel': $.proxy(function(e) {
   2201 				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
   2202 					e.preventDefault();
   2203 				}
   2204 			}, this),
   2205 			'refreshed.owl.carousel': $.proxy(function(e) {
   2206 				if (e.namespace && this._core.is('resizing')) {
   2207 					this._core.$stage.find('.cloned .owl-video-frame').remove();
   2208 				}
   2209 			}, this),
   2210 			'changed.owl.carousel': $.proxy(function(e) {
   2211 				if (e.namespace && e.property.name === 'position' && this._playing) {
   2212 					this.stop();
   2213 				}
   2214 			}, this),
   2215 			'prepared.owl.carousel': $.proxy(function(e) {
   2216 				if (!e.namespace) {
   2217 					return;
   2218 				}
   2219 
   2220 				var $element = $(e.content).find('.owl-video');
   2221 
   2222 				if ($element.length) {
   2223 					$element.css('display', 'none');
   2224 					this.fetch($element, $(e.content));
   2225 				}
   2226 			}, this)
   2227 		};
   2228 
   2229 		// set default options
   2230 		this._core.options = $.extend({}, Video.Defaults, this._core.options);
   2231 
   2232 		// register event handlers
   2233 		this._core.$element.on(this._handlers);
   2234 
   2235 		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
   2236 			this.play(e);
   2237 		}, this));
   2238 	};
   2239 
   2240 	/**
   2241 	 * Default options.
   2242 	 * @public
   2243 	 */
   2244 	Video.Defaults = {
   2245 		video: false,
   2246 		videoHeight: false,
   2247 		videoWidth: false
   2248 	};
   2249 
   2250 	/**
   2251 	 * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
   2252 	 * @protected
   2253 	 * @param {jQuery} target - The target containing the video data.
   2254 	 * @param {jQuery} item - The item containing the video.
   2255 	 */
   2256 	Video.prototype.fetch = function(target, item) {
   2257 			var type = (function() {
   2258 					if (target.attr('data-vimeo-id')) {
   2259 						return 'vimeo';
   2260 					} else if (target.attr('data-vzaar-id')) {
   2261 						return 'vzaar'
   2262 					} else {
   2263 						return 'youtube';
   2264 					}
   2265 				})(),
   2266 				id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
   2267 				width = target.attr('data-width') || this._core.settings.videoWidth,
   2268 				height = target.attr('data-height') || this._core.settings.videoHeight,
   2269 				url = target.attr('href');
   2270 
   2271 		if (url) {
   2272 
   2273 			/*
   2274 					Parses the id's out of the following urls (and probably more):
   2275 					https://www.youtube.com/watch?v=:id
   2276 					https://youtu.be/:id
   2277 					https://vimeo.com/:id
   2278 					https://vimeo.com/channels/:channel/:id
   2279 					https://vimeo.com/groups/:group/videos/:id
   2280 					https://app.vzaar.com/videos/:id
   2281 
   2282 					Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
   2283 			*/
   2284 
   2285 			id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
   2286 
   2287 			if (id[3].indexOf('youtu') > -1) {
   2288 				type = 'youtube';
   2289 			} else if (id[3].indexOf('vimeo') > -1) {
   2290 				type = 'vimeo';
   2291 			} else if (id[3].indexOf('vzaar') > -1) {
   2292 				type = 'vzaar';
   2293 			} else {
   2294 				throw new Error('Video URL not supported.');
   2295 			}
   2296 			id = id[6];
   2297 		} else {
   2298 			throw new Error('Missing video URL.');
   2299 		}
   2300 
   2301 		this._videos[url] = {
   2302 			type: type,
   2303 			id: id,
   2304 			width: width,
   2305 			height: height
   2306 		};
   2307 
   2308 		item.attr('data-video', url);
   2309 
   2310 		this.thumbnail(target, this._videos[url]);
   2311 	};
   2312 
   2313 	/**
   2314 	 * Creates video thumbnail.
   2315 	 * @protected
   2316 	 * @param {jQuery} target - The target containing the video data.
   2317 	 * @param {Object} info - The video info object.
   2318 	 * @see `fetch`
   2319 	 */
   2320 	Video.prototype.thumbnail = function(target, video) {
   2321 		var tnLink,
   2322 			icon,
   2323 			path,
   2324 			dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '',
   2325 			customTn = target.find('img'),
   2326 			srcType = 'src',
   2327 			lazyClass = '',
   2328 			settings = this._core.settings,
   2329 			create = function(path) {
   2330 				icon = '<div class="owl-video-play-icon"></div>';
   2331 
   2332 				if (settings.lazyLoad) {
   2333 					tnLink = $('<div/>',{
   2334 						"class": 'owl-video-tn ' + lazyClass,
   2335 						"srcType": path
   2336 					});
   2337 				} else {
   2338 					tnLink = $( '<div/>', {
   2339 						"class": "owl-video-tn",
   2340 						"style": 'opacity:1;background-image:url(' + path + ')'
   2341 					});
   2342 				}
   2343 				target.after(tnLink);
   2344 				target.after(icon);
   2345 			};
   2346 
   2347 		// wrap video content into owl-video-wrapper div
   2348 		target.wrap( $( '<div/>', {
   2349 			"class": "owl-video-wrapper",
   2350 			"style": dimensions
   2351 		}));
   2352 
   2353 		if (this._core.settings.lazyLoad) {
   2354 			srcType = 'data-src';
   2355 			lazyClass = 'owl-lazy';
   2356 		}
   2357 
   2358 		// custom thumbnail
   2359 		if (customTn.length) {
   2360 			create(customTn.attr(srcType));
   2361 			customTn.remove();
   2362 			return false;
   2363 		}
   2364 
   2365 		if (video.type === 'youtube') {
   2366 			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
   2367 			create(path);
   2368 		} else if (video.type === 'vimeo') {
   2369 			$.ajax({
   2370 				type: 'GET',
   2371 				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
   2372 				jsonp: 'callback',
   2373 				dataType: 'jsonp',
   2374 				success: function(data) {
   2375 					path = data[0].thumbnail_large;
   2376 					create(path);
   2377 				}
   2378 			});
   2379 		} else if (video.type === 'vzaar') {
   2380 			$.ajax({
   2381 				type: 'GET',
   2382 				url: '//vzaar.com/api/videos/' + video.id + '.json',
   2383 				jsonp: 'callback',
   2384 				dataType: 'jsonp',
   2385 				success: function(data) {
   2386 					path = data.framegrab_url;
   2387 					create(path);
   2388 				}
   2389 			});
   2390 		}
   2391 	};
   2392 
   2393 	/**
   2394 	 * Stops the current video.
   2395 	 * @public
   2396 	 */
   2397 	Video.prototype.stop = function() {
   2398 		this._core.trigger('stop', null, 'video');
   2399 		this._playing.find('.owl-video-frame').remove();
   2400 		this._playing.removeClass('owl-video-playing');
   2401 		this._playing = null;
   2402 		this._core.leave('playing');
   2403 		this._core.trigger('stopped', null, 'video');
   2404 	};
   2405 
   2406 	/**
   2407 	 * Starts the current video.
   2408 	 * @public
   2409 	 * @param {Event} event - The event arguments.
   2410 	 */
   2411 	Video.prototype.play = function(event) {
   2412 		var target = $(event.target),
   2413 			item = target.closest('.' + this._core.settings.itemClass),
   2414 			video = this._videos[item.attr('data-video')],
   2415 			width = video.width || '100%',
   2416 			height = video.height || this._core.$stage.height(),
   2417 			html,
   2418 			iframe;
   2419 
   2420 		if (this._playing) {
   2421 			return;
   2422 		}
   2423 
   2424 		this._core.enter('playing');
   2425 		this._core.trigger('play', null, 'video');
   2426 
   2427 		item = this._core.items(this._core.relative(item.index()));
   2428 
   2429 		this._core.reset(item.index());
   2430 
   2431 		html = $( '<iframe frameborder="0" allowfullscreen mozallowfullscreen webkitAllowFullScreen ></iframe>' );
   2432 		html.attr( 'height', height );
   2433 		html.attr( 'width', width );
   2434 		if (video.type === 'youtube') {
   2435 			html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id );
   2436 		} else if (video.type === 'vimeo') {
   2437 			html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' );
   2438 		} else if (video.type === 'vzaar') {
   2439 			html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' );
   2440 		}
   2441 
   2442 		iframe = $(html).wrap( '<div class="owl-video-frame" />' ).insertAfter(item.find('.owl-video'));
   2443 
   2444 		this._playing = item.addClass('owl-video-playing');
   2445 	};
   2446 
   2447 	/**
   2448 	 * Checks whether an video is currently in full screen mode or not.
   2449 	 * @todo Bad style because looks like a readonly method but changes members.
   2450 	 * @protected
   2451 	 * @returns {Boolean}
   2452 	 */
   2453 	Video.prototype.isInFullScreen = function() {
   2454 		var element = document.fullscreenElement || document.mozFullScreenElement ||
   2455 				document.webkitFullscreenElement;
   2456 
   2457 		return element && $(element).parent().hasClass('owl-video-frame');
   2458 	};
   2459 
   2460 	/**
   2461 	 * Destroys the plugin.
   2462 	 */
   2463 	Video.prototype.destroy = function() {
   2464 		var handler, property;
   2465 
   2466 		this._core.$element.off('click.owl.video');
   2467 
   2468 		for (handler in this._handlers) {
   2469 			this._core.$element.off(handler, this._handlers[handler]);
   2470 		}
   2471 		for (property in Object.getOwnPropertyNames(this)) {
   2472 			typeof this[property] != 'function' && (this[property] = null);
   2473 		}
   2474 	};
   2475 
   2476 	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
   2477 
   2478 })(window.Zepto || window.jQuery, window, document);
   2479 
   2480 /**
   2481  * Animate Plugin
   2482  * @version 2.3.4
   2483  * @author Bartosz Wojciechowski
   2484  * @author David Deutsch
   2485  * @license The MIT License (MIT)
   2486  */
   2487 ;(function($, window, document, undefined) {
   2488 
   2489 	/**
   2490 	 * Creates the animate plugin.
   2491 	 * @class The Navigation Plugin
   2492 	 * @param {Owl} scope - The Owl Carousel
   2493 	 */
   2494 	var Animate = function(scope) {
   2495 		this.core = scope;
   2496 		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
   2497 		this.swapping = true;
   2498 		this.previous = undefined;
   2499 		this.next = undefined;
   2500 
   2501 		this.handlers = {
   2502 			'change.owl.carousel': $.proxy(function(e) {
   2503 				if (e.namespace && e.property.name == 'position') {
   2504 					this.previous = this.core.current();
   2505 					this.next = e.property.value;
   2506 				}
   2507 			}, this),
   2508 			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
   2509 				if (e.namespace) {
   2510 					this.swapping = e.type == 'translated';
   2511 				}
   2512 			}, this),
   2513 			'translate.owl.carousel': $.proxy(function(e) {
   2514 				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
   2515 					this.swap();
   2516 				}
   2517 			}, this)
   2518 		};
   2519 
   2520 		this.core.$element.on(this.handlers);
   2521 	};
   2522 
   2523 	/**
   2524 	 * Default options.
   2525 	 * @public
   2526 	 */
   2527 	Animate.Defaults = {
   2528 		animateOut: false,
   2529 		animateIn: false
   2530 	};
   2531 
   2532 	/**
   2533 	 * Toggles the animation classes whenever an translations starts.
   2534 	 * @protected
   2535 	 * @returns {Boolean|undefined}
   2536 	 */
   2537 	Animate.prototype.swap = function() {
   2538 
   2539 		if (this.core.settings.items !== 1) {
   2540 			return;
   2541 		}
   2542 
   2543 		if (!$.support.animation || !$.support.transition) {
   2544 			return;
   2545 		}
   2546 
   2547 		this.core.speed(0);
   2548 
   2549 		var left,
   2550 			clear = $.proxy(this.clear, this),
   2551 			previous = this.core.$stage.children().eq(this.previous),
   2552 			next = this.core.$stage.children().eq(this.next),
   2553 			incoming = this.core.settings.animateIn,
   2554 			outgoing = this.core.settings.animateOut;
   2555 
   2556 		if (this.core.current() === this.previous) {
   2557 			return;
   2558 		}
   2559 
   2560 		if (outgoing) {
   2561 			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
   2562 			previous.one($.support.animation.end, clear)
   2563 				.css( { 'left': left + 'px' } )
   2564 				.addClass('animated owl-animated-out')
   2565 				.addClass(outgoing);
   2566 		}
   2567 
   2568 		if (incoming) {
   2569 			next.one($.support.animation.end, clear)
   2570 				.addClass('animated owl-animated-in')
   2571 				.addClass(incoming);
   2572 		}
   2573 	};
   2574 
   2575 	Animate.prototype.clear = function(e) {
   2576 		$(e.target).css( { 'left': '' } )
   2577 			.removeClass('animated owl-animated-out owl-animated-in')
   2578 			.removeClass(this.core.settings.animateIn)
   2579 			.removeClass(this.core.settings.animateOut);
   2580 		this.core.onTransitionEnd();
   2581 	};
   2582 
   2583 	/**
   2584 	 * Destroys the plugin.
   2585 	 * @public
   2586 	 */
   2587 	Animate.prototype.destroy = function() {
   2588 		var handler, property;
   2589 
   2590 		for (handler in this.handlers) {
   2591 			this.core.$element.off(handler, this.handlers[handler]);
   2592 		}
   2593 		for (property in Object.getOwnPropertyNames(this)) {
   2594 			typeof this[property] != 'function' && (this[property] = null);
   2595 		}
   2596 	};
   2597 
   2598 	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
   2599 
   2600 })(window.Zepto || window.jQuery, window, document);
   2601 
   2602 /**
   2603  * Autoplay Plugin
   2604  * @version 2.3.4
   2605  * @author Bartosz Wojciechowski
   2606  * @author Artus Kolanowski
   2607  * @author David Deutsch
   2608  * @author Tom De Caluwé
   2609  * @license The MIT License (MIT)
   2610  */
   2611 ;(function($, window, document, undefined) {
   2612 
   2613 	/**
   2614 	 * Creates the autoplay plugin.
   2615 	 * @class The Autoplay Plugin
   2616 	 * @param {Owl} scope - The Owl Carousel
   2617 	 */
   2618 	var Autoplay = function(carousel) {
   2619 		/**
   2620 		 * Reference to the core.
   2621 		 * @protected
   2622 		 * @type {Owl}
   2623 		 */
   2624 		this._core = carousel;
   2625 
   2626 		/**
   2627 		 * The autoplay timeout id.
   2628 		 * @type {Number}
   2629 		 */
   2630 		this._call = null;
   2631 
   2632 		/**
   2633 		 * Depending on the state of the plugin, this variable contains either
   2634 		 * the start time of the timer or the current timer value if it's
   2635 		 * paused. Since we start in a paused state we initialize the timer
   2636 		 * value.
   2637 		 * @type {Number}
   2638 		 */
   2639 		this._time = 0;
   2640 
   2641 		/**
   2642 		 * Stores the timeout currently used.
   2643 		 * @type {Number}
   2644 		 */
   2645 		this._timeout = 0;
   2646 
   2647 		/**
   2648 		 * Indicates whenever the autoplay is paused.
   2649 		 * @type {Boolean}
   2650 		 */
   2651 		this._paused = true;
   2652 
   2653 		/**
   2654 		 * All event handlers.
   2655 		 * @protected
   2656 		 * @type {Object}
   2657 		 */
   2658 		this._handlers = {
   2659 			'changed.owl.carousel': $.proxy(function(e) {
   2660 				if (e.namespace && e.property.name === 'settings') {
   2661 					if (this._core.settings.autoplay) {
   2662 						this.play();
   2663 					} else {
   2664 						this.stop();
   2665 					}
   2666 				} else if (e.namespace && e.property.name === 'position' && this._paused) {
   2667 					// Reset the timer. This code is triggered when the position
   2668 					// of the carousel was changed through user interaction.
   2669 					this._time = 0;
   2670 				}
   2671 			}, this),
   2672 			'initialized.owl.carousel': $.proxy(function(e) {
   2673 				if (e.namespace && this._core.settings.autoplay) {
   2674 					this.play();
   2675 				}
   2676 			}, this),
   2677 			'play.owl.autoplay': $.proxy(function(e, t, s) {
   2678 				if (e.namespace) {
   2679 					this.play(t, s);
   2680 				}
   2681 			}, this),
   2682 			'stop.owl.autoplay': $.proxy(function(e) {
   2683 				if (e.namespace) {
   2684 					this.stop();
   2685 				}
   2686 			}, this),
   2687 			'mouseover.owl.autoplay': $.proxy(function() {
   2688 				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
   2689 					this.pause();
   2690 				}
   2691 			}, this),
   2692 			'mouseleave.owl.autoplay': $.proxy(function() {
   2693 				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
   2694 					this.play();
   2695 				}
   2696 			}, this),
   2697 			'touchstart.owl.core': $.proxy(function() {
   2698 				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
   2699 					this.pause();
   2700 				}
   2701 			}, this),
   2702 			'touchend.owl.core': $.proxy(function() {
   2703 				if (this._core.settings.autoplayHoverPause) {
   2704 					this.play();
   2705 				}
   2706 			}, this)
   2707 		};
   2708 
   2709 		// register event handlers
   2710 		this._core.$element.on(this._handlers);
   2711 
   2712 		// set default options
   2713 		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
   2714 	};
   2715 
   2716 	/**
   2717 	 * Default options.
   2718 	 * @public
   2719 	 */
   2720 	Autoplay.Defaults = {
   2721 		autoplay: false,
   2722 		autoplayTimeout: 5000,
   2723 		autoplayHoverPause: false,
   2724 		autoplaySpeed: false
   2725 	};
   2726 
   2727 	/**
   2728 	 * Transition to the next slide and set a timeout for the next transition.
   2729 	 * @private
   2730 	 * @param {Number} [speed] - The animation speed for the animations.
   2731 	 */
   2732 	Autoplay.prototype._next = function(speed) {
   2733 		this._call = window.setTimeout(
   2734 			$.proxy(this._next, this, speed),
   2735 			this._timeout * (Math.round(this.read() / this._timeout) + 1) - this.read()
   2736 		);
   2737 
   2738 		if (this._core.is('interacting') || document.hidden) {
   2739 			return;
   2740 		}
   2741 		this._core.next(speed || this._core.settings.autoplaySpeed);
   2742 	}
   2743 
   2744 	/**
   2745 	 * Reads the current timer value when the timer is playing.
   2746 	 * @public
   2747 	 */
   2748 	Autoplay.prototype.read = function() {
   2749 		return new Date().getTime() - this._time;
   2750 	};
   2751 
   2752 	/**
   2753 	 * Starts the autoplay.
   2754 	 * @public
   2755 	 * @param {Number} [timeout] - The interval before the next animation starts.
   2756 	 * @param {Number} [speed] - The animation speed for the animations.
   2757 	 */
   2758 	Autoplay.prototype.play = function(timeout, speed) {
   2759 		var elapsed;
   2760 
   2761 		if (!this._core.is('rotating')) {
   2762 			this._core.enter('rotating');
   2763 		}
   2764 
   2765 		timeout = timeout || this._core.settings.autoplayTimeout;
   2766 
   2767 		// Calculate the elapsed time since the last transition. If the carousel
   2768 		// wasn't playing this calculation will yield zero.
   2769 		elapsed = Math.min(this._time % (this._timeout || timeout), timeout);
   2770 
   2771 		if (this._paused) {
   2772 			// Start the clock.
   2773 			this._time = this.read();
   2774 			this._paused = false;
   2775 		} else {
   2776 			// Clear the active timeout to allow replacement.
   2777 			window.clearTimeout(this._call);
   2778 		}
   2779 
   2780 		// Adjust the origin of the timer to match the new timeout value.
   2781 		this._time += this.read() % timeout - elapsed;
   2782 
   2783 		this._timeout = timeout;
   2784 		this._call = window.setTimeout($.proxy(this._next, this, speed), timeout - elapsed);
   2785 	};
   2786 
   2787 	/**
   2788 	 * Stops the autoplay.
   2789 	 * @public
   2790 	 */
   2791 	Autoplay.prototype.stop = function() {
   2792 		if (this._core.is('rotating')) {
   2793 			// Reset the clock.
   2794 			this._time = 0;
   2795 			this._paused = true;
   2796 
   2797 			window.clearTimeout(this._call);
   2798 			this._core.leave('rotating');
   2799 		}
   2800 	};
   2801 
   2802 	/**
   2803 	 * Pauses the autoplay.
   2804 	 * @public
   2805 	 */
   2806 	Autoplay.prototype.pause = function() {
   2807 		if (this._core.is('rotating') && !this._paused) {
   2808 			// Pause the clock.
   2809 			this._time = this.read();
   2810 			this._paused = true;
   2811 
   2812 			window.clearTimeout(this._call);
   2813 		}
   2814 	};
   2815 
   2816 	/**
   2817 	 * Destroys the plugin.
   2818 	 */
   2819 	Autoplay.prototype.destroy = function() {
   2820 		var handler, property;
   2821 
   2822 		this.stop();
   2823 
   2824 		for (handler in this._handlers) {
   2825 			this._core.$element.off(handler, this._handlers[handler]);
   2826 		}
   2827 		for (property in Object.getOwnPropertyNames(this)) {
   2828 			typeof this[property] != 'function' && (this[property] = null);
   2829 		}
   2830 	};
   2831 
   2832 	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
   2833 
   2834 })(window.Zepto || window.jQuery, window, document);
   2835 
   2836 /**
   2837  * Navigation Plugin
   2838  * @version 2.3.4
   2839  * @author Artus Kolanowski
   2840  * @author David Deutsch
   2841  * @license The MIT License (MIT)
   2842  */
   2843 ;(function($, window, document, undefined) {
   2844 	'use strict';
   2845 
   2846 	/**
   2847 	 * Creates the navigation plugin.
   2848 	 * @class The Navigation Plugin
   2849 	 * @param {Owl} carousel - The Owl Carousel.
   2850 	 */
   2851 	var Navigation = function(carousel) {
   2852 		/**
   2853 		 * Reference to the core.
   2854 		 * @protected
   2855 		 * @type {Owl}
   2856 		 */
   2857 		this._core = carousel;
   2858 
   2859 		/**
   2860 		 * Indicates whether the plugin is initialized or not.
   2861 		 * @protected
   2862 		 * @type {Boolean}
   2863 		 */
   2864 		this._initialized = false;
   2865 
   2866 		/**
   2867 		 * The current paging indexes.
   2868 		 * @protected
   2869 		 * @type {Array}
   2870 		 */
   2871 		this._pages = [];
   2872 
   2873 		/**
   2874 		 * All DOM elements of the user interface.
   2875 		 * @protected
   2876 		 * @type {Object}
   2877 		 */
   2878 		this._controls = {};
   2879 
   2880 		/**
   2881 		 * Markup for an indicator.
   2882 		 * @protected
   2883 		 * @type {Array.<String>}
   2884 		 */
   2885 		this._templates = [];
   2886 
   2887 		/**
   2888 		 * The carousel element.
   2889 		 * @type {jQuery}
   2890 		 */
   2891 		this.$element = this._core.$element;
   2892 
   2893 		/**
   2894 		 * Overridden methods of the carousel.
   2895 		 * @protected
   2896 		 * @type {Object}
   2897 		 */
   2898 		this._overrides = {
   2899 			next: this._core.next,
   2900 			prev: this._core.prev,
   2901 			to: this._core.to
   2902 		};
   2903 
   2904 		/**
   2905 		 * All event handlers.
   2906 		 * @protected
   2907 		 * @type {Object}
   2908 		 */
   2909 		this._handlers = {
   2910 			'prepared.owl.carousel': $.proxy(function(e) {
   2911 				if (e.namespace && this._core.settings.dotsData) {
   2912 					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
   2913 						$(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '</div>');
   2914 				}
   2915 			}, this),
   2916 			'added.owl.carousel': $.proxy(function(e) {
   2917 				if (e.namespace && this._core.settings.dotsData) {
   2918 					this._templates.splice(e.position, 0, this._templates.pop());
   2919 				}
   2920 			}, this),
   2921 			'remove.owl.carousel': $.proxy(function(e) {
   2922 				if (e.namespace && this._core.settings.dotsData) {
   2923 					this._templates.splice(e.position, 1);
   2924 				}
   2925 			}, this),
   2926 			'changed.owl.carousel': $.proxy(function(e) {
   2927 				if (e.namespace && e.property.name == 'position') {
   2928 					this.draw();
   2929 				}
   2930 			}, this),
   2931 			'initialized.owl.carousel': $.proxy(function(e) {
   2932 				if (e.namespace && !this._initialized) {
   2933 					this._core.trigger('initialize', null, 'navigation');
   2934 					this.initialize();
   2935 					this.update();
   2936 					this.draw();
   2937 					this._initialized = true;
   2938 					this._core.trigger('initialized', null, 'navigation');
   2939 				}
   2940 			}, this),
   2941 			'refreshed.owl.carousel': $.proxy(function(e) {
   2942 				if (e.namespace && this._initialized) {
   2943 					this._core.trigger('refresh', null, 'navigation');
   2944 					this.update();
   2945 					this.draw();
   2946 					this._core.trigger('refreshed', null, 'navigation');
   2947 				}
   2948 			}, this)
   2949 		};
   2950 
   2951 		// set default options
   2952 		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
   2953 
   2954 		// register event handlers
   2955 		this.$element.on(this._handlers);
   2956 	};
   2957 
   2958 	/**
   2959 	 * Default options.
   2960 	 * @public
   2961 	 * @todo Rename `slideBy` to `navBy`
   2962 	 */
   2963 	Navigation.Defaults = {
   2964 		nav: false,
   2965 		navText: [
   2966 			'<span aria-label="' + 'Previous' + '">&#x2039;</span>',
   2967 			'<span aria-label="' + 'Next' + '">&#x203a;</span>'
   2968 		],
   2969 		navSpeed: false,
   2970 		navElement: 'button type="button" role="presentation"',
   2971 		navContainer: false,
   2972 		navContainerClass: 'owl-nav',
   2973 		navClass: [
   2974 			'owl-prev',
   2975 			'owl-next'
   2976 		],
   2977 		slideBy: 1,
   2978 		dotClass: 'owl-dot',
   2979 		dotsClass: 'owl-dots',
   2980 		dots: true,
   2981 		dotsEach: false,
   2982 		dotsData: false,
   2983 		dotsSpeed: false,
   2984 		dotsContainer: false
   2985 	};
   2986 
   2987 	/**
   2988 	 * Initializes the layout of the plugin and extends the carousel.
   2989 	 * @protected
   2990 	 */
   2991 	Navigation.prototype.initialize = function() {
   2992 		var override,
   2993 			settings = this._core.settings;
   2994 
   2995 		// create DOM structure for relative navigation
   2996 		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
   2997 			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
   2998 
   2999 		this._controls.$previous = $('<' + settings.navElement + '>')
   3000 			.addClass(settings.navClass[0])
   3001 			.html(settings.navText[0])
   3002 			.prependTo(this._controls.$relative)
   3003 			.on('click', $.proxy(function(e) {
   3004 				this.prev(settings.navSpeed);
   3005 			}, this));
   3006 		this._controls.$next = $('<' + settings.navElement + '>')
   3007 			.addClass(settings.navClass[1])
   3008 			.html(settings.navText[1])
   3009 			.appendTo(this._controls.$relative)
   3010 			.on('click', $.proxy(function(e) {
   3011 				this.next(settings.navSpeed);
   3012 			}, this));
   3013 
   3014 		// create DOM structure for absolute navigation
   3015 		if (!settings.dotsData) {
   3016 			this._templates = [ $('<button role="button">')
   3017 				.addClass(settings.dotClass)
   3018 				.append($('<span>'))
   3019 				.prop('outerHTML') ];
   3020 		}
   3021 
   3022 		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
   3023 			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
   3024 
   3025 		this._controls.$absolute.on('click', 'button', $.proxy(function(e) {
   3026 			var index = $(e.target).parent().is(this._controls.$absolute)
   3027 				? $(e.target).index() : $(e.target).parent().index();
   3028 
   3029 			e.preventDefault();
   3030 
   3031 			this.to(index, settings.dotsSpeed);
   3032 		}, this));
   3033 
   3034 		/*$el.on('focusin', function() {
   3035 			$(document).off(".carousel");
   3036 
   3037 			$(document).on('keydown.carousel', function(e) {
   3038 				if(e.keyCode == 37) {
   3039 					$el.trigger('prev.owl')
   3040 				}
   3041 				if(e.keyCode == 39) {
   3042 					$el.trigger('next.owl')
   3043 				}
   3044 			});
   3045 		});*/
   3046 
   3047 		// override public methods of the carousel
   3048 		for (override in this._overrides) {
   3049 			this._core[override] = $.proxy(this[override], this);
   3050 		}
   3051 	};
   3052 
   3053 	/**
   3054 	 * Destroys the plugin.
   3055 	 * @protected
   3056 	 */
   3057 	Navigation.prototype.destroy = function() {
   3058 		var handler, control, property, override, settings;
   3059 		settings = this._core.settings;
   3060 
   3061 		for (handler in this._handlers) {
   3062 			this.$element.off(handler, this._handlers[handler]);
   3063 		}
   3064 		for (control in this._controls) {
   3065 			if (control === '$relative' && settings.navContainer) {
   3066 				this._controls[control].html('');
   3067 			} else {
   3068 				this._controls[control].remove();
   3069 			}
   3070 		}
   3071 		for (override in this.overides) {
   3072 			this._core[override] = this._overrides[override];
   3073 		}
   3074 		for (property in Object.getOwnPropertyNames(this)) {
   3075 			typeof this[property] != 'function' && (this[property] = null);
   3076 		}
   3077 	};
   3078 
   3079 	/**
   3080 	 * Updates the internal state.
   3081 	 * @protected
   3082 	 */
   3083 	Navigation.prototype.update = function() {
   3084 		var i, j, k,
   3085 			lower = this._core.clones().length / 2,
   3086 			upper = lower + this._core.items().length,
   3087 			maximum = this._core.maximum(true),
   3088 			settings = this._core.settings,
   3089 			size = settings.center || settings.autoWidth || settings.dotsData
   3090 				? 1 : settings.dotsEach || settings.items;
   3091 
   3092 		if (settings.slideBy !== 'page') {
   3093 			settings.slideBy = Math.min(settings.slideBy, settings.items);
   3094 		}
   3095 
   3096 		if (settings.dots || settings.slideBy == 'page') {
   3097 			this._pages = [];
   3098 
   3099 			for (i = lower, j = 0, k = 0; i < upper; i++) {
   3100 				if (j >= size || j === 0) {
   3101 					this._pages.push({
   3102 						start: Math.min(maximum, i - lower),
   3103 						end: i - lower + size - 1
   3104 					});
   3105 					if (Math.min(maximum, i - lower) === maximum) {
   3106 						break;
   3107 					}
   3108 					j = 0, ++k;
   3109 				}
   3110 				j += this._core.mergers(this._core.relative(i));
   3111 			}
   3112 		}
   3113 	};
   3114 
   3115 	/**
   3116 	 * Draws the user interface.
   3117 	 * @todo The option `dotsData` wont work.
   3118 	 * @protected
   3119 	 */
   3120 	Navigation.prototype.draw = function() {
   3121 		var difference,
   3122 			settings = this._core.settings,
   3123 			disabled = this._core.items().length <= settings.items,
   3124 			index = this._core.relative(this._core.current()),
   3125 			loop = settings.loop || settings.rewind;
   3126 
   3127 		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
   3128 
   3129 		if (settings.nav) {
   3130 			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
   3131 			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
   3132 		}
   3133 
   3134 		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
   3135 
   3136 		if (settings.dots) {
   3137 			difference = this._pages.length - this._controls.$absolute.children().length;
   3138 
   3139 			if (settings.dotsData && difference !== 0) {
   3140 				this._controls.$absolute.html(this._templates.join(''));
   3141 			} else if (difference > 0) {
   3142 				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
   3143 			} else if (difference < 0) {
   3144 				this._controls.$absolute.children().slice(difference).remove();
   3145 			}
   3146 
   3147 			this._controls.$absolute.find('.active').removeClass('active');
   3148 			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
   3149 		}
   3150 	};
   3151 
   3152 	/**
   3153 	 * Extends event data.
   3154 	 * @protected
   3155 	 * @param {Event} event - The event object which gets thrown.
   3156 	 */
   3157 	Navigation.prototype.onTrigger = function(event) {
   3158 		var settings = this._core.settings;
   3159 
   3160 		event.page = {
   3161 			index: $.inArray(this.current(), this._pages),
   3162 			count: this._pages.length,
   3163 			size: settings && (settings.center || settings.autoWidth || settings.dotsData
   3164 				? 1 : settings.dotsEach || settings.items)
   3165 		};
   3166 	};
   3167 
   3168 	/**
   3169 	 * Gets the current page position of the carousel.
   3170 	 * @protected
   3171 	 * @returns {Number}
   3172 	 */
   3173 	Navigation.prototype.current = function() {
   3174 		var current = this._core.relative(this._core.current());
   3175 		return $.grep(this._pages, $.proxy(function(page, index) {
   3176 			return page.start <= current && page.end >= current;
   3177 		}, this)).pop();
   3178 	};
   3179 
   3180 	/**
   3181 	 * Gets the current succesor/predecessor position.
   3182 	 * @protected
   3183 	 * @returns {Number}
   3184 	 */
   3185 	Navigation.prototype.getPosition = function(successor) {
   3186 		var position, length,
   3187 			settings = this._core.settings;
   3188 
   3189 		if (settings.slideBy == 'page') {
   3190 			position = $.inArray(this.current(), this._pages);
   3191 			length = this._pages.length;
   3192 			successor ? ++position : --position;
   3193 			position = this._pages[((position % length) + length) % length].start;
   3194 		} else {
   3195 			position = this._core.relative(this._core.current());
   3196 			length = this._core.items().length;
   3197 			successor ? position += settings.slideBy : position -= settings.slideBy;
   3198 		}
   3199 
   3200 		return position;
   3201 	};
   3202 
   3203 	/**
   3204 	 * Slides to the next item or page.
   3205 	 * @public
   3206 	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
   3207 	 */
   3208 	Navigation.prototype.next = function(speed) {
   3209 		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
   3210 	};
   3211 
   3212 	/**
   3213 	 * Slides to the previous item or page.
   3214 	 * @public
   3215 	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
   3216 	 */
   3217 	Navigation.prototype.prev = function(speed) {
   3218 		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
   3219 	};
   3220 
   3221 	/**
   3222 	 * Slides to the specified item or page.
   3223 	 * @public
   3224 	 * @param {Number} position - The position of the item or page.
   3225 	 * @param {Number} [speed] - The time in milliseconds for the transition.
   3226 	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
   3227 	 */
   3228 	Navigation.prototype.to = function(position, speed, standard) {
   3229 		var length;
   3230 
   3231 		if (!standard && this._pages.length) {
   3232 			length = this._pages.length;
   3233 			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
   3234 		} else {
   3235 			$.proxy(this._overrides.to, this._core)(position, speed);
   3236 		}
   3237 	};
   3238 
   3239 	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
   3240 
   3241 })(window.Zepto || window.jQuery, window, document);
   3242 
   3243 /**
   3244  * Hash Plugin
   3245  * @version 2.3.4
   3246  * @author Artus Kolanowski
   3247  * @author David Deutsch
   3248  * @license The MIT License (MIT)
   3249  */
   3250 ;(function($, window, document, undefined) {
   3251 	'use strict';
   3252 
   3253 	/**
   3254 	 * Creates the hash plugin.
   3255 	 * @class The Hash Plugin
   3256 	 * @param {Owl} carousel - The Owl Carousel
   3257 	 */
   3258 	var Hash = function(carousel) {
   3259 		/**
   3260 		 * Reference to the core.
   3261 		 * @protected
   3262 		 * @type {Owl}
   3263 		 */
   3264 		this._core = carousel;
   3265 
   3266 		/**
   3267 		 * Hash index for the items.
   3268 		 * @protected
   3269 		 * @type {Object}
   3270 		 */
   3271 		this._hashes = {};
   3272 
   3273 		/**
   3274 		 * The carousel element.
   3275 		 * @type {jQuery}
   3276 		 */
   3277 		this.$element = this._core.$element;
   3278 
   3279 		/**
   3280 		 * All event handlers.
   3281 		 * @protected
   3282 		 * @type {Object}
   3283 		 */
   3284 		this._handlers = {
   3285 			'initialized.owl.carousel': $.proxy(function(e) {
   3286 				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
   3287 					$(window).trigger('hashchange.owl.navigation');
   3288 				}
   3289 			}, this),
   3290 			'prepared.owl.carousel': $.proxy(function(e) {
   3291 				if (e.namespace) {
   3292 					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
   3293 
   3294 					if (!hash) {
   3295 						return;
   3296 					}
   3297 
   3298 					this._hashes[hash] = e.content;
   3299 				}
   3300 			}, this),
   3301 			'changed.owl.carousel': $.proxy(function(e) {
   3302 				if (e.namespace && e.property.name === 'position') {
   3303 					var current = this._core.items(this._core.relative(this._core.current())),
   3304 						hash = $.map(this._hashes, function(item, hash) {
   3305 							return item === current ? hash : null;
   3306 						}).join();
   3307 
   3308 					if (!hash || window.location.hash.slice(1) === hash) {
   3309 						return;
   3310 					}
   3311 
   3312 					window.location.hash = hash;
   3313 				}
   3314 			}, this)
   3315 		};
   3316 
   3317 		// set default options
   3318 		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
   3319 
   3320 		// register the event handlers
   3321 		this.$element.on(this._handlers);
   3322 
   3323 		// register event listener for hash navigation
   3324 		$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
   3325 			var hash = window.location.hash.substring(1),
   3326 				items = this._core.$stage.children(),
   3327 				position = this._hashes[hash] && items.index(this._hashes[hash]);
   3328 
   3329 			if (position === undefined || position === this._core.current()) {
   3330 				return;
   3331 			}
   3332 
   3333 			this._core.to(this._core.relative(position), false, true);
   3334 		}, this));
   3335 	};
   3336 
   3337 	/**
   3338 	 * Default options.
   3339 	 * @public
   3340 	 */
   3341 	Hash.Defaults = {
   3342 		URLhashListener: false
   3343 	};
   3344 
   3345 	/**
   3346 	 * Destroys the plugin.
   3347 	 * @public
   3348 	 */
   3349 	Hash.prototype.destroy = function() {
   3350 		var handler, property;
   3351 
   3352 		$(window).off('hashchange.owl.navigation');
   3353 
   3354 		for (handler in this._handlers) {
   3355 			this._core.$element.off(handler, this._handlers[handler]);
   3356 		}
   3357 		for (property in Object.getOwnPropertyNames(this)) {
   3358 			typeof this[property] != 'function' && (this[property] = null);
   3359 		}
   3360 	};
   3361 
   3362 	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
   3363 
   3364 })(window.Zepto || window.jQuery, window, document);
   3365 
   3366 /**
   3367  * Support Plugin
   3368  *
   3369  * @version 2.3.4
   3370  * @author Vivid Planet Software GmbH
   3371  * @author Artus Kolanowski
   3372  * @author David Deutsch
   3373  * @license The MIT License (MIT)
   3374  */
   3375 ;(function($, window, document, undefined) {
   3376 
   3377 	var style = $('<support>').get(0).style,
   3378 		prefixes = 'Webkit Moz O ms'.split(' '),
   3379 		events = {
   3380 			transition: {
   3381 				end: {
   3382 					WebkitTransition: 'webkitTransitionEnd',
   3383 					MozTransition: 'transitionend',
   3384 					OTransition: 'oTransitionEnd',
   3385 					transition: 'transitionend'
   3386 				}
   3387 			},
   3388 			animation: {
   3389 				end: {
   3390 					WebkitAnimation: 'webkitAnimationEnd',
   3391 					MozAnimation: 'animationend',
   3392 					OAnimation: 'oAnimationEnd',
   3393 					animation: 'animationend'
   3394 				}
   3395 			}
   3396 		},
   3397 		tests = {
   3398 			csstransforms: function() {
   3399 				return !!test('transform');
   3400 			},
   3401 			csstransforms3d: function() {
   3402 				return !!test('perspective');
   3403 			},
   3404 			csstransitions: function() {
   3405 				return !!test('transition');
   3406 			},
   3407 			cssanimations: function() {
   3408 				return !!test('animation');
   3409 			}
   3410 		};
   3411 
   3412 	function test(property, prefixed) {
   3413 		var result = false,
   3414 			upper = property.charAt(0).toUpperCase() + property.slice(1);
   3415 
   3416 		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
   3417 			if (style[property] !== undefined) {
   3418 				result = prefixed ? property : true;
   3419 				return false;
   3420 			}
   3421 		});
   3422 
   3423 		return result;
   3424 	}
   3425 
   3426 	function prefixed(property) {
   3427 		return test(property, true);
   3428 	}
   3429 
   3430 	if (tests.csstransitions()) {
   3431 		/* jshint -W053 */
   3432 		$.support.transition = new String(prefixed('transition'))
   3433 		$.support.transition.end = events.transition.end[ $.support.transition ];
   3434 	}
   3435 
   3436 	if (tests.cssanimations()) {
   3437 		/* jshint -W053 */
   3438 		$.support.animation = new String(prefixed('animation'))
   3439 		$.support.animation.end = events.animation.end[ $.support.animation ];
   3440 	}
   3441 
   3442 	if (tests.csstransforms()) {
   3443 		/* jshint -W053 */
   3444 		$.support.transform = new String(prefixed('transform'));
   3445 		$.support.transform3d = tests.csstransforms3d();
   3446 	}
   3447 
   3448 })(window.Zepto || window.jQuery, window, document);