/**
 * @name Owl Carousel - code name Phenix
 * @author Bartosz Wojciechowski
 * @release 2014
 * Licensed under MIT
 *
 * @version 2.0.0-beta.1.8
 * @versionNotes Not compatibile with Owl Carousel <2.0.0
 */

/*

 {0,0}
 )_)
 ""

 To do:

 * Lazy Load Icon
 * prevent animationend bubling
 * itemsScaleUp
 * Test Zepto

 Callback events list:

 onInitBefore
 onInitAfter
 onResponsiveBefore
 onResponsiveAfter
 onTransitionStart
 onTransitionEnd
 onTouchStart
 onTouchEnd
 onChangeState
 onLazyLoaded
 onVideoPlay
 onVideoStop

 Custom events list:

 next.owl
 prev.owl
 goTo.owl
 jumpTo.owl
 addItem.owl
 removeItem.owl
 refresh.owl
 play.owl
 stop.owl
 stopVideo.owl

 */


;(function ( $, window, document, undefined ) {

  var defaults = {
    items:				3,
    loop:				false,
    center:				false,

    mouseDrag:			true,
    touchDrag:			true,
    pullDrag: 			true,
    freeDrag:			false,

    margin:				0,
    stagePadding:		0,

    merge:				false,
    mergeFit:			true,
    autoWidth:			false,
    autoHeight:			false,

    startPosition:		0,
    URLhashListener:	false,

    nav: 				false,
    navRewind:			true,
    navText: 			['prev','next'],
    slideBy:			1,
    dots: 				true,
    dotsEach:			false,
    dotData:			false,

    lazyLoad:			false,
    lazyContent:		false,

    autoplay:			false,
    autoplayTimeout:	5000,
    autoplayHoverPause:	false,

    smartSpeed:			250,
    fluidSpeed:			false,
    autoplaySpeed:		false,
    navSpeed:			false,
    dotsSpeed:			false,
    dragEndSpeed:		false,

    responsive: 		{},
    responsiveRefreshRate : 200,
    responsiveBaseElement: window,
    responsiveClass:	false,

    video:				false,
    videoHeight:		false,
    videoWidth:			false,

    animateOut:			false,
    animateIn:			false,

    fallbackEasing:		'swing',

    callbacks:			false,
    info: 				false,

    nestedItemSelector:	false,
    itemElement:		'div',
    stageElement:		'div',

    //Classes and Names
    themeClass: 		'owl-theme',
    baseClass:			'owl-carousel',
    itemClass:			'owl-item',
    centerClass:		'center',
    activeClass: 		'active',
    navContainerClass:	'owl-nav',
    navClass:			['owl-prev','owl-next'],
    controlsClass:		'owl-controls',
    dotClass: 			'owl-dot',
    dotsClass:			'owl-dots',
    autoHeightClass:	'owl-height'

  };

  // Reference to DOM elements
  // Those with $ sign are jQuery objects

  var dom = {
    el:			null,	// main element
    $el:		null,	// jQuery main element
    stage:		null,	// stage
    $stage:		null,	// jQuery stage
    oStage:		null,	// outer stage
    $oStage:	null,	// $ outer stage
    $items:		null,	// all items, clones and originals included
    $oItems:	null,	// original items
    $cItems:	null,	// cloned items only
    $cc:		null,
    $navPrev:	null,
    $navNext:	null,
    $page:		null,
    $nav:		null,
    $content:	null
  };

  /**
   * Variables
   * @since 2.0.0
   */

  // Only for development process

  // Widths

  var width = {
    el:			0,
    stage:		0,
    item:		0,
    prevWindow:	0,
    cloneLast:  0
  };

  // Numbers

  var num = {
    items:				0,
    oItems: 			0,
    cItems:				0,
    active:				0,
    merged:				[],
    nav:				[],
    allPages:			0
  };

  // Positions

  var pos = {
    start:		0,
    max:		0,
    maxValue:	0,
    prev:		0,
    current:	0,
    currentAbs:	0,
    currentPage:0,
    stage:		0,
    items:		[],
    lsCurrent:	0
  };

  // Drag/Touches

  var drag = {
    start:		0,
    startX:		0,
    startY:		0,
    current:	0,
    currentX:	0,
    currentY:	0,
    offsetX:	0,
    offsetY:	0,
    distance:	null,
    startTime:	0,
    endTime:	0,
    updatedX:	0,
    targetEl:	null
  };

  // Speeds

  var speed = {
    onDragEnd: 	300,
    nav:		300,
    css2speed:	0

  };

  // States

  var state = {
    isTouch:		false,
    isScrolling:	false,
    isSwiping:		false,
    direction:		false,
    inMotion:		false,
    autoplay:		false,
    lazyContent:	false
  };

  // Event functions references

  var e = {
    _onDragStart:	null,
    _onDragMove:	null,
    _onDragEnd:		null,
    _transitionEnd: null,
    _resizer:		null,
    _responsiveCall:null,
    _goToLoop:		null,
    _checkVisibile: null,
    _autoplay:		null,
    _pause:			null,
    _play:			null,
    _stop:			null
  };

  function Owl( element, options ) {

    // add basic Owl information to dom element

    element.owlCarousel = {
      'name':		'Owl Carousel',
      'author':	'Bartosz Wojciechowski',
      'version':	'2.0.0-beta.1.8',
      'released':	'03.05.2014'
    };

    // Attach variables to object
    // Only for development process

    this.options = 		$.extend( {}, defaults, options);
    this._options =		$.extend( {}, defaults, options);
    this.dom =			$.extend( {}, dom);
    this.width =		$.extend( {}, width);
    this.num =			$.extend( {}, num);
    this.pos =			$.extend( {}, pos);
    this.drag =			$.extend( {}, drag);
    this.speed =		$.extend( {}, speed);
    this.state =		$.extend( {}, state);
    this.e =			$.extend( {}, e);

    this.dom.el =		element;
    this.dom.$el =		$(element);
    this.init();
  }

  /**
   * init
   * @since 2.0.0
   */

  Owl.prototype.init = function(){

    this.fireCallback('onInitBefore');

    //Add base class
    if(!this.dom.$el.hasClass(this.options.baseClass)){
      this.dom.$el.addClass(this.options.baseClass);
    }

    //Add theme class
    if(!this.dom.$el.hasClass(this.options.themeClass)){
      this.dom.$el.addClass(this.options.themeClass);
    }

    //Add theme class
    if(this.options.rtl){
      this.dom.$el.addClass('owl-rtl');
    }

    // Check support
    this.browserSupport();

    // Sort responsive items in array
    this.sortOptions();

    // Update options.items on given size
    this.setResponsiveOptions();

    if(this.options.autoWidth && this.state.imagesLoaded !== true){
      var imgs = this.dom.$el.find('img');
      if(imgs.length){
        this.preloadAutoWidthImages(imgs);
        return false;
      }
    }

    // Get and store window width
    // iOS safari likes to trigger unnecessary resize event
    this.width.prevWindow = this.windowWidth();

    // create stage object
    this.createStage();

    // Append local content
    this.fetchContent();

    // attach generic events
    this.eventsCall();

    // attach custom control events
    this.addCustomEvents();

    // attach generic events
    this.internalEvents();

    this.dom.$el.addClass('owl-loading');
    this.refresh(true);
    this.dom.$el.removeClass('owl-loading').addClass('owl-loaded');
    this.fireCallback('onInitAfter');
  };

  /**
   * sortOptions
   * @desc Sort responsive sizes
   * @since 2.0.0
   */

  Owl.prototype.sortOptions = function(){

    var resOpt = this.options.responsive;
    this.responsiveSorted = {};
    var keys = [],
      i, j, k;
    for (i in resOpt){
      keys.push(i);
    }

    keys = keys.sort(function (a, b) {return a - b;});

    for (j = 0; j < keys.length; j++){
      k = keys[j];
      this.responsiveSorted[k] = resOpt[k];
    }

  };

  /**
   * setResponsiveOptions
   * @since 2.0.0
   */

  Owl.prototype.setResponsiveOptions = function(){
    if(this.options.responsive === false){return false;}

    var width = this.windowWidth();
    var resOpt = this.options.responsive;
    var i,j,k, minWidth;

    // overwrite non resposnive options
    for(k in this._options){
      if(k !== 'responsive'){
        this.options[k] = this._options[k];
      }
    }

    // find responsive width
    for (i in this.responsiveSorted){
      if(i<= width){
        minWidth = i;
        // set responsive options
        for(j in this.responsiveSorted[minWidth]){
          this.options[j] = this.responsiveSorted[minWidth][j];
        }

      }
    }
    this.num.breakpoint = minWidth;

    // Responsive Class
    if(this.options.responsiveClass){
      this.dom.$el.attr('class',
        function(i, c){
          return c.replace(/\b owl-responsive-\S+/g, '');
        }).addClass('owl-responsive-'+minWidth);
    }


  };

  /**
   * optionsLogic
   * @desc Update option logic if necessery
   * @since 2.0.0
   */

  Owl.prototype.optionsLogic = function(){
    // Toggle Center class
    this.dom.$el.toggleClass('owl-center',this.options.center);

    // Scroll per - 'page' option will scroll per visible items number
    // You can set this to any other number below visible items.
    if(this.options.slideBy && this.options.slideBy === 'page'){
      this.options.slideBy = this.options.items;
    } else if(this.options.slideBy > this.options.items){
      this.options.slideBy = this.options.items;
    }

    // if items number is less than in body
    if(this.options.loop && this.num.oItems < this.options.items){
      this.options.loop = false;
    }

    if(this.num.oItems <= this.options.items){
      this.options.navRewind = false;
    }

    if(this.options.autoWidth){
      this.options.stagePadding = false;
      this.options.dotsEach = 1;
      this.options.merge = false;
    }
    if(this.state.lazyContent){
      this.options.loop = false;
      this.options.merge = false;
      this.options.dots = false;
      this.options.freeDrag = false;
      this.options.lazyContent = true;
    }

    if((this.options.animateIn || this.options.animateOut) && this.options.items === 1 && this.support3d){
      this.state.animate = true;
    } else {this.state.animate = false;}

  };

  /**
   * createStage
   * @desc Create stage and Outer-stage elements
   * @since 2.0.0
   */

  Owl.prototype.createStage = function(){
    var oStage = document.createElement('div');
    var stage = document.createElement(this.options.stageElement);

    oStage.className = 'owl-stage-outer';
    stage.className = 'owl-stage';

    oStage.appendChild(stage);
    this.dom.el.appendChild(oStage);

    this.dom.oStage = oStage;
    this.dom.$oStage = $(oStage);
    this.dom.stage = stage;
    this.dom.$stage = $(stage);

    oStage = null;
    stage = null;
  };

  /**
   * createItem
   * @desc Create item container
   * @since 2.0.0
   */

  Owl.prototype.createItem = function(){
    var item = document.createElement(this.options.itemElement);
    item.className = this.options.itemClass;
    return item;
  };

  /**
   * fetchContent
   * @since 2.0.0
   */

  Owl.prototype.fetchContent = function(extContent){
    if(extContent){
      this.dom.$content = (extContent instanceof jQuery) ? extContent : $(extContent);
    }
    else if(this.options.nestedItemSelector){
      this.dom.$content= this.dom.$el.find('.'+this.options.nestedItemSelector).not('.owl-stage-outer');
    }
    else {
      this.dom.$content= this.dom.$el.children().not('.owl-stage-outer');
    }
    // content length
    this.num.oItems = this.dom.$content.length;

    // init Structure
    if(this.num.oItems !== 0){
      this.initStructure();
    }
  };


  /**
   * initStructure
   * @param [refresh] - if refresh and not lazyContent then dont create normal structure
   * @since 2.0.0
   */

  Owl.prototype.initStructure = function(){

    // lazyContent needs at least 3*items

    if(this.options.lazyContent && this.num.oItems >= this.options.items*3){
      this.state.lazyContent = true;
    } else {
      this.state.lazyContent = false;
    }

    if(this.state.lazyContent){

      // start position
      this.pos.currentAbs = this.options.items;

      //remove lazy content from DOM
      this.dom.$content.remove();

    } else {
      // create normal structure
      this.createNormalStructure();
    }
  };

  /**
   * createNormalStructure
   * @desc Create normal structure for small/mid weight content
   * @since 2.0.0
   */

  Owl.prototype.createNormalStructure = function(){
    for(var i = 0; i < this.num.oItems; i++){
      // fill 'owl-item' with content
      var item = this.fillItem(this.dom.$content,i);
      // append into stage
      this.dom.$stage.append(item);
    }
    this.dom.$content = null;
  };

  /**
   * createCustomStructure
   * @since 2.0.0
   */

  Owl.prototype.createCustomStructure = function(howManyItems){
    for(var i = 0; i < howManyItems; i++){
      var emptyItem = this.createItem();
      var item = $(emptyItem);

      this.setData(item,false);
      this.dom.$stage.append(item);
    }
  };

  /**
   * createLazyContentStructure
   * @desc Create lazyContent structure for large content and better mobile experience
   * @since 2.0.0
   */

  Owl.prototype.createLazyContentStructure = function(refresh){
    if(!this.state.lazyContent){return false;}

    // prevent recreate - to do
    if(refresh && this.dom.$stage.children().length === this.options.items*3){
      return false;
    }
    // remove items from stage
    this.dom.$stage.empty();

    // create custom structure
    this.createCustomStructure(3*this.options.items);
  };

  /**
   * fillItem
   * @desc Fill empty item container with provided content
   * @since 2.0.0
   * @param [content] - string/$dom - passed owl-item
   * @param [i] - index in jquery object
   * return $ new object
   */

  Owl.prototype.fillItem = function(content,i){
    var emptyItem = this.createItem();
    var c = content[i] || content;
    // set item data
    var traversed = this.traversContent(c);
    this.setData(emptyItem,false,traversed);
    return $(emptyItem).append(c);
  };

  /**
   * traversContent
   * @since 2.0.0
   * @param [c] - content
   * return object
   */

  Owl.prototype.traversContent = function(c){
    var $c = $(c), dotValue, hashValue;
    if(this.options.dotData){
      dotValue = $c.find('[data-dot]').andSelf().data('dot');
    }
    // update URL hash
    if(this.options.URLhashListener){
      hashValue = $c.find('[data-hash]').andSelf().data('hash');
    }
    return {
      dot : dotValue || false,
      hash : hashValue  || false
    };
  };


  /**
   * setData
   * @desc Set item jQuery Data
   * @since 2.0.0
   * @param [item] - dom - passed owl-item
   * @param [cloneObj] - $dom - passed clone item
   */


  Owl.prototype.setData = function(item,cloneObj,traversed){
    var dot,hash;
    if(traversed){
      dot = traversed.dot;
      hash = traversed.hash;
    }
    var itemData = {
      index:		false,
      indexAbs:	false,
      posLeft:	false,
      clone:		false,
      active:		false,
      loaded:		false,
      lazyLoad:	false,
      current:	false,
      width:		false,
      center:		false,
      page:		false,
      hasVideo:	false,
      playVideo:	false,
      dot:		dot,
      hash:		hash
    };

    // copy itemData to cloned item

    if(cloneObj){
      itemData = $.extend({}, itemData, cloneObj.data('owl-item'));
    }

    $(item).data('owl-item', itemData);
  };

  /**
   * updateLocalContent
   * @since 2.0.0
   */

  Owl.prototype.updateLocalContent = function(){
    this.dom.$oItems = this.dom.$stage.find('.'+this.options.itemClass).filter(function(){
      return $(this).data('owl-item').clone === false;
    });

    this.num.oItems = this.dom.$oItems.length;
    //update index on original items

    for(var k = 0; k<this.num.oItems; k++){
      var item = this.dom.$oItems.eq(k);
      item.data('owl-item').index = k;
    }
  };

  /**
   * checkVideoLinks
   * @desc Check if for any videos links
   * @since 2.0.0
   */

  Owl.prototype.checkVideoLinks = function(){
    if(!this.options.video){return false;}
    var videoEl,item;

    for(var i = 0; i<this.num.items; i++){

      item = this.dom.$items.eq(i);
      if(item.data('owl-item').hasVideo){
        continue;
      }

      videoEl = item.find('.owl-video');
      if(videoEl.length){
        this.state.hasVideos = true;
        this.dom.$items.eq(i).data('owl-item').hasVideo = true;
        videoEl.css('display','none');
        this.getVideoInfo(videoEl,item);
      }
    }
  };

  /**
   * getVideoInfo
   * @desc Get Video ID and Type (YouTube/Vimeo only)
   * @since 2.0.0
   */

  Owl.prototype.getVideoInfo = function(videoEl,item){

    var info, type, id,
      vimeoId = videoEl.data('vimeo-id'),
      youTubeId = videoEl.data('youtube-id'),
      width = videoEl.data('width') || this.options.videoWidth,
      height = videoEl.data('height') || this.options.videoHeight,
      url = videoEl.attr('href');

    if(vimeoId){
      type = 'vimeo';
      id = vimeoId;
    } else if(youTubeId){
      type = 'youtube';
      id = youTubeId;
    } else if(url){
      id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);

      if (id[3].indexOf('youtu') > -1) {
        type = 'youtube';
      } else if (id[3].indexOf('vimeo') > -1) {
        type = 'vimeo';
      }
      id = id[6];
    } else {
      throw new Error('Missing video link.');
    }

    item.data('owl-item').videoType = type;
    item.data('owl-item').videoId = id;
    item.data('owl-item').videoWidth = width;
    item.data('owl-item').videoHeight = height;

    info = {
      type: type,
      id: id
    };

    // Check dimensions
    var dimensions = width && height ? 'style="width:'+width+'px;height:'+height+'px;"' : '';

    // wrap video content into owl-video-wrapper div
    videoEl.wrap('<div class="owl-video-wrapper"'+dimensions+'></div>');

    this.createVideoTn(videoEl,info);
  };

  /**
   * createVideoTn
   * @desc Create Video Thumbnail
   * @since 2.0.0
   */

  Owl.prototype.createVideoTn = function(videoEl,info){

    var tnLink,icon,height;
    var customTn = videoEl.find('img');
    var srcType = 'src';
    var lazyClass = '';
    var that = this;

    if(this.options.lazyLoad){
      srcType = 'data-src';
      lazyClass = 'owl-lazy';
    }

    // Custom thumbnail

    if(customTn.length){
      addThumbnail(customTn.attr(srcType));
      customTn.remove();
      return false;
    }

    function addThumbnail(tnPath){
      icon = '<div class="owl-video-play-icon"></div>';

      if(that.options.lazyLoad){
        tnLink = '<div class="owl-video-tn '+ lazyClass +'" '+ srcType +'="'+ tnPath +'"></div>';
      } else{
        tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + tnPath + ')"></div>';
      }
      videoEl.after(tnLink);
      videoEl.after(icon);
    }

    if(info.type === 'youtube'){
      var path = "http://img.youtube.com/vi/"+ info.id +"/hqdefault.jpg";
      addThumbnail(path);
    } else
    if(info.type === 'vimeo'){
      $.ajax({
        type:'GET',
        url: 'http://vimeo.com/api/v2/video/' + info.id + '.json',
        jsonp: 'callback',
        dataType: 'jsonp',
        success: function(data){
          var path = data[0].thumbnail_large;
          addThumbnail(path);
          if(that.options.loop){
            that.updateItemState();
          }
        }
      });
    }
  };

  /**
   * stopVideo
   * @since 2.0.0
   */

  Owl.prototype.stopVideo = function(){
    this.fireCallback('onVideoStop');
    var item = this.dom.$items.eq(this.state.videoPlayIndex);
    item.find('.owl-video-frame').remove();
    item.removeClass('owl-video-playing');
    this.state.videoPlay = false;
  };

  /**
   * playVideo
   * @since 2.0.0
   */

  Owl.prototype.playVideo = function(ev){
    this.fireCallback('onVideoPlay');

    if(this.state.videoPlay){
      this.stopVideo();
    }
    var videoLink,videoWrap,
      target = $(ev.target || ev.srcElement),
      item = target.closest('.'+this.options.itemClass);

    var videoType = item.data('owl-item').videoType,
      id = item.data('owl-item').videoId,
      width = item.data('owl-item').videoWidth || Math.floor(item.data('owl-item').width - this.options.margin),
      height = item.data('owl-item').videoHeight || this.dom.$stage.height();

    if(videoType === 'youtube'){
      videoLink = "<iframe width=\""+ width +"\" height=\""+ height +"\" src=\"http://www.youtube.com/embed/" + id + "?autoplay=1&v=" + id + "\" frameborder=\"0\" allowfullscreen></iframe>";
    } else if(videoType === 'vimeo'){
      videoLink = '<iframe src="http://player.vimeo.com/video/'+ id +'?autoplay=1" width="'+ width +'" height="'+ height +'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
    }

    item.addClass('owl-video-playing');
    this.state.videoPlay = true;
    this.state.videoPlayIndex = item.data('owl-item').indexAbs;

    videoWrap = $('<div style="height:'+ height +'px; width:'+ width +'px" class="owl-video-frame">' + videoLink + '</div>');
    target.after(videoWrap);
  };

  /**
   * loopClone
   * @desc Make a clones for infinity loop
   * @since 2.0.0
   */

  Owl.prototype.loopClone = function(){
    if(!this.options.loop || this.state.lazyContent || this.num.oItems < this.options.items){return false;}

    var firstClone,	lastClone, i,
      num	=		this.options.items,
      lastNum =	this.num.oItems-1;

    // if neighbour margin then add one more duplicat
    if(this.options.stagePadding && this.options.items === 1){
      num+=1;
    }
    this.num.cItems = num * 2;

    for(i = 0; i < num; i++){
      // Clone item
      var first =		this.dom.$oItems.eq(i).clone(true,true);
      var last =		this.dom.$oItems.eq(lastNum-i).clone(true,true);
      firstClone = 	$(first[0]).addClass('cloned');
      lastClone = 	$(last[0]).addClass('cloned');

      // set clone data
      // Somehow data has reference to same data id in cash

      this.setData(firstClone[0],first);
      this.setData(lastClone[0],last);

      firstClone.data('owl-item').clone = true;
      lastClone.data('owl-item').clone = true;

      this.dom.$stage.append(firstClone);
      this.dom.$stage.prepend(lastClone);

      firstClone = lastClone = null;
    }

    this.dom.$cItems = this.dom.$stage.find('.'+this.options.itemClass).filter(function(){
      return $(this).data('owl-item').clone === true;
    });
  };

  /**
   * reClone
   * @desc Update Cloned elements
   * @since 2.0.0
   */

  Owl.prototype.reClone = function(){
    // remove cloned items
    if(this.dom.$cItems !== null){ // && (this.num.oItems !== 0 && this.num.oItems <= this.options.items)){
      this.dom.$cItems.remove();
      this.dom.$cItems = null;
      this.num.cItems = 0;
    }

    if(!this.options.loop){
      return;
    }
    // generete new elements
    this.loopClone();
  };

  /**
   * calculate
   * @desc Update item index data
   * @since 2.0.0
   */

  Owl.prototype.calculate = function(){

    var i,j,k,dist,posLeft=0,fullWidth=0;

    // element width minus neighbour
    this.width.el = this.dom.$el.width() - (this.options.stagePadding*2);

    //to check
    this.width.view = this.dom.$el.width();

    // calculate width minus addition margins
    var elMinusMargin = this.width.el - (this.options.margin * (this.options.items === 1 ? 0 : this.options.items -1));

    // calculate element width and item width
    this.width.el =  	this.width.el + this.options.margin;
    this.width.item = 	((elMinusMargin / this.options.items) + this.options.margin).toFixed(3);

    this.dom.$items = 	this.dom.$stage.find('.owl-item');
    this.num.items = 	this.dom.$items.length;

    //change to autoWidths
    if(this.options.autoWidth){
      this.dom.$items.css('width','');
    }

    // Set grid array
    this.pos.items = 	[];
    this.num.merged = 	[];
    this.num.nav = 		[];

    // item distances
    if(this.options.rtl){
      dist = this.options.center ? -((this.width.el)/2) : 0;
    } else {
      dist = this.options.center ? (this.width.el)/2 : 0;
    }

    this.width.mergeStage = 0;

    // Calculate items positions
    for(i = 0; i<this.num.items; i++){

      // check merged items

      if(this.options.merge){
        var mergeNumber = this.dom.$items.eq(i).find('[data-merge]').attr('data-merge') || 1;
        if(this.options.mergeFit && mergeNumber > this.options.items){
          mergeNumber = this.options.items;
        }
        this.num.merged.push(parseInt(mergeNumber));
        this.width.mergeStage += this.width.item * this.num.merged[i];
      } else {
        this.num.merged.push(1);
      }

      // Array based on merged items used by dots and navigation
      if(this.options.loop){
        if(i>=this.num.cItems/2 && i<this.num.cItems/2+this.num.oItems){
          this.num.nav.push(this.num.merged[i]);
        }
      } else {
        this.num.nav.push(this.num.merged[i]);
      }

      var iWidth = this.width.item * this.num.merged[i];

      // autoWidth item size
      if(this.options.autoWidth){
        iWidth = this.dom.$items.eq(i).width() + this.options.margin;
        if(this.options.rtl){
          this.dom.$items[i].style.marginLeft = this.options.margin + 'px';
        } else {
          this.dom.$items[i].style.marginRight = this.options.margin + 'px';
        }

      }
      // push item position into array
      this.pos.items.push(dist);

      // update item data
      this.dom.$items.eq(i).data('owl-item').posLeft = posLeft;
      this.dom.$items.eq(i).data('owl-item').width = iWidth;

      // dist starts from middle of stage if center
      // posLeft always starts from 0
      if(this.options.rtl){
        dist += iWidth;
        posLeft += iWidth;
      } else{
        dist -= iWidth;
        posLeft -= iWidth;
      }

      fullWidth -= Math.abs(iWidth);

      // update position if center
      if(this.options.center){
        this.pos.items[i] = !this.options.rtl ? this.pos.items[i] - (iWidth/2) : this.pos.items[i] + (iWidth/2);
      }
    }

    if(this.options.autoWidth){
      this.width.stage = this.options.center ? Math.abs(fullWidth) : Math.abs(dist);
    } else {
      this.width.stage = Math.abs(fullWidth);
    }

    //update indexAbs on all items
    var allItems = this.num.oItems + this.num.cItems;

    for(j = 0; j< allItems; j++){
      this.dom.$items.eq(j).data('owl-item').indexAbs = j;
    }

    // Set Min and Max
    this.setMinMax();

    // Recalculate grid
    this.setSizes();
  };

  /**
   * setMinMax
   * @since 2.0.0
   */

  Owl.prototype.setMinMax = function(){

    // set Min
    var minimum = this.dom.$oItems.eq(0).data('owl-item').indexAbs;
    this.pos.min = 0;
    this.pos.minValue = this.pos.items[minimum];

    // set max position
    if(!this.options.loop){
      this.pos.max = this.num.oItems-1;
    }

    if(this.options.loop){
      this.pos.max = this.num.oItems+this.options.items;
    }

    if(!this.options.loop && !this.options.center){
      this.pos.max = this.num.oItems-this.options.items;
    }

    if(this.options.loop && this.options.center){
      this.pos.max = this.num.oItems+this.options.items;
    }

    //set max value
    this.pos.maxValue = this.pos.items[this.pos.max];

    //Max for autoWidth content
    if((!this.options.loop && !this.options.center && this.options.autoWidth) || (this.options.merge && !this.options.center) ){
      var revert = this.options.rtl ? 1 : -1;
      for (i = 0; i < this.pos.items.length; i++) {
        if( (this.pos.items[i] * revert) < this.width.stage-this.width.el ){
          this.pos.max = i+1;
        }
      }
      this.pos.maxValue = this.options.rtl ? this.width.stage-this.width.el : -(this.width.stage-this.width.el);
      this.pos.items[this.pos.max] = this.pos.maxValue;
    }

    // Set loop boundries
    if(this.options.center){
      this.pos.loop = this.pos.items[0]-this.pos.items[this.num.oItems];
    } else {
      this.pos.loop = -this.pos.items[this.num.oItems];
    }

    //if is less items
    if(this.num.oItems < this.options.items && !this.options.center){
      this.pos.max = 0;
      this.pos.maxValue = this.pos.items[0];
    }
  };

  /**
   * setSizes
   * @desc Set sizes on elements (from collectData function)
   * @since 2.0.0
   */

  Owl.prototype.setSizes = function(){

    // show neighbours
    if(this.options.stagePadding !== false){
      this.dom.oStage.style.paddingLeft = 	this.options.stagePadding + 'px';
      this.dom.oStage.style.paddingRight = 	this.options.stagePadding + 'px';
    }

    // CRAZY FIX!!! Doublecheck this!
    //if(this.width.stagePrev > this.width.stage){
    if(this.options.rtl){
      window.setTimeout(function(){
        this.dom.stage.style.width = this.width.stage + 'px';
      }.bind(this),0);
    } else{
      this.dom.stage.style.width = this.width.stage + 'px';
    }

    for(var i=0; i<this.num.items; i++){

      // Set items width
      if(!this.options.autoWidth){
        this.dom.$items[i].style.width = this.width.item - (this.options.margin) + 'px';
      }
      // add margin
      if(this.options.rtl){
        this.dom.$items[i].style.marginLeft = this.options.margin + 'px';
      } else {
        this.dom.$items[i].style.marginRight = this.options.margin + 'px';
      }

      if(this.num.merged[i] !== 1 && !this.options.autoWidth){
        this.dom.$items[i].style.width = (this.width.item * this.num.merged[i]) - (this.options.margin) + 'px';
      }
    }

    // save prev stage size
    this.width.stagePrev = this.width.stage;
  };

  /**
   * responsive
   * @desc Responsive function update all data by calling refresh()
   * @since 2.0.0
   */

  Owl.prototype.responsive = function(){

    if(!this.num.oItems){return false;}
    // If El width hasnt change then stop responsive
    var elChanged = this.isElWidthChanged();
    if(!elChanged){return false;}

    // if Vimeo Fullscreen mode
    var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement;
    if(fullscreenElement){
      if($(fullscreenElement.parentNode).hasClass('owl-video-frame')){
        this.setSpeed(0);
        this.state.isFullScreen = true;
      }
    }

    if(fullscreenElement && this.state.isFullScreen && this.state.videoPlay){
      return false;
    }

    // Comming back from fullscreen
    if(this.state.isFullScreen){
      this.state.isFullScreen = false;
      return false;
    }

    // check full screen mode and window orientation
    if (this.state.videoPlay) {
      if(this.state.orientation !== window.orientation){
        this.state.orientation = window.orientation;
        return false;
      }
    }

    this.fireCallback('onResponsiveBefore');
    this.state.responsive = true;
    this.refresh();
    this.state.responsive = false;
    this.fireCallback('onResponsiveAfter');
  };

  /**
   * refresh
   * @desc Refresh method is basically collection of functions that are responsible for Owl responsive functionality
   * @since 2.0.0
   */

  Owl.prototype.refresh = function(init){

    if(this.state.videoPlay){
      this.stopVideo();
    }

    // Update Options for given width
    this.setResponsiveOptions();

    //set lazy structure
    this.createLazyContentStructure(true);

    // update info about local content
    this.updateLocalContent();

    // udpate options
    this.optionsLogic();

    // if no items then stop
    if(this.num.oItems === 0){
      if(this.dom.$page !== null){
        this.dom.$page.hide();
      }
      return false;
    }

    // Hide and Show methods helps here to set a proper widths.
    // This prevents Scrollbar to be calculated in stage width
    this.dom.$stage.addClass('owl-refresh');

    // Remove clones and generate new ones
    this.reClone();

    // calculate
    this.calculate();

    //aaaand show.
    this.dom.$stage.removeClass('owl-refresh');

    // to do
    // lazyContent last position on refresh
    if(this.state.lazyContent){
      this.pos.currentAbs = this.options.items;
    }

    this.initPosition(init);

    // jump to last position
    if(!this.state.lazyContent && !init){
      this.jumpTo(this.pos.current,false); // fix that
    }

    //Check for videos ( YouTube and Vimeo currently supported)
    this.checkVideoLinks();

    this.updateItemState();

    // Update controls
    this.rebuildDots();

    this.updateControls();

    // update drag events
    //this.updateEvents();

    // update autoplay
    this.autoplay();

    this.autoHeight();

    this.state.orientation = window.orientation;

    this.watchVisibility();
  };

  /**
   * updateItemState
   * @desc Update information about current state of items (visibile, hidden, active, etc.)
   * @since 2.0.0
   */

  Owl.prototype.updateItemState = function(update){

    if(!this.state.lazyContent){
      this.updateActiveItems();
    } else {
      this.updateLazyContent(update);
    }

    if(this.options.center){
      this.dom.$items.eq(this.pos.currentAbs)
        .addClass(this.options.centerClass)
        .data('owl-item').center = true;
    }

    if(this.options.lazyLoad){
      this.lazyLoad();
    }
  };

  /**
   * updateActiveItems
   * @since 2.0.0
   */


  Owl.prototype.updateActiveItems = function(){
    var i,j,item,ipos,iwidth,wpos,stage,outsideView,foundCurrent;
    // clear states
    for(i = 0; i<this.num.items; i++){
      this.dom.$items.eq(i).data('owl-item').active = false;
      this.dom.$items.eq(i).data('owl-item').current = false;
      this.dom.$items.eq(i).removeClass(this.options.activeClass).removeClass(this.options.centerClass);
    }

    this.num.active = 0;
    stageX = this.pos.stage;
    view = this.options.rtl ? this.width.view : -this.width.view;

    for(j = 0; j<this.num.items; j++){

      item = this.dom.$items.eq(j);
      ipos = item.data('owl-item').posLeft;
      iwidth = item.data('owl-item').width;
      outsideView = this.options.rtl ? ipos + iwidth : ipos - iwidth;

      if( (this.op(ipos,'<=',stageX) && (this.op(ipos,'>',stageX + view))) ||
        (this.op(outsideView,'<',stageX) && this.op(outsideView,'>',stageX + view))
      ){

        this.num.active++;

        if(this.options.freeDrag && !foundCurrent){
          foundCurrent = true;
          this.pos.current = item.data('owl-item').index;
          this.pos.currentAbs = item.data('owl-item').indexAbs;
        }

        item.data('owl-item').active = true;
        item.data('owl-item').current = true;
        item.addClass(this.options.activeClass);

        if(!this.options.lazyLoad){
          item.data('owl-item').loaded = true;
        }
        if(this.options.loop && (this.options.lazyLoad || this.options.center)){
          this.updateClonedItemsState(item.data('owl-item').index);
        }
      }
    }
  };

  /**
   * updateClonedItemsState
   * @desc Set current state on sibilings items for lazyLoad and center
   * @since 2.0.0
   */

  Owl.prototype.updateClonedItemsState = function(activeIndex){

    //find cloned center
    var center, $el,i;
    if(this.options.center){
      center = this.dom.$items.eq(this.pos.currentAbs).data('owl-item').index;
    }

    for(i = 0; i<this.num.items; i++){
      $el = this.dom.$items.eq(i);
      if( $el.data('owl-item').index === activeIndex ){
        $el.data('owl-item').current = true;
        if($el.data('owl-item').index === center ){
          $el.addClass(this.options.centerClass);
        }
      }
    }
  };

  /**
   * updateLazyPosition
   * @desc Set current state on sibilings items for lazyLoad and center
   * @since 2.0.0
   */

  Owl.prototype.updateLazyPosition = function(){
    var jumpTo = this.pos.goToLazyContent || 0;

    this.pos.lcMovedBy = Math.abs(this.options.items - this.pos.currentAbs);

    if(this.options.items < this.pos.currentAbs ){
      this.pos.lcCurrent += this.pos.currentAbs - this.options.items;
      this.state.lcDirection = 'right';
    } else if(this.options.items > this.pos.currentAbs ){
      this.pos.lcCurrent -= this.options.items - this.pos.currentAbs;
      this.state.lcDirection = 'left';
    }

    this.pos.lcCurrent = jumpTo !== 0 ? jumpTo : this.pos.lcCurrent;

    if(this.pos.lcCurrent >= this.dom.$content.length){
      this.pos.lcCurrent = this.pos.lcCurrent-this.dom.$content.length;
    } else if(this.pos.lcCurrent < -this.dom.$content.length+1){
      this.pos.lcCurrent = this.pos.lcCurrent+this.dom.$content.length;
    }

    if(this.options.startPosition>0){
      this.pos.lcCurrent = this.options.startPosition;
      this._options.startPosition = this.options.startPosition = 0;
    }

    this.pos.lcCurrentAbs = this.pos.lcCurrent < 0 ? this.pos.lcCurrent+this.dom.$content.length : this.pos.lcCurrent;

  };

  /**
   * updateLazyContent
   * @param [update] - boolean - update call by content manipulations
   * @since 2.0.0
   */

  Owl.prototype.updateLazyContent = function(update){

    if(this.pos.lcCurrent === undefined){
      this.pos.lcCurrent = 0;
      this.pos.current = this.pos.currentAbs = this.options.items;
    }

    if(!update){
      this.updateLazyPosition();
    }
    var i,j,item,contentPos,content,freshItem,freshData;

    if(this.state.lcDirection !== false){
      for(i = 0; i<this.pos.lcMovedBy; i++){

        if(this.state.lcDirection === 'right'){
          item = this.dom.$stage.find('.owl-item').eq(0); //.appendTo(this.dom.$stage);
          item.appendTo(this.dom.$stage);
        }
        if(this.state.lcDirection === 'left'){
          item = this.dom.$stage.find('.owl-item').eq(-1);
          item.prependTo(this.dom.$stage);
        }
        item.data('owl-item').active = false;
      }
    }

    // recollect
    this.dom.$items = this.dom.$stage.find('.owl-item');

    for(j = 0; j<this.num.items; j++){
      // to do
      this.dom.$items.eq(j).removeClass(this.options.centerClass);

      // get Content
      contentPos = this.pos.lcCurrent + j - this.options.items;// + this.options.startPosition;

      if(contentPos >= this.dom.$content.length){
        contentPos = contentPos - this.dom.$content.length;
      }
      if(contentPos < -this.dom.$content.length){
        contentPos = contentPos + this.dom.$content.length;
      }

      content = this.dom.$content.eq(contentPos);
      freshItem = this.dom.$items.eq(j);
      freshData = freshItem.data('owl-item');

      if(freshData.active === false || this.pos.goToLazyContent !== 0 || update === true){

        freshItem.empty();
        freshItem.append(content.clone(true,true));
        freshData.active = true;
        freshData.current = true;
        if(!this.options.lazyLoad){
          freshData.loaded = true;
        } else {
          freshData.loaded = false;
        }
      }
    }

    this.pos.goToLazyContent = 0;
    this.pos.current = this.pos.currentAbs = this.options.items;
    this.setSpeed(0);
    this.animStage(this.pos.items[this.options.items]);
  };

  /**
   * eventsCall
   * @desc Save internal event references and add event based functions like transitionEnd,responsive etc.
   * @since 2.0.0
   */

  Owl.prototype.eventsCall = function(){
    // Save events references
    this.e._onDragStart =	function(e){this.onDragStart(e);		}.bind(this);
    this.e._onDragMove =	function(e){this.onDragMove(e);			}.bind(this);
    this.e._onDragEnd =		function(e){this.onDragEnd(e);			}.bind(this);
    this.e._transitionEnd =	function(e){this.transitionEnd(e);		}.bind(this);
    this.e._resizer =		function(){this.responsiveTimer();		}.bind(this);
    this.e._responsiveCall =function(){this.responsive();			}.bind(this);
    this.e._preventClick =	function(e){this.preventClick(e);		}.bind(this);
    this.e._goToHash =		function(){this.goToHash();				}.bind(this);
    this.e._goToPage =		function(e){this.goToPage(e);			}.bind(this);
    this.e._ap = 			function(){this.autoplay();				}.bind(this);
    this.e._play = 			function(){this.play();					}.bind(this);
    this.e._pause = 		function(){this.pause();				}.bind(this);
    this.e._playVideo = 	function(e){this.playVideo(e);			}.bind(this);

    this.e._navNext = function(e){
      if($(e.target).hasClass('disabled')){return false;}
      e.preventDefault();
      this.next();
    }.bind(this);

    this.e._navPrev = function(e){
      if($(e.target).hasClass('disabled')){return false;}
      e.preventDefault();
      this.prev();
    }.bind(this);

  };

  /**
   * responsiveTimer
   * @desc Check Window resize event with 200ms delay / this.options.responsiveRefreshRate
   * @since 2.0.0
   */

  Owl.prototype.responsiveTimer = function(){
    if(this.windowWidth() === this.width.prevWindow){
      return false;
    }
    window.clearInterval(this.e._autoplay);
    window.clearTimeout(this.resizeTimer);
    this.resizeTimer = window.setTimeout(this.e._responsiveCall, this.options.responsiveRefreshRate);
    this.width.prevWindow = this.windowWidth();
  };

  /**
   * internalEvents
   * @desc Checks for touch/mouse drag options and add necessery event handlers.
   * @since 2.0.0
   */

  Owl.prototype.internalEvents = function(){
    var isTouch = isTouchSupport();
    var isTouchIE = isTouchSupportIE();

    if(isTouch && !isTouchIE){
      this.dragType = ['touchstart','touchmove','touchend','touchcancel'];
    } else if(isTouch && isTouchIE){
      this.dragType = ['MSPointerDown','MSPointerMove','MSPointerUp','MSPointerCancel'];
    } else {
      this.dragType = ['mousedown','mousemove','mouseup'];
    }

    if( (isTouch || isTouchIE) && this.options.touchDrag){
      //touch cancel event
      this.on(document, this.dragType[3], this.e._onDragEnd);

    } else {
      // firefox startdrag fix - addeventlistener doesnt work here :/
      this.dom.$stage.on('dragstart', function() {return false;});

      if(this.options.mouseDrag){
        //disable text select
        this.dom.stage.onselectstart = function(){return false;};
      } else {
        // enable text select
        this.dom.$el.addClass('owl-text-select-on');
      }
    }

    // Video Play Button event delegation
    this.dom.$stage.on(this.dragType[2], '.owl-video-play-icon', this.e._playVideo);

    if(this.options.URLhashListener){
      this.on(window, 'hashchange', this.e._goToHash, false);
    }

    if(this.options.autoplayHoverPause){
      var that = this;
      this.dom.$stage.on('mouseover', this.e._pause );
      this.dom.$stage.on('mouseleave', this.e._ap );
    }

    // Catch transitionEnd event
    if(this.transitionEndVendor){
      this.on(this.dom.stage, this.transitionEndVendor, this.e._transitionEnd, false);
    }

    // Responsive
    if(this.options.responsive !== false){
      this.on(window, 'resize', this.e._resizer, false);
    }

    this.updateEvents();
  };

  /**
   * updateEvents
   * @since 2.0.0
   */

  Owl.prototype.updateEvents = function(){

    if(this.options.touchDrag && (this.dragType[0] === 'touchstart' || this.dragType[0] === 'MSPointerDown')){
      this.on(this.dom.stage, this.dragType[0], this.e._onDragStart,false);
    } else if(this.options.mouseDrag && this.dragType[0] === 'mousedown'){
      this.on(this.dom.stage, this.dragType[0], this.e._onDragStart,false);

    } else {
      this.off(this.dom.stage, this.dragType[0], this.e._onDragStart);
    }
  };

  /**
   * onDragStart
   * @desc touchstart/mousedown event
   * @since 2.0.0
   */

  Owl.prototype.onDragStart = function(event){
    var ev = event.originalEvent || event || window.event;
    // prevent right click
    if (ev.which === 3) {
      return false;
    }

    if(this.dragType[0] === 'mousedown'){
      this.dom.$stage.addClass('owl-grab');
    }

    this.fireCallback('onTouchStart');
    this.drag.startTime = new Date().getTime();
    this.setSpeed(0);
    this.state.isTouch = true;
    this.state.isScrolling = false;
    this.state.isSwiping = false;
    this.drag.distance = 0;

    // if is 'touchstart'
    var isTouchEvent = ev.type === 'touchstart';
    var pageX = isTouchEvent ? event.targetTouches[0].pageX : (ev.pageX || ev.clientX);
    var pageY = isTouchEvent ? event.targetTouches[0].pageY : (ev.pageY || ev.clientY);

    //get stage position left
    this.drag.offsetX = this.dom.$stage.position().left - this.options.stagePadding;
    this.drag.offsetY = this.dom.$stage.position().top;

    if(this.options.rtl){
      this.drag.offsetX = this.dom.$stage.position().left + this.width.stage - this.width.el + this.options.margin;
    }

    //catch position // ie to fix
    if(this.state.inMotion && this.support3d){
      var animatedPos = this.getTransformProperty();
      this.drag.offsetX = animatedPos;
      this.animStage(animatedPos);
    } else if(this.state.inMotion && !this.support3d ){
      this.state.inMotion = false;
      return false;
    }

    this.drag.startX = pageX - this.drag.offsetX;
    this.drag.startY = pageY - this.drag.offsetY;

    this.drag.start = pageX - this.drag.startX;
    this.drag.targetEl = ev.target || ev.srcElement;
    this.drag.updatedX = this.drag.start;

    // to do/check
    //prevent links and images dragging;
    //this.drag.targetEl.draggable = false;

    this.on(document, this.dragType[1], this.e._onDragMove, false);
    this.on(document, this.dragType[2], this.e._onDragEnd, false);
  };

  /**
   * onDragMove
   * @desc touchmove/mousemove event
   * @since 2.0.0
   */

  Owl.prototype.onDragMove = function(event){
    if (!this.state.isTouch){
      return;
    }

    if (this.state.isScrolling){
      return;
    }

    var neighbourItemWidth=0;
    var ev = event.originalEvent || event || window.event;

    // if is 'touchstart'
    var isTouchEvent = ev.type == 'touchmove';
    var pageX = isTouchEvent ? ev.targetTouches[0].pageX : (ev.pageX || ev.clientX);
    var pageY = isTouchEvent ? ev.targetTouches[0].pageY : (ev.pageY || ev.clientY);

    // Drag Direction
    this.drag.currentX = pageX - this.drag.startX;
    this.drag.currentY = pageY - this.drag.startY;
    this.drag.distance = this.drag.currentX - this.drag.offsetX;

    // Check move direction
    if (this.drag.distance < 0) {
      this.state.direction = this.options.rtl ? 'right' : 'left';
    } else if(this.drag.distance > 0){
      this.state.direction = this.options.rtl ? 'left' : 'right';
    }
    // Loop
    if(this.options.loop){
      if(this.op(this.drag.currentX, '>', this.pos.minValue) && this.state.direction === 'right' ){
        this.drag.currentX -= this.pos.loop;
      }else if(this.op(this.drag.currentX, '<', this.pos.maxValue) && this.state.direction === 'left' ){
        this.drag.currentX += this.pos.loop;
      }
    } else {
      // pull
      var minValue = this.options.rtl ? this.pos.maxValue : this.pos.minValue;
      var maxValue = this.options.rtl ? this.pos.minValue : this.pos.maxValue;
      var pull = this.options.pullDrag ? this.drag.distance / 5 : 0;
      this.drag.currentX = Math.max(Math.min(this.drag.currentX, minValue + pull), maxValue + pull);
    }



    // Lock browser if swiping horizontal

    if ((this.drag.distance > 8 || this.drag.distance < -8)) {
      if (ev.preventDefault !== undefined) {
        ev.preventDefault();
      } else {
        ev.returnValue = false;
      }
      this.state.isSwiping = true;
    }

    this.drag.updatedX = this.drag.currentX;

    // Lock Owl if scrolling
    if ((this.drag.currentY > 16 || this.drag.currentY < -16) && this.state.isSwiping === false) {
      this.state.isScrolling = true;
      this.drag.updatedX = this.drag.start;
    }

    this.animStage(this.drag.updatedX);
  };

  /**
   * onDragEnd
   * @desc touchend/mouseup event
   * @since 2.0.0
   */

  Owl.prototype.onDragEnd = function(event){
    if (!this.state.isTouch){
      return;
    }
    if(this.dragType[0] === 'mousedown'){
      this.dom.$stage.removeClass('owl-grab');
    }

    this.fireCallback('onTouchEnd');

    //prevent links and images dragging;
    //this.drag.targetEl.draggable = true;

    //remove drag event listeners

    this.state.isTouch = false;
    this.state.isScrolling = false;
    this.state.isSwiping = false;

    //to check
    if(this.drag.distance === 0 && this.state.inMotion !== true){
      this.state.inMotion = false;
      return false;
    }

    // prevent clicks while scrolling

    this.drag.endTime = new Date().getTime();
    var compareTimes = this.drag.endTime - this.drag.startTime;
    var distanceAbs = Math.abs(this.drag.distance);

    //to test
    if(distanceAbs > 3 || compareTimes > 300){
      this.removeClick(this.drag.targetEl);
    }

    var closest = this.closest(this.drag.updatedX);

    this.setSpeed(this.options.dragEndSpeed, false, true);
    this.animStage(this.pos.items[closest]);

    //if pullDrag is off then fire transitionEnd event manually when stick to border
    if(!this.options.pullDrag && this.drag.updatedX === this.pos.items[closest]){
      this.transitionEnd();
    }

    this.drag.distance = 0;

    this.off(document, this.dragType[1], this.e._onDragMove);
    this.off(document, this.dragType[2], this.e._onDragEnd);
  };

  /**
   * removeClick
   * @desc Attach preventClick function to disable link while swipping
   * @since 2.0.0
   * @param [target] - clicked dom element
   */

  Owl.prototype.removeClick = function(target){
    this.drag.targetEl = target;
    this.on(target,'click', this.e._preventClick, false);
  };

  /**
   * preventClick
   * @desc Add preventDefault for any link and then remove removeClick event hanlder
   * @since 2.0.0
   */

  Owl.prototype.preventClick = function(ev){
    if(ev.preventDefault) {
      ev.preventDefault();
    }else {
      ev.returnValue = false;
    }
    if(ev.stopPropagation){
      ev.stopPropagation();
    }
    this.off(this.drag.targetEl,'click',this.e._preventClick,false);
  };

  /**
   * getTransformProperty
   * @desc catch stage position while animate (only css3)
   * @since 2.0.0
   */

  Owl.prototype.getTransformProperty = function(){
    var transform = window.getComputedStyle(this.dom.stage, null).getPropertyValue(this.vendorName + 'transform');
    //var transform = this.dom.$stage.css(this.vendorName + 'transform')
    transform = transform.replace(/matrix(3d)?\(|\)/g, '').split(',');
    var matrix3d = transform.length === 16;

    return matrix3d !== true ? transform[4] : transform[12];
  };

  /**
   * closest
   * @desc Get closest item after touchend/mouseup
   * @since 2.0.0
   * @param [x] - curent position in pixels
   * return position in pixels
   */

  Owl.prototype.closest = function(x){
    var newX = 0,
      pull = 30;

    if(!this.options.freeDrag){
      // Check closest item
      for(var i = 0; i< this.num.items; i++){
        if(x > this.pos.items[i]-pull && x < this.pos.items[i]+pull){
          newX = i;
        }else if(this.op(x,'<',this.pos.items[i]) && this.op(x,'>',this.pos.items[i+1 || this.pos.items[i] - this.width.el]) ){
          newX = this.state.direction === 'left' ? i+1 : i;
        }
      }
    }
    //non loop boundries
    if(!this.options.loop){
      if(this.op(x,'>',this.pos.minValue)){
        newX = x = this.pos.min;
      } else if(this.op(x,'<',this.pos.maxValue)){
        newX = x = this.pos.max;
      }
    }

    if(!this.options.freeDrag){
      // set positions
      this.pos.currentAbs = newX;
      this.pos.current = this.dom.$items.eq(newX).data('owl-item').index;
    } else {
      this.updateItemState();
      return x;
    }

    return newX;
  };

  /**
   * animStage
   * @desc animate stage position (both css3/css2) and perform onChange functions/events
   * @since 2.0.0
   * @param [x] - curent position in pixels
   */

  Owl.prototype.animStage = function(pos){

    // if speed is 0 the set inMotion to false
    if(this.speed.current !== 0 && this.pos.currentAbs !== this.pos.min){
      this.fireCallback('onTransitionStart');
      this.state.inMotion = true;
    }

    var posX = this.pos.stage = pos,
      style = this.dom.stage.style;

    if(this.support3d){
      translate = 'translate3d(' + posX + 'px'+',0px, 0px)';
      style[this.transformVendor] = translate;
    } else if(this.state.isTouch){
      style.left = posX+'px';
    } else {
      this.dom.$stage.animate({left: posX},this.speed.css2speed, this.options.fallbackEasing, function(){
        if(this.state.inMotion){
          this.transitionEnd();
        }
      }.bind(this));
    }

    this.onChange();
  };

  /**
   * updatePosition
   * @desc Update current positions
   * @since 2.0.0
   * @param [pos] - number - new position
   */

  Owl.prototype.updatePosition = function(pos){

    // if no items then stop
    if(this.num.oItems === 0){return false;}
    // to do
    //if(pos > this.num.items){pos = 0;}
    if(pos === undefined){return false;}

    //pos - new current position
    var nextPos = pos;
    this.pos.prev = this.pos.currentAbs;

    if(this.state.revert){
      this.pos.current = this.dom.$items.eq(nextPos).data('owl-item').index;
      this.pos.currentAbs = nextPos;
      return;
    }

    if(!this.options.loop){
      if(this.options.navRewind){
        nextPos = nextPos > this.pos.max ? this.pos.min : (nextPos < 0 ? this.pos.max : nextPos);
      } else {
        nextPos = nextPos > this.pos.max ? this.pos.max : (nextPos <= 0 ? 0 : nextPos);
      }
    } else {
      nextPos = nextPos >= this.num.oItems ? this.num.oItems-1 : nextPos;
    }

    this.pos.current = this.dom.$oItems.eq(nextPos).data('owl-item').index;
    this.pos.currentAbs = this.dom.$oItems.eq(nextPos).data('owl-item').indexAbs;

  };

  /**
   * setSpeed
   * @since 2.0.0
   * @param [speed] - number
   * @param [pos] - number - next position - use this param to calculate smartSpeed
   * @param [drag] - boolean - if drag is true then smart speed is disabled
   * return speed
   */

  Owl.prototype.setSpeed = function(speed,pos,drag) {
    var s = speed,
      nextPos = pos;

    if((s === false && s !== 0 && drag !== true) || s === undefined){

      //Double check this
      // var nextPx = this.pos.items[nextPos];
      // var currPx = this.pos.stage
      // var diff = Math.abs(nextPx-currPx);
      // var s = diff/1
      // if(s>1000){
      // 	s = 1000;
      // }

      var diff = Math.abs(nextPos - this.pos.prev);
      diff = diff === 0 ? 1 : diff;
      if(diff>6){diff = 6;}
      s = diff * this.options.smartSpeed;
    }

    if(s === false && drag === true){
      s = this.options.smartSpeed;
    }

    if(s === 0){s=0;}

    if(this.support3d){
      var style = this.dom.stage.style;
      style.webkitTransitionDuration = style.MsTransitionDuration = style.msTransitionDuration = style.MozTransitionDuration = style.OTransitionDuration = style.transitionDuration = (s / 1000) + 's';
    } else{
      this.speed.css2speed = s;
    }
    this.speed.current = s;
    return s;
  };

  /**
   * jumpTo
   * @since 2.0.0
   * @param [pos] - number - next position - use this param to calculate smartSpeed
   * @param [update] - boolean - if drag is true then smart speed is disabled
   */

  Owl.prototype.jumpTo = function(pos,update){
    if(this.state.lazyContent){
      this.pos.goToLazyContent = pos;
    }
    this.updatePosition(pos);
    this.setSpeed(0);
    this.animStage(this.pos.items[this.pos.currentAbs]);
    if(update !== true){
      this.updateItemState();
    }
  };

  /**
   * goTo
   * @since 2.0.0
   * @param [pos] - number
   * @param [speed] - speed in ms
   * @param [speed] - speed in ms
   */

  Owl.prototype.goTo = function(pos,speed){
    if(this.state.lazyContent && this.state.inMotion){
      return false;
    }

    this.updatePosition(pos);

    if(this.state.animate){speed = 0;}
    this.setSpeed(speed,this.pos.currentAbs);

    if(this.state.animate){this.animate();}
    this.animStage(this.pos.items[this.pos.currentAbs]);

  };

  /**
   * next
   * @since 2.0.0
   */

  Owl.prototype.next = function(optionalSpeed){
    var s = optionalSpeed || this.options.navSpeed;
    if(this.options.loop && !this.state.lazyContent){
      this.goToLoop(this.options.slideBy, s);
    }else{
      this.goTo(this.pos.current + this.options.slideBy, s);
    }
  };

  /**
   * prev
   * @since 2.0.0
   */

  Owl.prototype.prev = function(optionalSpeed){
    var s = optionalSpeed || this.options.navSpeed;
    if(this.options.loop && !this.state.lazyContent){
      this.goToLoop(-this.options.slideBy, s);
    }else{
      this.goTo(this.pos.current-this.options.slideBy, s);
    }
  };

  /**
   * goToLoop
   * @desc Go to given position if loop is enabled - used only internal
   * @since 2.0.0
   * @param [distance] - number -how far to go
   * @param [speed] - number - speed in ms
   */

  Owl.prototype.goToLoop = function(distance,speed){

    var revert = this.pos.currentAbs,
      prevPosition = this.pos.currentAbs,
      newPosition = this.pos.currentAbs + distance,
      direction = prevPosition - newPosition < 0 ? true : false;

    this.state.revert = true;

    if(newPosition < 1 && direction === false){

      this.state.bypass = true;
      revert = this.num.items - (this.options.items-prevPosition) - this.options.items;
      this.jumpTo(revert,true);

    } else if(newPosition >= this.num.items - this.options.items && direction === true ){

      this.state.bypass = true;
      revert = prevPosition - this.num.oItems;
      this.jumpTo(revert,true);

    }
    window.clearTimeout(this.e._goToLoop);
    this.e._goToLoop = window.setTimeout(function(){
      this.state.bypass = false;
      this.goTo(revert + distance, speed);
      this.state.revert = false;

    }.bind(this), 30);
  };

  /**
   * initPosition
   * @since 2.0.0
   */

  Owl.prototype.initPosition = function(init){

    if( !this.dom.$oItems || !init || this.state.lazyContent ){return false;}
    var pos = this.options.startPosition;

    if(this.options.startPosition === 'URLHash'){
      pos = this.options.startPosition = this.hashPosition();
    } else if(typeof this.options.startPosition !== Number && !this.options.center){
      this.options.startPosition = 0;
    }
    this.dom.oStage.scrollLeft = 0;
    this.jumpTo(pos,true);
  };

  /**
   * goToHash
   * @since 2.0.0
   */

  Owl.prototype.goToHash = function(){
    var pos = this.hashPosition();
    if(pos === false){
      pos = 0;
    }
    this.dom.oStage.scrollLeft = 0;
    this.goTo(pos,this.options.navSpeed);
  };

  /**
   * hashPosition
   * @desc Find hash in URL then look into items to find contained ID
   * @since 2.0.0
   * return hashPos - number of item
   */

  Owl.prototype.hashPosition = function(){
    var hash = window.location.hash.substring(1),
      hashPos;
    if(hash === ""){return false;}

    for(var i=0;i<this.num.oItems; i++){
      if(hash === this.dom.$oItems.eq(i).data('owl-item').hash){
        hashPos = i;
      }
    }
    return hashPos;
  };

  /**
   * Autoplay
   * @since 2.0.0
   */

  Owl.prototype.autoplay = function(){
    if(this.options.autoplay && !this.state.videoPlay){
      window.clearInterval(this.e._autoplay);
      this.e._autoplay = window.setInterval(this.e._play, this.options.autoplayTimeout);
    } else {
      window.clearInterval(this.e._autoplay);
      this.state.autoplay=false;
    }
  };

  /**
   * play
   * @param [timeout] - Integrer
   * @param [speed] - Integrer
   * @since 2.0.0
   */

  Owl.prototype.play = function(timeout, speed){

    // if tab is inactive - doesnt work in <IE10
    if(document.hidden === true){return false;}

    // overwrite default options (custom options are always priority)
    if(!this.options.autoplay){
      this._options.autoplay = this.options.autoplay = true;
      this._options.autoplayTimeout = this.options.autoplayTimeout = timeout || this.options.autoplayTimeout || 4000;
      this._options.autoplaySpeed = speed || this.options.autoplaySpeed;
    }

    if(this.options.autoplay === false || this.state.isTouch || this.state.isScrolling || this.state.isSwiping || this.state.inMotion){
      window.clearInterval(this.e._autoplay);
      return false;
    }

    if(!this.options.loop && this.pos.current >= this.pos.max){
      window.clearInterval(this.e._autoplay);
      this.goTo(0);
    } else {
      this.next(this.options.autoplaySpeed);
    }
    this.state.autoplay=true;
  };

  /**
   * stop
   * @since 2.0.0
   */

  Owl.prototype.stop = function(){
    this._options.autoplay = this.options.autoplay = false;
    this.state.autoplay = false;
    window.clearInterval(this.e._autoplay);
  };

  Owl.prototype.pause = function(){
    window.clearInterval(this.e._autoplay);
  };

  /**
   * transitionEnd
   * @desc event used by css3 animation end and $.animate callback like transitionEnd,responsive etc.
   * @since 2.0.0
   */

  Owl.prototype.transitionEnd = function(event){

    // if css2 animation then event object is undefined
    if(event !== undefined){
      event.stopPropagation();

      // Catch only owl-stage transitionEnd event
      var eventTarget = event.target || event.srcElement || event.originalTarget;
      if(eventTarget !== this.dom.stage){
        return false;
      }
    }

    this.state.inMotion = false;
    this.updateItemState();
    this.autoplay();
    this.fireCallback('onTransitionEnd');
  };

  /**
   * isElWidthChanged
   * @desc Check if element width has changed
   * @since 2.0.0
   */

  Owl.prototype.isElWidthChanged = function(){
    var newElWidth = 	this.dom.$el.width() - this.options.stagePadding,//to check
      prevElWidth = 	this.width.el + this.options.margin;
    return newElWidth !== prevElWidth;
  };

  /**
   * windowWidth
   * @desc Get Window/responsiveBaseElement width
   * @since 2.0.0
   */

  Owl.prototype.windowWidth = function() {
    if(this.options.responsiveBaseElement !== window){
      this.width.window =  $(this.options.responsiveBaseElement).width();
    } else if (window.innerWidth){
      this.width.window = window.innerWidth;
    } else if (document.documentElement && document.documentElement.clientWidth){
      this.width.window = document.documentElement.clientWidth;
    }
    return this.width.window;
  };

  /**
   * Controls
   * @desc Calls controls container, navigation and dots creator
   * @since 2.0.0
   */

  Owl.prototype.controls = function(){
    var cc = document.createElement('div');
    cc.className = this.options.controlsClass;
    this.dom.$el.append(cc);
    this.dom.$cc = $(cc);
  };

  /**
   * updateControls
   * @since 2.0.0
   */

  Owl.prototype.updateControls = function(){

    if(this.dom.$cc === null && (this.options.nav || this.options.dots)){
      this.controls();
    }

    if(this.dom.$nav === null && this.options.nav){
      this.createNavigation(this.dom.$cc[0]);
    }

    if(this.dom.$page === null && this.options.dots){
      this.createDots(this.dom.$cc[0]);
    }

    if(this.dom.$nav !== null){
      if(this.options.nav){
        this.dom.$nav.show();
        this.updateNavigation();
      } else {
        this.dom.$nav.hide();
      }
    }

    if(this.dom.$page !== null){
      if(this.options.dots){
        this.dom.$page.show();
        this.updateDots();
      } else {
        this.dom.$page.hide();
      }
    }
  };

  /**
   * createNavigation
   * @since 2.0.0
   * @param [cc] - dom element - Controls Container
   */

  Owl.prototype.createNavigation = function(cc){

    // Create nav container
    var nav = document.createElement('div');
    nav.className = this.options.navContainerClass;
    cc.appendChild(nav);

    // Create left and right buttons
    var navPrev = document.createElement('div'),
      navNext = document.createElement('div');

    navPrev.className = this.options.navClass[0];
    navNext.className = this.options.navClass[1];

    nav.appendChild(navPrev);
    nav.appendChild(navNext);

    this.dom.$nav = $(nav);
    this.dom.$navPrev = $(navPrev).html(this.options.navText[0]);
    this.dom.$navNext = $(navNext).html(this.options.navText[1]);

    // add events to do
    //this.on(navPrev, this.dragType[2], this.e._navPrev, false);
    //this.on(navNext, this.dragType[2], this.e._navNext, false);

    //FF fix?
    this.dom.$nav.on(this.dragType[2], '.'+this.options.navClass[0], this.e._navPrev);
    this.dom.$nav.on(this.dragType[2], '.'+this.options.navClass[1], this.e._navNext);
  };

  /**
   * createNavigation
   * @since 2.0.0
   * @param [cc] - dom element - Controls Container
   */

  Owl.prototype.createDots = function(cc){

    // Create dots container
    var page = document.createElement('div');
    page.className = this.options.dotsClass;
    cc.appendChild(page);

    // save reference
    this.dom.$page = $(page);

    // add events
    //this.on(page, this.dragType[2], this.e._goToPage, false);

    // FF fix? To test!
    var that = this;
    this.dom.$page.on(this.dragType[2], '.'+this.options.dotClass, goToPage);

    function goToPage(e){
      e.preventDefault();
      var page = $(this).data('page');
      that.goTo(page,that.options.dotsSpeed);
    }
    // build dots
    this.rebuildDots();
  };

  /**
   * goToPage
   * @desc Event used by dots
   * @since 2.0.0
   */

  // Owl.prototype.goToPage = function(e){
  // 	console.log(e.taget);
  // 	var page = $(e.currentTarget).data('page')
  // 	this.goTo(page,this.options.dotsSpeed);
  // 	return false;
  // };

  /**
   * rebuildDots
   * @since 2.0.0
   */

  Owl.prototype.rebuildDots = function(){
    if(this.dom.$page === null){return false;}
    var each, dot, span, counter = 0, last = 0, i, page=0, roundPages = 0;

    each = this.options.dotsEach || this.options.items;

    // display full dots if center
    if(this.options.center || this.options.dotData){
      each = 1;
    }

    // clear dots
    this.dom.$page.html('');

    for(i = 0; i < this.num.nav.length; i++){

      if(counter >= each || counter === 0){

        dot = document.createElement('div');
        dot.className = this.options.dotClass;
        span = document.createElement('span');
        dot.appendChild(span);
        var $dot = $(dot);

        if(this.options.dotData){
          $dot.html(this.dom.$oItems.eq(i).data('owl-item').dot);
        }

        $dot.data('page',page);
        $dot.data('goToPage',roundPages);

        this.dom.$page.append(dot);

        counter = 0;
        roundPages++;
      }

      this.dom.$oItems.eq(i).data('owl-item').page = roundPages-1;

      //add merged items
      counter += this.num.nav[i];
      page++;
    }
    // find rest of dots
    if(!this.options.loop && !this.options.center){
      for(var j = this.num.nav.length-1; j >= 0; j--){
        last += this.num.nav[j];
        this.dom.$oItems.eq(j).data('owl-item').page = roundPages-1;
        if(last >= each){
          break;
        }
      }
    }

    this.num.allPages = roundPages-1;
  };

  /**
   * updateDots
   * @since 2.0.0
   */

  Owl.prototype.updateDots = function(){
    var dots = this.dom.$page.children();
    var itemIndex = this.dom.$oItems.eq(this.pos.current).data('owl-item').page;

    for(var i = 0; i < dots.length; i++){
      var dotPage = dots.eq(i).data('goToPage');

      if(dotPage===itemIndex){
        this.pos.currentPage = i;
        dots.eq(i).addClass('active');
      }else{
        dots.eq(i).removeClass('active');
      }
    }
  };

  /**
   * updateNavigation
   * @since 2.0.0
   */

  Owl.prototype.updateNavigation = function(){

    var isNav = this.options.nav;

    this.dom.$navNext.toggleClass('disabled',!isNav);
    this.dom.$navPrev.toggleClass('disabled',!isNav);

    if(!this.options.loop && isNav && !this.options.navRewind){

      if(this.pos.current <= 0){
        this.dom.$navPrev.addClass('disabled');
      }
      if(this.pos.current >= this.pos.max){
        this.dom.$navNext.addClass('disabled');
      }
    }
  };

  Owl.prototype.insertContent = function(content){
    this.dom.$stage.empty();
    this.fetchContent(content);
    this.refresh();
  };

  /**
   * addItem - Add an item
   * @since 2.0.0
   * @param [content] - dom element / string '<div>content</div>'
   * @param [pos] - number - position
   */

  Owl.prototype.addItem = function(content,pos){
    pos = pos || 0;

    if(this.state.lazyContent){
      this.dom.$content = this.dom.$content.add($(content));
      this.updateItemState(true);
    } else {
      // wrap content
      var item = this.fillItem(content);
      // if carousel is empty then append item
      if(this.dom.$oItems.length === 0){
        this.dom.$stage.append(item);
      } else {
        // append item
        var it = this.dom.$oItems.eq(pos);
        if(pos !== -1){it.before(item);} else {it.after(item);}
      }
      // update and calculate carousel
      this.refresh();
    }

  };

  /**
   * removeItem - Remove an Item
   * @since 2.0.0
   * @param [pos] - number - position
   */

  Owl.prototype.removeItem = function(pos){
    if(this.state.lazyContent){
      this.dom.$content.splice(pos,1);
      this.updateItemState(true);
    } else {
      this.dom.$oItems.eq(pos).remove();
      this.refresh();
    }
  };

  /**
   * addCustomEvents
   * @desc Add custom events by jQuery .on method
   * @since 2.0.0
   */

  Owl.prototype.addCustomEvents = function(){

    this.e.next = function(e,s){this.next(s);			}.bind(this);
    this.e.prev = function(e,s){this.prev(s);			}.bind(this);
    this.e.goTo = function(e,p,s){this.goTo(p,s);		}.bind(this);
    this.e.jumpTo = function(e,p){this.jumpTo(p);		}.bind(this);
    this.e.addItem = function(e,c,p){this.addItem(c,p);	}.bind(this);
    this.e.removeItem = function(e,p){this.removeItem(p);}.bind(this);
    this.e.refresh = function(e){this.refresh();		}.bind(this);
    this.e.destroy = function(e){this.destroy();		}.bind(this);
    this.e.autoHeight = function(e){this.autoHeight(true);}.bind(this);
    this.e.stop = function(){this.stop();				}.bind(this);
    this.e.play = function(e,t,s){this.play(t,s);		}.bind(this);
    this.e.insertContent = function(e,d){this.insertContent(d);	}.bind(this);

    this.dom.$el.on('next.owl',this.e.next);
    this.dom.$el.on('prev.owl',this.e.prev);
    this.dom.$el.on('goTo.owl',this.e.goTo);
    this.dom.$el.on('jumpTo.owl',this.e.jumpTo);
    this.dom.$el.on('addItem.owl',this.e.addItem);
    this.dom.$el.on('removeItem.owl',this.e.removeItem);
    this.dom.$el.on('destroy.owl',this.e.destroy);
    this.dom.$el.on('refresh.owl',this.e.refresh);
    this.dom.$el.on('autoHeight.owl',this.e.autoHeight);
    this.dom.$el.on('play.owl',this.e.play);
    this.dom.$el.on('stop.owl',this.e.stop);
    this.dom.$el.on('stopVideo.owl',this.e.stop);
    this.dom.$el.on('insertContent.owl',this.e.insertContent);

  };

  /**
   * on
   * @desc On method for adding internal events
   * @since 2.0.0
   */

  Owl.prototype.on = function (element, event, listener, capture) {

    if (element.addEventListener) {
      element.addEventListener(event, listener, capture);
    }
    else if (element.attachEvent) {
      element.attachEvent('on' + event, listener);
    }
  };

  /**
   * off
   * @desc Off method for removing internal events
   * @since 2.0.0
   */

  Owl.prototype.off = function (element, event, listener, capture) {
    if (element.removeEventListener) {
      element.removeEventListener(event, listener, capture);
    }
    else if (element.detachEvent) {
      element.detachEvent('on' + event, listener);
    }
  };

  /**
   * fireCallback
   * @since 2.0.0
   * @param event - string - event name
   * @param data - object - additional options - to do
   */

  Owl.prototype.fireCallback = function(event, data){
    if(!this.options.callbacks){return;}

    if(this.dom.el.dispatchEvent){

      // dispatch event
      var evt = document.createEvent('CustomEvent');

      //evt.initEvent(event, false, true );
      evt.initCustomEvent(event, true, true, data);
      return this.dom.el.dispatchEvent(evt);

    } else if (!this.dom.el.dispatchEvent){

      //	There is no clean solution for custom events name in <=IE8
      //	But if you know better way, please let me know :)
      return this.dom.$el.trigger(event);
    }
  };

  /**
   * watchVisibility
   * @desc check if el is visible - handy if Owl is inside hidden content (tabs etc.)
   * @since 2.0.0
   */

  Owl.prototype.watchVisibility = function(){

    // test on zepto
    if(!isElVisible(this.dom.el)) {
      this.dom.$el.addClass('owl-hidden');
      window.clearInterval(this.e._checkVisibile);
      this.e._checkVisibile = window.setInterval(checkVisible.bind(this),500);
    }

    function isElVisible(el) {
      return el.offsetWidth > 0 && el.offsetHeight > 0;
    }

    function checkVisible(){
      if (isElVisible(this.dom.el)) {
        this.dom.$el.removeClass('owl-hidden');
        this.refresh();
        window.clearInterval(this.e._checkVisibile);
      }
    }
  };

  /**
   * onChange
   * @since 2.0.0
   */

  Owl.prototype.onChange = function(){

    if(!this.state.isTouch && !this.state.bypass && !this.state.responsive ){

      if (this.options.nav || this.options.dots) {
        this.updateControls();
      }
      this.autoHeight();

      this.fireCallback('onChangeState');
    }

    if(!this.state.isTouch && !this.state.bypass){
      // set Status to do
      this.storeInfo();

      // stopVideo
      if(this.state.videoPlay){
        this.stopVideo();
      }
    }
  };

  /**
   * storeInfo
   * store basic information about current states
   * @since 2.0.0
   */

  Owl.prototype.storeInfo = function(){
    var currentPosition = this.state.lazyContent ? this.pos.lcCurrentAbs || 0 : this.pos.current;
    var allItems = this.state.lazyContent ? this.dom.$content.length-1 : this.num.oItems;

    this.info = {
      items: 			this.options.items,
      allItems:		allItems,
      currentPosition:currentPosition,
      currentPage:	this.pos.currentPage,
      allPages:		this.num.allPages,
      autoplay:		this.state.autoplay,
      windowWidth:	this.width.window,
      elWidth:		this.width.el,
      breakpoint:		this.num.breakpoint
    };

    if (typeof this.options.info === 'function') {
      this.options.info.apply(this,[this.info,this.dom.el]);
    }
  };

  /**
   * autoHeight
   * @since 2.0.0
   */

  Owl.prototype.autoHeight = function(callback){
    if(this.options.autoHeight !== true && callback !== true){
      return false;
    }
    if(!this.dom.$oStage.hasClass(this.options.autoHeightClass)){
      this.dom.$oStage.addClass(this.options.autoHeightClass);
    }

    var loaded = this.dom.$items.eq(this.pos.currentAbs);
    var stage = this.dom.$oStage;
    var iterations = 0;

    var isLoaded = window.setInterval(function() {
      iterations += 1;
      if(loaded.data('owl-item').loaded){
        stage.height(loaded.height() + 'px');
        clearInterval(isLoaded);
      } else if(iterations === 500){
        clearInterval(isLoaded);
      }
    }, 100);
  };

  /**
   * preloadAutoWidthImages
   * @desc still to test
   * @since 2.0.0
   */

  Owl.prototype.preloadAutoWidthImages = function(imgs){
    var loaded = 0;
    var that = this;
    imgs.each(function(i,el){
      var $el = $(el);
      var img = new Image();

      img.onload = function(){
        loaded++;
        $el.attr('src',img.src);
        $el.css('opacity',1);
        if(loaded >= imgs.length){
          that.state.imagesLoaded = true;
          that.init();
        }
      }

      img.src = $el.attr('src') ||  $el.attr('data-src') || $el.attr('data-src-retina');;
    })
  };

  /**
   * lazyLoad
   * @desc lazyLoad images
   * @since 2.0.0
   */

  Owl.prototype.lazyLoad = function(){
    var attr = isRetina() ? 'data-src-retina' : 'data-src';
    var src, img,i;

    for(i = 0; i < this.num.items; i++){
      var $item = this.dom.$items.eq(i);

      if( $item.data('owl-item').current === true && $item.data('owl-item').loaded === false){
        img = $item.find('.owl-lazy');
        src = img.attr(attr);
        src = src || img.attr('data-src');
        if(src){
          img.css('opacity','0');
          this.preload(img,$item);
        }
      }
    }
  };

  /**
   * preload
   * @since 2.0.0
   */

  Owl.prototype.preload = function(images,$item){
    var that = this; // fix this later

    images.each(function(i,el){
      var $el = $(el);
      var img = new Image();

      img.onload = function(){

        $item.data('owl-item').loaded = true;
        if($el.is('img')){
          $el.attr('src',img.src);
        }else{
          $el.css('background-image','url(' + img.src + ')');
        }

        $el.css('opacity',1);
        that.fireCallback('onLazyLoaded');
      };
      img.src = $el.attr('data-src') || $el.attr('data-src-retina');
    });
  };

  /**
   * animate
   * @since 2.0.0
   */

  Owl.prototype.animate = function(){

    var prevItem = this.dom.$items.eq(this.pos.prev),
      prevPos = Math.abs(prevItem.data('owl-item').width) * this.pos.prev,
      currentItem = this.dom.$items.eq(this.pos.currentAbs),
      currentPos = Math.abs(currentItem.data('owl-item').width) * this.pos.currentAbs;

    if(this.pos.currentAbs === this.pos.prev){
      return false;
    }

    var pos = currentPos - prevPos;
    var tIn = this.options.animateIn;
    var tOut = this.options.animateOut;
    var that = this;

    removeStyles = function(){
      $(this).css({
        "left" : ""
      })
        .removeClass('animated owl-animated-out owl-animated-in')
        .removeClass(tIn)
        .removeClass(tOut);

      that.transitionEnd();
    };

    if(tOut){
      prevItem
        .css({
          "left" : pos + "px"
        })
        .addClass('animated owl-animated-out '+tOut)
        .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', removeStyles);
    }

    if(tIn){
      currentItem
        .addClass('animated owl-animated-in '+tIn)
        .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', removeStyles);
    }
  };

  /**
   * destroy
   * @desc Remove Owl structure and events :(
   * @since 2.0.0
   */

  Owl.prototype.destroy = function(){

    window.clearInterval(this.e._autoplay);

    if(this.dom.$el.hasClass(this.options.themeClass)){
      this.dom.$el.removeClass(this.options.themeClass);
    }

    if(this.options.responsive !== false){
      this.off(window, 'resize', this.e._resizer);
    }

    if(this.transitionEndVendor){
      this.off(this.dom.stage, this.transitionEndVendor, this.e._transitionEnd);
    }

    if(this.options.mouseDrag || this.options.touchDrag){
      this.off(this.dom.stage, this.dragType[0], this.e._onDragStart);
      if(this.options.mouseDrag){
        this.off(document, this.dragType[3], this.e._onDragStart);
      }
      if(this.options.mouseDrag){
        this.dom.$stage.off('dragstart', function() {return false;});
        this.dom.stage.onselectstart = function(){};
      }
    }

    if(this.options.URLhashListener){
      this.off(window, 'hashchange', this.e._goToHash);
    }

    this.dom.$el.off('next.owl',this.e.next);
    this.dom.$el.off('prev.owl',this.e.prev);
    this.dom.$el.off('goTo.owl',this.e.goTo);
    this.dom.$el.off('jumpTo.owl',this.e.jumpTo);
    this.dom.$el.off('addItem.owl',this.e.addItem);
    this.dom.$el.off('removeItem.owl',this.e.removeItem);
    this.dom.$el.off('refresh.owl',this.e.refresh);
    this.dom.$el.off('autoHeight.owl',this.e.autoHeight);
    this.dom.$el.off('play.owl',this.e.play);
    this.dom.$el.off('stop.owl',this.e.stop);
    this.dom.$el.off('stopVideo.owl',this.e.stop);
    this.dom.$stage.off('click',this.e._playVideo);

    if(this.dom.$cc !== null){
      this.dom.$cc.remove();
    }
    if(this.dom.$cItems !== null){
      this.dom.$cItems.remove();
    }
    this.e = null;
    this.dom.$el.data('owlCarousel',null);
    delete this.dom.el.owlCarousel;

    this.dom.$stage.unwrap();
    this.dom.$items.unwrap();
    this.dom.$items.contents().unwrap();
    this.dom = null;
  };

  /**
   * Opertators
   * @desc Used to calculate RTL
   * @param [a] - Number - left side
   * @param [o] - String - operator
   * @param [b] - Number - right side
   * @since 2.0.0
   */

  Owl.prototype.op = function(a,o,b){
    var rtl = this.options.rtl;
    switch(o) {
      case '<':
        return rtl ? a > b : a < b;
      case '>':
        return rtl ? a < b : a > b;
      case '>=':
        return rtl ? a <= b : a >= b;
      case '<=':
        return rtl ? a >= b : a <= b;
      default:
        break;
    }
  };

  /**
   * Opertators
   * @desc Used to calculate RTL
   * @since 2.0.0
   */

  Owl.prototype.browserSupport = function(){
    this.support3d = isPerspective();

    if(this.support3d){
      this.transformVendor = isTransform();

      // take transitionend event name by detecting transition
      var endVendors = ['transitionend','webkitTransitionEnd','transitionend','oTransitionEnd'];
      this.transitionEndVendor = endVendors[isTransition()];

      // take vendor name from transform name
      this.vendorName = this.transformVendor.replace(/Transform/i,'');
      this.vendorName = this.vendorName !== '' ? '-'+this.vendorName.toLowerCase()+'-' : '';
    }

    this.state.orientation = window.orientation;
  };

  // Pivate methods

  // CSS detection;
  function isStyleSupported(array){
    var p,s,fake = document.createElement('div'),list = array;
    for(p in list){
      s = list[p];
      if(typeof fake.style[s] !== 'undefined'){
        fake = null;
        return [s,p];
      }
    }
    return [false];
  }

  function isTransition(){
    return isStyleSupported(['transition','WebkitTransition','MozTransition','OTransition'])[1];
  }

  function isTransform() {
    return isStyleSupported(['transform','WebkitTransform','MozTransform','OTransform','msTransform'])[0];
  }

  function isPerspective(){
    return isStyleSupported(['perspective','webkitPerspective','MozPerspective','OPerspective','MsPerspective'])[0];
  }

  function isTouchSupport(){
    return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints);
  }

  function isTouchSupportIE(){
    return window.navigator.msPointerEnabled;
  }

  function isRetina(){
    return window.devicePixelRatio > 1;
  }

  $.fn.owlCarousel = function ( options ) {
    return this.each(function () {
      if (!$(this).data('owlCarousel')) {
        $(this).data( 'owlCarousel',
          new Owl( this, options ));
      }
    });

  };

})( window.Zepto || window.jQuery, window,  document );

//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
//The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs = Array.prototype.slice.call(arguments, 1),
      fToBind = this,
      fNOP = function () {},
      fBound = function () {
        return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
      };
    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;
  };
}