HEX
Server: Apache/2
System: Linux gains.linuxbigapps.com 4.18.0-553.74.1.lve.el8.x86_64 #1 SMP Tue Sep 9 14:25:24 UTC 2025 x86_64
User: mountains (1551)
PHP: 8.0.30
Disabled: allow_url_include, show_source, symlink, system, passthru, exec, popen, pclose, proc_open, proc_terminate,proc_get_status, proc_close, proc_nice, allow_url_fopen, shell-exec, shell_exec, fpassthru, base64_encodem, escapeshellcmd, escapeshellarg, crack_check,crack_closedict, crack_getlastmessage, crack_opendict, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, dl, escap, phpinfo
Upload Files
File: /home/mountains/public_html/wp-content/plugins/kadence-blocks/dist/assets/js/src/tiny-slider.js
var tns = (function (){
	var win = window;
	
	var raf = win.requestAnimationFrame
	  || win.webkitRequestAnimationFrame
	  || win.mozRequestAnimationFrame
	  || win.msRequestAnimationFrame
	  || function(cb) { return setTimeout(cb, 16); };
	
	var win$1 = window;
	
	var caf = win$1.cancelAnimationFrame
	  || win$1.mozCancelAnimationFrame
	  || function(id){ clearTimeout(id); };
	
	function extend() {
	  var obj, name, copy,
		  target = arguments[0] || {},
		  i = 1,
		  length = arguments.length;
	
	  for (; i < length; i++) {
		if ((obj = arguments[i]) !== null) {
		  for (name in obj) {
			copy = obj[name];
	
			if (target === copy) {
			  continue;
			} else if (copy !== undefined) {
			  target[name] = copy;
			}
		  }
		}
	  }
	  return target;
	}
	
	function checkStorageValue (value) {
	  return ['true', 'false'].indexOf(value) >= 0 ? JSON.parse(value) : value;
	}
	
	function setLocalStorage(storage, key, value, access) {
	  if (access) {
		try { storage.setItem(key, value); } catch (e) {}
	  }
	  return value;
	}
	
	function getSlideId() {
	  var id = window.tnsId;
	  window.tnsId = !id ? 1 : id + 1;
	  
	  return 'tns' + window.tnsId;
	}
	
	function getBody () {
	  var doc = document,
		  body = doc.body;
	
	  if (!body) {
		body = doc.createElement('body');
		body.fake = true;
	  }
	
	  return body;
	}
	
	var docElement = document.documentElement;
	
	function setFakeBody (body) {
	  var docOverflow = '';
	  if (body.fake) {
		docOverflow = docElement.style.overflow;
		//avoid crashing IE8, if background image is used
		body.style.background = '';
		//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
		body.style.overflow = docElement.style.overflow = 'hidden';
		docElement.appendChild(body);
	  }
	
	  return docOverflow;
	}
	
	function resetFakeBody (body, docOverflow) {
	  if (body.fake) {
		body.remove();
		docElement.style.overflow = docOverflow;
		// Trigger layout so kinetic scrolling isn't disabled in iOS6+
		// eslint-disable-next-line
		docElement.offsetHeight;
	  }
	}
	
	// get css-calc 
	
	function calc() {
	  var doc = document, 
		  body = getBody(),
		  docOverflow = setFakeBody(body),
		  div = doc.createElement('div'), 
		  result = false;
	
	  body.appendChild(div);
	  try {
		var str = '(10px * 10)',
			vals = ['calc' + str, '-moz-calc' + str, '-webkit-calc' + str],
			val;
		for (var i = 0; i < 3; i++) {
		  val = vals[i];
		  div.style.width = val;
		  if (div.offsetWidth === 100) { 
			result = val.replace(str, ''); 
			break;
		  }
		}
	  } catch (e) {}
	  
	  body.fake ? resetFakeBody(body, docOverflow) : div.remove();
	
	  return result;
	}
	
	// get subpixel support value
	
	function percentageLayout() {
	  // check subpixel layout supporting
	  var doc = document,
		  body = getBody(),
		  docOverflow = setFakeBody(body),
		  wrapper = doc.createElement('div'),
		  outer = doc.createElement('div'),
		  str = '',
		  count = 70,
		  perPage = 3,
		  supported = false;
	
	  wrapper.className = "tns-t-subp2";
	  outer.className = "tns-t-ct";
	
	  for (var i = 0; i < count; i++) {
		str += '<div></div>';
	  }
	
	  outer.innerHTML = str;
	  wrapper.appendChild(outer);
	  body.appendChild(wrapper);
	
	  supported = Math.abs(wrapper.getBoundingClientRect().left - outer.children[count - perPage].getBoundingClientRect().left) < 2;
	
	  body.fake ? resetFakeBody(body, docOverflow) : wrapper.remove();
	
	  return supported;
	}
	
	function mediaquerySupport () {
	  var doc = document,
		  body = getBody(),
		  docOverflow = setFakeBody(body),
		  div = doc.createElement('div'),
		  style = doc.createElement('style'),
		  rule = '@media all and (min-width:1px){.tns-mq-test{position:absolute}}',
		  position;
	
	  style.type = 'text/css';
	  div.className = 'tns-mq-test';
	
	  body.appendChild(style);
	  body.appendChild(div);
	
	  if (style.styleSheet) {
		style.styleSheet.cssText = rule;
	  } else {
		style.appendChild(doc.createTextNode(rule));
	  }
	
	  position = window.getComputedStyle ? window.getComputedStyle(div).position : div.currentStyle['position'];
	
	  body.fake ? resetFakeBody(body, docOverflow) : div.remove();
	
	  return position === "absolute";
	}
	
	// create and append style sheet
	function createStyleSheet (media) {
	  // Create the <style> tag
	  var style = document.createElement("style");
	  // style.setAttribute("type", "text/css");
	
	  // Add a media (and/or media query) here if you'd like!
	  // style.setAttribute("media", "screen")
	  // style.setAttribute("media", "only screen and (max-width : 1024px)")
	  if (media) { style.setAttribute("media", media); }
	
	  // WebKit hack :(
	  // style.appendChild(document.createTextNode(""));
	
	  // Add the <style> element to the page
	  document.querySelector('head').appendChild(style);
	
	  return style.sheet ? style.sheet : style.styleSheet;
	}
	
	// cross browsers addRule method
	function addCSSRule(sheet, selector, rules, index) {
	  // return raf(function() {
		'insertRule' in sheet ?
		  sheet.insertRule(selector + '{' + rules + '}', index) :
		  sheet.addRule(selector, rules, index);
	  // });
	}
	
	// cross browsers addRule method
	function removeCSSRule(sheet, index) {
	  // return raf(function() {
		'deleteRule' in sheet ?
		  sheet.deleteRule(index) :
		  sheet.removeRule(index);
	  // });
	}
	
	function getCssRulesLength(sheet) {
	  var rule = ('insertRule' in sheet) ? sheet.cssRules : sheet.rules;
	  return rule.length;
	}
	
	function toDegree (y, x) {
	  return Math.atan2(y, x) * (180 / Math.PI);
	}
	
	function getTouchDirection(angle, range) {
	  var direction = false,
		  gap = Math.abs(90 - Math.abs(angle));
		  
	  if (gap >= 90 - range) {
		direction = 'horizontal';
	  } else if (gap <= range) {
		direction = 'vertical';
	  }
	
	  return direction;
	}
	
	// https://toddmotto.com/ditch-the-array-foreach-call-nodelist-hack/
	function forEach (arr, callback, scope) {
	  for (var i = 0, l = arr.length; i < l; i++) {
		callback.call(scope, arr[i], i);
	  }
	}
	
	var classListSupport = 'classList' in document.createElement('_');
	
	var hasClass = classListSupport ?
		function (el, str) { return el.classList.contains(str); } :
		function (el, str) { return el.className.indexOf(str) >= 0; };
	
	var addClass = classListSupport ?
		function (el, str) {
		  if (!hasClass(el,  str)) { el.classList.add(str); }
		} :
		function (el, str) {
		  if (!hasClass(el,  str)) { el.className += ' ' + str; }
		};
	
	var removeClass = classListSupport ?
		function (el, str) {
		  if (hasClass(el,  str)) { el.classList.remove(str); }
		} :
		function (el, str) {
		  if (hasClass(el, str)) { el.className = el.className.replace(str, ''); }
		};
	
	function hasAttr(el, attr) {
	  return el.hasAttribute(attr);
	}
	
	function getAttr(el, attr) {
	  return el.getAttribute(attr);
	}
	
	function isNodeList(el) {
	  // Only NodeList has the "item()" function
	  return typeof el.item !== "undefined"; 
	}
	
	function setAttrs(els, attrs) {
	  els = (isNodeList(els) || els instanceof Array) ? els : [els];
	  if (Object.prototype.toString.call(attrs) !== '[object Object]') { return; }
	
	  for (var i = els.length; i--;) {
		for(var key in attrs) {
		  els[i].setAttribute(key, attrs[key]);
		}
	  }
	}
	function setInnerAttrs(els, attrs) {
		els = (isNodeList(els) || els instanceof Array) ? els : [els];
		if (Object.prototype.toString.call(attrs) !== '[object Object]') { return; }
		for (var i = els.length; i--;) {
			var childs = els[i].getElementsByTagName('a');
			for (var n = childs.length; n--;) {
				for(var key in attrs) {
					childs[n].setAttribute(key, attrs[key]);
				}
			}
		}
	}
	
	function removeAttrs(els, attrs) {
	  els = (isNodeList(els) || els instanceof Array) ? els : [els];
	  attrs = (attrs instanceof Array) ? attrs : [attrs];
	
	  var attrLength = attrs.length;
	  for (var i = els.length; i--;) {
		for (var j = attrLength; j--;) {
		  els[i].removeAttribute(attrs[j]);
		}
	  }
	}
	function removeInnerAttrs(els, attrs) {
		els = (isNodeList(els) || els instanceof Array) ? els : [els];
		attrs = (attrs instanceof Array) ? attrs : [attrs];
	  
		var attrLength = attrs.length;
		for (var i = els.length; i--;) {
			var childs = els[i].getElementsByTagName('a');
			for (var n = childs.length; n--;) {
				for (var j = attrLength; j--;) {
					childs[n].removeAttribute(attrs[j]);
				}
			}
		}
	  }
	
	function arrayFromNodeList (nl) {
	  var arr = [];
	  for (var i = 0, l = nl.length; i < l; i++) {
		arr.push(nl[i]);
	  }
	  return arr;
	}
	
	function hideElement(el, forceHide) {
	  if (el && el.style.display !== 'none') { el.style.display = 'none'; }
	}
	
	function showElement(el, forceHide) {
	  if (el.style.display === 'none') { el.style.display = ''; }
	}
	
	function isVisible(el) {
	  return window.getComputedStyle(el).display !== 'none';
	}
	
	function whichProperty(props){
	  if (typeof props === 'string') {
		var arr = [props],
			Props = props.charAt(0).toUpperCase() + props.substr(1),
			prefixes = ['Webkit', 'Moz', 'ms', 'O'];
			
		prefixes.forEach(function(prefix) {
		  if (prefix !== 'ms' || props === 'transform') {
			arr.push(prefix + Props);
		  }
		});
	
		props = arr;
	  }
	
	  var el = document.createElement('fakeelement'),
		  len = props.length;
	  for(var i = 0; i < props.length; i++){
		var prop = props[i];
		if( el.style[prop] !== undefined ){ return prop; }
	  }
	
	  return false; // explicit for ie9-
	}
	
	function has3DTransforms(tf){
	  if (!tf) { return false; }
	  if (!window.getComputedStyle) { return false; }
	  
	  var doc = document,
		  body = getBody(),
		  docOverflow = setFakeBody(body),
		  el = doc.createElement('p'),
		  has3d,
		  cssTF = tf.length > 9 ? '-' + tf.slice(0, -9).toLowerCase() + '-' : '';
	
	  cssTF += 'transform';
	
	  // Add it to the body to get the computed style
	  body.insertBefore(el, null);
	
	  el.style[tf] = 'translate3d(1px,1px,1px)';
	  has3d = window.getComputedStyle(el).getPropertyValue(cssTF);
	
	  body.fake ? resetFakeBody(body, docOverflow) : el.remove();
	
	  return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
	}
	
	// get transitionend, animationend based on transitionDuration
	// @propin: string
	// @propOut: string, first-letter uppercase
	// Usage: getEndProperty('WebkitTransitionDuration', 'Transition') => webkitTransitionEnd
	function getEndProperty(propIn, propOut) {
	  var endProp = false;
	  if (/^Webkit/.test(propIn)) {
		endProp = 'webkit' + propOut + 'End';
	  } else if (/^O/.test(propIn)) {
		endProp = 'o' + propOut + 'End';
	  } else if (propIn) {
		endProp = propOut.toLowerCase() + 'end';
	  }
	  return endProp;
	}
	
	// Test via a getter in the options object to see if the passive property is accessed
	var supportsPassive = false;
	try {
	  var opts = Object.defineProperty({}, 'passive', {
		get: function() {
		  supportsPassive = true;
		}
	  });
	  window.addEventListener("test", null, opts);
	} catch (e) {}
	var passiveOption = supportsPassive ? { passive: true } : false;
	
	function addEvents(el, obj, preventScrolling) {
	  for (var prop in obj) {
		var option = ['touchstart', 'touchmove'].indexOf(prop) >= 0 && !preventScrolling ? passiveOption : false;
		el.addEventListener(prop, obj[prop], option);
	  }
	}
	
	function removeEvents(el, obj) {
	  for (var prop in obj) {
		var option = ['touchstart', 'touchmove'].indexOf(prop) >= 0 ? passiveOption : false;
		el.removeEventListener(prop, obj[prop], option);
	  }
	}
	
	function Events() {
	  return {
		topics: {},
		on: function (eventName, fn) {
		  this.topics[eventName] = this.topics[eventName] || [];
		  this.topics[eventName].push(fn);
		},
		off: function(eventName, fn) {
		  if (this.topics[eventName]) {
			for (var i = 0; i < this.topics[eventName].length; i++) {
			  if (this.topics[eventName][i] === fn) {
				this.topics[eventName].splice(i, 1);
				break;
			  }
			}
		  }
		},
		emit: function (eventName, data) {
		  data.type = eventName;
		  if (this.topics[eventName]) {
			this.topics[eventName].forEach(function(fn) {
			  fn(data, eventName);
			});
		  }
		}
	  };
	}
	
	function jsTransform(element, attr, prefix, postfix, to, duration, callback) {
	  var tick = Math.min(duration, 10),
		  unit = (to.indexOf('%') >= 0) ? '%' : 'px',
		  to = to.replace(unit, ''),
		  from = Number(element.style[attr].replace(prefix, '').replace(postfix, '').replace(unit, '')),
		  positionTick = (to - from) / duration * tick,
		  running;
	
	  setTimeout(moveElement, tick);
	  function moveElement() {
		duration -= tick;
		from += positionTick;
		element.style[attr] = prefix + from + unit + postfix;
		if (duration > 0) { 
		  setTimeout(moveElement, tick); 
		} else {
		  callback();
		}
	  }
	}
	
	// ChildNode.remove
	if(!("remove" in Element.prototype)){
	  Element.prototype.remove = function(){
		if(this.parentNode) {
		  this.parentNode.removeChild(this);
		}
	  };
	}
	
	var tns = function(options) {
	  options = extend({
		container: '.slider',
		mode: 'carousel',
		axis: 'horizontal',
		items: 1,
		gutter: 0,
		edgePadding: 0,
		fixedWidth: false,
		autoWidth: false,
		viewportMax: false,
		slideBy: 1,
		center: false,
		controls: true,
		controlsPosition: 'top',
		controlsText: ['prev', 'next'],
		controlsContainer: false,
		prevButton: false,
		nextButton: false,
		nav: true,
		navPosition: 'top',
		navContainer: false,
		navAsThumbnails: false,
		arrowKeys: false,
		speed: 300,
		autoplay: false,
		autoplayPosition: 'top',
		autoplayTimeout: 5000,
		autoplayDirection: 'forward',
		autoplayText: ['start', 'stop'],
		autoplayHoverPause: false,
		autoplayButton: false,
		autoplayButtonOutput: true,
		autoplayResetOnVisibility: true,
		animateIn: 'tns-fadeIn',
		animateOut: 'tns-fadeOut',
		animateNormal: 'tns-normal',
		animateDelay: false,
		loop: true,
		rewind: false,
		autoHeight: false,
		responsive: false,
		lazyload: false,
		lazyloadSelector: '.tns-lazy-img',
		touch: true,
		mouseDrag: false,
		swipeAngle: 15,
		nested: false,
		preventActionWhenRunning: false,
		preventScrollOnTouch: false,
		freezable: true,
		onInit: false,
		useLocalStorage: true,
		textDirection: 'ltr'
	  }, options || {});
	
	  var doc = document,
		  win = window,
		  KEYS = {
			ENTER: 13,
			SPACE: 32,
			LEFT: 37,
			RIGHT: 39
		  },
		  tnsStorage = {},
		  localStorageAccess = options.useLocalStorage;
	
	  if (localStorageAccess) {
		// check browser version and local storage access
		var browserInfo = navigator.userAgent;
		var uid = new Date;
	
		try {
		  tnsStorage = win.localStorage;
		  if (tnsStorage) {
			tnsStorage.setItem(uid, uid);
			localStorageAccess = tnsStorage.getItem(uid) == uid;
			tnsStorage.removeItem(uid);
		  } else {
			localStorageAccess = false;
		  }
		  if (!localStorageAccess) { tnsStorage = {}; }
		} catch(e) {
		  localStorageAccess = false;
		}
	
		if (localStorageAccess) {
		  // remove storage when browser version changes
		  if (tnsStorage['tnsApp'] && tnsStorage['tnsApp'] !== browserInfo) {
			['tC', 'tPL', 'tMQ', 'tTf', 't3D', 'tTDu', 'tTDe', 'tADu', 'tADe', 'tTE', 'tAE'].forEach(function(item) { tnsStorage.removeItem(item); });
		  }
		  // update browserInfo
		  localStorage['tnsApp'] = browserInfo;
		}
	  }
	
	  var CALC = tnsStorage['tC'] ? checkStorageValue(tnsStorage['tC']) : setLocalStorage(tnsStorage, 'tC', calc(), localStorageAccess),
		  PERCENTAGELAYOUT = tnsStorage['tPL'] ? checkStorageValue(tnsStorage['tPL']) : setLocalStorage(tnsStorage, 'tPL', percentageLayout(), localStorageAccess),
		  CSSMQ = tnsStorage['tMQ'] ? checkStorageValue(tnsStorage['tMQ']) : setLocalStorage(tnsStorage, 'tMQ', mediaquerySupport(), localStorageAccess),
		  TRANSFORM = tnsStorage['tTf'] ? checkStorageValue(tnsStorage['tTf']) : setLocalStorage(tnsStorage, 'tTf', whichProperty('transform'), localStorageAccess),
		  HAS3DTRANSFORMS = tnsStorage['t3D'] ? checkStorageValue(tnsStorage['t3D']) : setLocalStorage(tnsStorage, 't3D', has3DTransforms(TRANSFORM), localStorageAccess),
		  TRANSITIONDURATION = tnsStorage['tTDu'] ? checkStorageValue(tnsStorage['tTDu']) : setLocalStorage(tnsStorage, 'tTDu', whichProperty('transitionDuration'), localStorageAccess),
		  TRANSITIONDELAY = tnsStorage['tTDe'] ? checkStorageValue(tnsStorage['tTDe']) : setLocalStorage(tnsStorage, 'tTDe', whichProperty('transitionDelay'), localStorageAccess),
		  ANIMATIONDURATION = tnsStorage['tADu'] ? checkStorageValue(tnsStorage['tADu']) : setLocalStorage(tnsStorage, 'tADu', whichProperty('animationDuration'), localStorageAccess),
		  ANIMATIONDELAY = tnsStorage['tADe'] ? checkStorageValue(tnsStorage['tADe']) : setLocalStorage(tnsStorage, 'tADe', whichProperty('animationDelay'), localStorageAccess),
		  TRANSITIONEND = tnsStorage['tTE'] ? checkStorageValue(tnsStorage['tTE']) : setLocalStorage(tnsStorage, 'tTE', getEndProperty(TRANSITIONDURATION, 'Transition'), localStorageAccess),
		  ANIMATIONEND = tnsStorage['tAE'] ? checkStorageValue(tnsStorage['tAE']) : setLocalStorage(tnsStorage, 'tAE', getEndProperty(ANIMATIONDURATION, 'Animation'), localStorageAccess);
	
	  // get element nodes from selectors
	  var supportConsoleWarn = win.console && typeof win.console.warn === "function",
		  tnsList = ['container', 'controlsContainer', 'prevButton', 'nextButton', 'navContainer', 'autoplayButton'],
		  optionsElements = {};
	
	  tnsList.forEach(function(item) {
		if (typeof options[item] === 'string') {
		  var str = options[item],
			  el = doc.querySelector(str);
		  optionsElements[item] = str;
	
		  if (el && el.nodeName) {
			options[item] = el;
		  } else {
			if (supportConsoleWarn) { console.warn('Can\'t find', options[item]); }
			return;
		  }
		}
	  });
	
	  // make sure at least 1 slide
	  if (options.container.children.length < 1) {
		if (supportConsoleWarn) { console.warn('No slides found in', options.container); }
		return;
	   }
	
	  // update options
	  var responsive = options.responsive,
		  nested = options.nested,
		  carousel = options.mode === 'carousel' ? true : false;
	
	  if (responsive) {
		// apply responsive[0] to options and remove it
		if (0 in responsive) {
		  options = extend(options, responsive[0]);
		  delete responsive[0];
		}
	
		var responsiveTem = {};
		for (var key in responsive) {
		  var val = responsive[key];
		  // update responsive
		  // from: 300: 2
		  // to:
		  //   300: {
		  //     items: 2
		  //   }
		  val = typeof val === 'number' ? {items: val} : val;
		  responsiveTem[key] = val;
		}
		responsive = responsiveTem;
		responsiveTem = null;
	  }
	
	  // update options
	  function updateOptions (obj) {
		for (var key in obj) {
		  if (!carousel) {
			if (key === 'slideBy') { obj[key] = 'page'; }
			if (key === 'edgePadding') { obj[key] = false; }
			if (key === 'autoHeight') { obj[key] = false; }
		  }
	
		  // update responsive options
		  if (key === 'responsive') { updateOptions(obj[key]); }
		}
	  }
	  if (!carousel) { updateOptions(options); }
	
	
	  // === define and set variables ===
	  if (!carousel) {
		options.axis = 'horizontal';
		options.slideBy = 'page';
		options.edgePadding = false;
	
		var animateIn = options.animateIn,
			animateOut = options.animateOut,
			animateDelay = options.animateDelay,
			animateNormal = options.animateNormal;
	  }
	
	  var horizontal = options.axis === 'horizontal' ? true : false,
		  outerWrapper = doc.createElement('div'),
		  innerWrapper = doc.createElement('div'),
		  middleWrapper,
		  container = options.container,
		  containerParent = container.parentNode,
		  containerHTML = container.outerHTML,
		  slideItems = container.children,
		  slideCount = slideItems.length,
		  breakpointZone,
		  windowWidth = getWindowWidth(),
		  isOn = false;
	  if (responsive) { setBreakpointZone(); }
	  if (carousel) { container.className += ' tns-vpfix'; }
	
	  // fixedWidth: viewport > rightBoundary > indexMax
	  var autoWidth = options.autoWidth,
		  fixedWidth = getOption('fixedWidth'),
		  edgePadding = getOption('edgePadding'),
		  gutter = getOption('gutter'),
		  viewport = getViewportWidth(),
		  center = getOption('center'),
		  items = !autoWidth ? Math.floor(getOption('items')) : 1,
		  slideBy = getOption('slideBy'),
		  viewportMax = options.viewportMax || options.fixedWidthViewportWidth,
		  arrowKeys = getOption('arrowKeys'),
		  speed = getOption('speed'),
		  rewind = options.rewind,
		  loop = rewind ? false : options.loop,
		  autoHeight = getOption('autoHeight'),
		  controls = getOption('controls'),
		  controlsText = getOption('controlsText'),
		  textDirection = getOption('textDirection'),
		  nav = getOption('nav'),
		  touch = getOption('touch'),
		  mouseDrag = getOption('mouseDrag'),
		  autoplay = getOption('autoplay'),
		  autoplayTimeout = getOption('autoplayTimeout'),
		  autoplayText = getOption('autoplayText'),
		  autoplayHoverPause = getOption('autoplayHoverPause'),
		  autoplayResetOnVisibility = getOption('autoplayResetOnVisibility'),
		  sheet = createStyleSheet(),
		  lazyload = options.lazyload,
		  lazyloadSelector = options.lazyloadSelector,
		  slidePositions, // collection of slide positions
		  slideItemsOut = [],
		  cloneCount = loop ? getCloneCountForLoop() : 0,
		  slideCountNew = !carousel ? slideCount + cloneCount : slideCount + cloneCount * 2,
		  hasRightDeadZone = (fixedWidth || autoWidth) && !loop ? true : false,
		  rightBoundary = fixedWidth ? getRightBoundary() : null,
		  updateIndexBeforeTransform = (!carousel || !loop) ? true : false,
		  // transform
		  transformAttr = horizontal ? 'left' : 'top',
		  transformPrefix = '',
		  transformPostfix = '',
		  // index
		  getIndexMax = (function () {
			if (fixedWidth) {
			  return function() { return center && !loop ? slideCount - 1 : Math.ceil(- rightBoundary / (fixedWidth + gutter)); };
			} else if (autoWidth) {
			  return function() {
				for (var i = slideCountNew; i--;) {
				  if (slidePositions[i] >= - rightBoundary) { return i; }
				}
			  };
			} else {
			  return function() {
				if (center && carousel && !loop) {
				  return slideCount - 1;
				} else {
				  return loop || carousel ? Math.max(0, slideCountNew - Math.ceil(items)) : slideCountNew - 1;
				}
			  };
			}
		  })(),
		  index = getStartIndex(getOption('startIndex')),
		  indexCached = index,
		  displayIndex = getCurrentSlide(),
		  indexMin = 0,
		  indexMax = !autoWidth ? getIndexMax() : null,
		  // resize
		  resizeTimer,
		  preventActionWhenRunning = options.preventActionWhenRunning,
		  swipeAngle = options.swipeAngle,
		  moveDirectionExpected = swipeAngle ? '?' : true,
		  running = false,
		  onInit = options.onInit,
		  events = new Events(),
		  // id, class
		  newContainerClasses = ' tns-slider tns-' + options.mode,
		  slideId = container.id || getSlideId(),
		  disable = getOption('disable'),
		  disabled = false,
		  freezable = options.freezable,
		  freeze = freezable && !autoWidth ? getFreeze() : false,
		  frozen = false,
		  controlsEvents = {
			'click': onControlsClick,
			'keydown': onControlsKeydown
		  },
		  navEvents = {
			'click': onNavClick,
			'keydown': onNavKeydown
		  },
		  hoverEvents = {
			'mouseover': mouseoverPause,
			'mouseout': mouseoutRestart
		  },
		  visibilityEvent = {'visibilitychange': onVisibilityChange},
		  docmentKeydownEvent = {'keydown': onDocumentKeydown},
		  touchEvents = {
			'touchstart': onPanStart,
			'touchmove': onPanMove,
			'touchend': onPanEnd,
			'touchcancel': onPanEnd
		  }, dragEvents = {
			'mousedown': onPanStart,
			'mousemove': onPanMove,
			'mouseup': onPanEnd,
			'mouseleave': onPanEnd
		  },
		  hasControls = hasOption('controls'),
		  hasNav = hasOption('nav'),
		  navAsThumbnails = autoWidth ? true : options.navAsThumbnails,
		  hasAutoplay = hasOption('autoplay'),
		  hasTouch = hasOption('touch'),
		  hasMouseDrag = hasOption('mouseDrag'),
		  slideActiveClass = 'tns-slide-active',
		  imgCompleteClass = 'tns-complete',
		  imgEvents = {
			'load': onImgLoaded,
			'error': onImgFailed
		  },
		  imgsComplete,
		  liveregionCurrent,
		  preventScroll = options.preventScrollOnTouch === 'force' ? true : false;
	
	  // controls
	  if (hasControls) {
		var controlsContainer = options.controlsContainer,
			controlsContainerHTML = options.controlsContainer ? options.controlsContainer.outerHTML : '',
			prevButton = options.prevButton,
			nextButton = options.nextButton,
			prevButtonHTML = options.prevButton ? options.prevButton.outerHTML : '',
			nextButtonHTML = options.nextButton ? options.nextButton.outerHTML : '',
			prevIsButton,
			nextIsButton;
	  }
	
	  // nav
	  if (hasNav) {
		var navContainer = options.navContainer,
			navContainerHTML = options.navContainer ? options.navContainer.outerHTML : '',
			navItems,
			pages = autoWidth ? slideCount : getPages(),
			pagesCached = 0,
			navClicked = -1,
			navCurrentIndex = getCurrentNavIndex(),
			navCurrentIndexCached = navCurrentIndex,
			navActiveClass = 'tns-nav-active',
			navStr = 'Carousel Page ',
			navStrCurrent = ' (Current Slide)';
	  }
	
	  // autoplay
	  if (hasAutoplay) {
		var autoplayDirection = options.autoplayDirection === 'forward' ? 1 : -1,
			autoplayButton = options.autoplayButton,
			autoplayButtonHTML = options.autoplayButton ? options.autoplayButton.outerHTML : '',
			autoplayHtmlStrings = ['<span class=\'tns-visually-hidden\'>', ' animation</span>'],
			autoplayTimer,
			animating,
			autoplayHoverPaused,
			autoplayUserPaused,
			autoplayVisibilityPaused;
	  }
	
	  if (hasTouch || hasMouseDrag) {
		var initPosition = {},
			lastPosition = {},
			translateInit,
			disX,
			disY,
			panStart = false,
			rafIndex,
			getDist = horizontal ?
			  function(a, b) { return a.x - b.x; } :
			  function(a, b) { return a.y - b.y; };
	  }
	
	  // disable slider when slidecount <= items
	  if (!autoWidth) { resetVariblesWhenDisable(disable || freeze); }
	
	  if (TRANSFORM) {
		transformAttr = TRANSFORM;
		transformPrefix = 'translate';
	
		if (HAS3DTRANSFORMS) {
		  transformPrefix += horizontal ? '3d(' : '3d(0px, ';
		  transformPostfix = horizontal ? ', 0px, 0px)' : ', 0px)';
		} else {
		  transformPrefix += horizontal ? 'X(' : 'Y(';
		  transformPostfix = ')';
		}
	
	  }
	
	  if (carousel) { container.className = container.className.replace('tns-vpfix', ''); }
	  initStructure();
	  initSheet();
	  initSliderTransform();
	
	  // === COMMON FUNCTIONS === //
	  function resetVariblesWhenDisable (condition) {
		if (condition) {
		  controls = nav = touch = mouseDrag = arrowKeys = autoplay = autoplayHoverPause = autoplayResetOnVisibility = false;
		}
	  }
	
	  function getCurrentSlide () {
		var tem = carousel ? index - cloneCount : index;
		while (tem < 0) { tem += slideCount; }
		return tem%slideCount + 1;
	  }
	
	  function getStartIndex (ind) {
		ind = ind ? Math.max(0, Math.min(loop ? slideCount - 1 : slideCount - items, ind)) : 0;
		return carousel ? ind + cloneCount : ind;
	  }
	
	  function getAbsIndex (i) {
		if (i == null) { i = index; }
	
		if (carousel) { i -= cloneCount; }
		while (i < 0) { i += slideCount; }
	
		return Math.floor(i%slideCount);
	  }
	
	  function getCurrentNavIndex () {
		var absIndex = getAbsIndex(),
			result;
	
		result = navAsThumbnails ? absIndex :
		  fixedWidth || autoWidth ? Math.ceil((absIndex + 1) * pages / slideCount - 1) :
			  Math.floor(absIndex / items);
	
		// set active nav to the last one when reaches the right edge
		if (!loop && carousel && index === indexMax) { result = pages - 1; }
	
		return result;
	  }
	
	  function getItemsMax () {
		// fixedWidth or autoWidth while viewportMax is not available
		if (autoWidth || (fixedWidth && !viewportMax)) {
		  return slideCount - 1;
		// most cases
		} else {
		  var str = fixedWidth ? 'fixedWidth' : 'items',
			  arr = [];
	
		  if (fixedWidth || options[str] < slideCount) { arr.push(options[str]); }
	
		  if (responsive) {
			for (var bp in responsive) {
			  var tem = responsive[bp][str];
			  if (tem && (fixedWidth || tem < slideCount)) { arr.push(tem); }
			}
		  }
	
		  if (!arr.length) { arr.push(0); }
	
		  return Math.ceil(fixedWidth ? viewportMax / Math.min.apply(null, arr) : Math.max.apply(null, arr));
		}
	  }
	
	  function getCloneCountForLoop () {
		var itemsMax = getItemsMax(),
			result = carousel ? Math.ceil((itemsMax * 5 - slideCount)/2) : (itemsMax * 4 - slideCount);
		result = Math.max(itemsMax, result);
	
		return hasOption('edgePadding') ? result + 1 : result;
	  }
	
	  function getWindowWidth () {
		return win.innerWidth || doc.documentElement.clientWidth || doc.body.clientWidth;
	  }
	
	  function getInsertPosition (pos) {
		return pos === 'top' ? 'afterbegin' : 'beforeend';
	  }
	
	  function getClientWidth (el) {
		if (el == null) { return; }
		var div = doc.createElement('div'), rect, width;
		el.appendChild(div);
		rect = div.getBoundingClientRect();
		width = rect.right - rect.left;
		div.remove();
		return width || getClientWidth(el.parentNode);
	  }
	
	  function getViewportWidth () {
		var gap = edgePadding ? edgePadding * 2 - gutter : 0;
		return getClientWidth(containerParent) - gap;
	  }
	
	  function hasOption (item) {
		if (options[item]) {
		  return true;
		} else {
		  if (responsive) {
			for (var bp in responsive) {
			  if (responsive[bp][item]) { return true; }
			}
		  }
		  return false;
		}
	  }
	
	  // get option:
	  // fixed width: viewport, fixedWidth, gutter => items
	  // others: window width => all variables
	  // all: items => slideBy
	  function getOption (item, ww) {
		if (ww == null) { ww = windowWidth; }
	
		if (item === 'items' && fixedWidth) {
		  return Math.floor((viewport + gutter) / (fixedWidth + gutter)) || 1;
	
		} else {
		  var result = options[item];
	
		  if (responsive) {
			for (var bp in responsive) {
			  // bp: convert string to number
			  if (ww >= parseInt(bp)) {
				if (item in responsive[bp]) { result = responsive[bp][item]; }
			  }
			}
		  }
	
		  if (item === 'slideBy' && result === 'page') { result = getOption('items'); }
		  if (!carousel && (item === 'slideBy' || item === 'items')) { result = Math.floor(result); }
	
		  return result;
		}
	  }
	
	  function getSlideMarginLeft (i) {
		return CALC ?
		  CALC + '(' + i * 100 + '% / ' + slideCountNew + ')' :
		  i * 100 / slideCountNew + '%';
	  }
	
	  function getInnerWrapperStyles (edgePaddingTem, gutterTem, fixedWidthTem, speedTem, autoHeightBP) {
		var str = '';
	
		if (edgePaddingTem !== undefined) {
		  var gap = edgePaddingTem;
		  if (gutterTem) { gap -= gutterTem; }
		  str = horizontal ?
			'margin: 0 ' + gap + 'px 0 ' + edgePaddingTem + 'px;' :
			'margin: ' + edgePaddingTem + 'px 0 ' + gap + 'px 0;';
		} else if (gutterTem && !fixedWidthTem) {
		  var gutterTemUnit = '-' + gutterTem + 'px',
			  dir = horizontal ? gutterTemUnit + ' 0 0' : '0 ' + gutterTemUnit + ' 0';
		  str = 'margin: 0 ' + dir + ';';
		}
	
		if (!carousel && autoHeightBP && TRANSITIONDURATION && speedTem) { str += getTransitionDurationStyle(speedTem); }
		return str;
	  }
	
	  function getContainerWidth (fixedWidthTem, gutterTem, itemsTem) {
		if (fixedWidthTem) {
		  return (fixedWidthTem + gutterTem) * slideCountNew + 'px';
		} else {
		  return CALC ?
			CALC + '(' + slideCountNew * 100 + '% / ' + itemsTem + ')' :
			slideCountNew * 100 / itemsTem + '%';
		}
	  }
	
	  function getSlideWidthStyle (fixedWidthTem, gutterTem, itemsTem) {
		var width;
	
		if (fixedWidthTem) {
		  width = (fixedWidthTem + gutterTem) + 'px';
		} else {
		  if (!carousel) { itemsTem = Math.floor(itemsTem); }
		  var dividend = carousel ? slideCountNew : itemsTem;
		  width = CALC ?
			CALC + '(100% / ' + dividend + ')' :
			100 / dividend + '%';
		}
	
		width = 'width:' + width;
	
		// inner slider: overwrite outer slider styles
		return nested !== 'inner' ? width + ';' : width + ' !important;';
	  }
	
	  function getSlideGutterStyle (gutterTem) {
		var str = '';
	
		// gutter maybe interger || 0
		// so can't use 'if (gutter)'
		if (gutterTem !== false) {
		  var prop = horizontal ? 'padding-' : 'margin-',
			  dir = horizontal ? 'right' : 'bottom';
		  str = prop +  dir + ': ' + gutterTem + 'px;';
		}
	
		return str;
	  }
	
	  function getCSSPrefix (name, num) {
		var prefix = name.substring(0, name.length - num).toLowerCase();
		if (prefix) { prefix = '-' + prefix + '-'; }
	
		return prefix;
	  }
	
	  function getTransitionDurationStyle (speed) {
		return getCSSPrefix(TRANSITIONDURATION, 18) + 'transition-duration:' + speed / 1000 + 's;';
	  }
	
	  function getAnimationDurationStyle (speed) {
		return getCSSPrefix(ANIMATIONDURATION, 17) + 'animation-duration:' + speed / 1000 + 's;';
	  }
	
	  function initStructure () {
		var classOuter = 'tns-outer',
			classInner = 'tns-inner',
			hasGutter = hasOption('gutter');
	
		outerWrapper.className = classOuter;
		innerWrapper.className = classInner;
		outerWrapper.id = slideId + '-ow';
		innerWrapper.id = slideId + '-iw';
	
		// set container properties
		if (container.id === '') { container.id = slideId; }
		newContainerClasses += PERCENTAGELAYOUT || autoWidth ? ' tns-subpixel' : ' tns-no-subpixel';
		newContainerClasses += CALC ? ' tns-calc' : ' tns-no-calc';
		if (autoWidth) { newContainerClasses += ' tns-autowidth'; }
		newContainerClasses += ' tns-' + options.axis;
		container.className += newContainerClasses;
	
		// add constrain layer for carousel
		if (carousel) {
		  middleWrapper = doc.createElement('div');
		  middleWrapper.id = slideId + '-mw';
		  middleWrapper.className = 'tns-ovh';
	
		  outerWrapper.appendChild(middleWrapper);
		  middleWrapper.appendChild(innerWrapper);
		} else {
		  outerWrapper.appendChild(innerWrapper);
		}
	
		if (autoHeight) {
		  var wp = middleWrapper ? middleWrapper : innerWrapper;
		  wp.className += ' tns-ah';
		}
	
		containerParent.insertBefore(outerWrapper, container);
		innerWrapper.appendChild(container);
	
		// add id, class, aria attributes
		// before clone slides
		forEach(slideItems, function(item, i) {
		  addClass(item, 'tns-item');
		  if (!item.id) { item.id = slideId + '-item' + i; }
		  if (!carousel && animateNormal) { addClass(item, animateNormal); }
		  setAttrs(item, {
			'aria-hidden': 'true',
			'tabindex': '-1'
		  });
		  setInnerAttrs( item, {
			'tabindex': '-1'
		  } );
		});
	
		// ## clone slides
		// carousel: n + slides + n
		// gallery:      slides + n
		if (cloneCount) {
		  var fragmentBefore = doc.createDocumentFragment(),
			  fragmentAfter = doc.createDocumentFragment();
	
		  for (var j = cloneCount; j--;) {
			var num = j%slideCount,
				cloneFirst = slideItems[num].cloneNode(true);
			removeAttrs(cloneFirst, 'id');
			fragmentAfter.insertBefore(cloneFirst, fragmentAfter.firstChild);
	
			if (carousel) {
			  var cloneLast = slideItems[slideCount - 1 - num].cloneNode(true);
			  removeAttrs(cloneLast, 'id');
			  fragmentBefore.appendChild(cloneLast);
			}
		  }
	
		  container.insertBefore(fragmentBefore, container.firstChild);
		  container.appendChild(fragmentAfter);
		  slideItems = container.children;
		}
	
	  }
	
	  function initSliderTransform () {
		// ## images loaded/failed
		if (hasOption('autoHeight') || autoWidth || !horizontal) {
		  var imgs = container.querySelectorAll('img');
	
		  // add img load event listener
		  forEach(imgs, function(img) {
			var src = img.src;
	
			if (!lazyload) {
			  // not data img
			  if (src && src.indexOf('data:image') < 0) {
				img.src = '';
				addEvents(img, imgEvents);
				addClass(img, 'loading');
	
				img.src = src;
			  // data img
			  } else {
				imgLoaded(img);
			  }
			}
		  });
	
		  // set imgsComplete
		  raf(function(){ imgsLoadedCheck(arrayFromNodeList(imgs), function() { imgsComplete = true; }); });
	
		  // reset imgs for auto height: check visible imgs only
		  if (hasOption('autoHeight')) { imgs = getImageArray(index, Math.min(index + items - 1, slideCountNew - 1)); }
	
		  lazyload ? initSliderTransformStyleCheck() : raf(function(){ imgsLoadedCheck(arrayFromNodeList(imgs), initSliderTransformStyleCheck); });
	
		} else {
		  // set container transform property
		  if (carousel) { doContainerTransformSilent(); }
	
		  // update slider tools and events
		  initTools();
		  initEvents();
		}
	  }
	
	  function initSliderTransformStyleCheck () {
		if (autoWidth) {
		  // check styles application
		  var num = loop ? index : slideCount - 1;
	
		  (function stylesApplicationCheck() {
			var left = slideItems[num].getBoundingClientRect().left;
			var right = slideItems[num - 1].getBoundingClientRect().right;
	
			(Math.abs(left - right) <= 1) ?
			  initSliderTransformCore() :
			  setTimeout(function(){ stylesApplicationCheck(); }, 16);
		  })();
	
		} else {
		  initSliderTransformCore();
		}
	  }
	
	
	  function initSliderTransformCore () {
		// run Fn()s which are rely on image loading
		if (!horizontal || autoWidth) {
		  setSlidePositions();
	
		  if (autoWidth) {
			rightBoundary = getRightBoundary();
			if (freezable) { freeze = getFreeze(); }
			indexMax = getIndexMax(); // <= slidePositions, rightBoundary <=
			resetVariblesWhenDisable(disable || freeze);
		  } else {
			updateContentWrapperHeight();
		  }
		}
	
		// set container transform property
		if (carousel) { doContainerTransformSilent(); }
	
		// update slider tools and events
		initTools();
		initEvents();
	  }
	
	  function initSheet () {
		// gallery:
		// set animation classes and left value for gallery slider
		if (!carousel) {
		  for (var i = index, l = index + Math.min(slideCount, items); i < l; i++) {
			var item = slideItems[i];
			item.style.left = (i - index) * 100 / items + '%';
			addClass(item, animateIn);
			removeClass(item, animateNormal);
		  }
		}
	
		// #### LAYOUT
	
		// ## INLINE-BLOCK VS FLOAT
	
		// ## PercentageLayout:
		// slides: inline-block
		// remove blank space between slides by set font-size: 0
	
		// ## Non PercentageLayout:
		// slides: float
		//         margin-right: -100%
		//         margin-left: ~
	
		// Resource: https://docs.google.com/spreadsheets/d/147up245wwTXeQYve3BRSAD4oVcvQmuGsFteJOeA5xNQ/edit?usp=sharing
		if (horizontal) {
		  if (PERCENTAGELAYOUT || autoWidth) {
			addCSSRule(sheet, '#' + slideId + ' > .tns-item', 'font-size:' + win.getComputedStyle(slideItems[0]).fontSize + ';', getCssRulesLength(sheet));
			addCSSRule(sheet, '#' + slideId, 'font-size:0;', getCssRulesLength(sheet));
		  } else if (carousel) {
			forEach(slideItems, function (slide, i) {
			  slide.style.marginLeft = getSlideMarginLeft(i);
			});
		  }
		}
	
	
		// ## BASIC STYLES
		if (CSSMQ) {
		  // middle wrapper style
		  if (TRANSITIONDURATION) {
			var str = middleWrapper && options.autoHeight ? getTransitionDurationStyle(options.speed) : '';
			addCSSRule(sheet, '#' + slideId + '-mw', str, getCssRulesLength(sheet));
		  }
	
		  // inner wrapper styles
		  str = getInnerWrapperStyles(options.edgePadding, options.gutter, options.fixedWidth, options.speed, options.autoHeight);
		  addCSSRule(sheet, '#' + slideId + '-iw', str, getCssRulesLength(sheet));
	
		  // container styles
		  if (carousel) {
			str = horizontal && !autoWidth ? 'width:' + getContainerWidth(options.fixedWidth, options.gutter, options.items) + ';' : '';
			if (TRANSITIONDURATION) { str += getTransitionDurationStyle(speed); }
			addCSSRule(sheet, '#' + slideId, str, getCssRulesLength(sheet));
		  }
	
		  // slide styles
		  str = horizontal && !autoWidth ? getSlideWidthStyle(options.fixedWidth, options.gutter, options.items) : '';
		  if (options.gutter) { str += getSlideGutterStyle(options.gutter); }
		  // set gallery items transition-duration
		  if (!carousel) {
			if (TRANSITIONDURATION) { str += getTransitionDurationStyle(speed); }
			if (ANIMATIONDURATION) { str += getAnimationDurationStyle(speed); }
		  }
		  if (str) { addCSSRule(sheet, '#' + slideId + ' > .tns-item', str, getCssRulesLength(sheet)); }
	
		// non CSS mediaqueries: IE8
		// ## update inner wrapper, container, slides if needed
		// set inline styles for inner wrapper & container
		// insert stylesheet (one line) for slides only (since slides are many)
		} else {
		  // middle wrapper styles
		  update_carousel_transition_duration();
	
		  // inner wrapper styles
		  innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, gutter, fixedWidth, autoHeight);
	
		  // container styles
		  if (carousel && horizontal && !autoWidth) {
			container.style.width = getContainerWidth(fixedWidth, gutter, items);
		  }
	
		  // slide styles
		  var str = horizontal && !autoWidth ? getSlideWidthStyle(fixedWidth, gutter, items) : '';
		  if (gutter) { str += getSlideGutterStyle(gutter); }
	
		  // append to the last line
		  if (str) { addCSSRule(sheet, '#' + slideId + ' > .tns-item', str, getCssRulesLength(sheet)); }
		}
	
		// ## MEDIAQUERIES
		if (responsive && CSSMQ) {
		  for (var bp in responsive) {
			// bp: convert string to number
			bp = parseInt(bp);
	
			var opts = responsive[bp],
				str = '',
				middleWrapperStr = '',
				innerWrapperStr = '',
				containerStr = '',
				slideStr = '',
				itemsBP = !autoWidth ? getOption('items', bp) : null,
				fixedWidthBP = getOption('fixedWidth', bp),
				speedBP = getOption('speed', bp),
				edgePaddingBP = getOption('edgePadding', bp),
				autoHeightBP = getOption('autoHeight', bp),
				gutterBP = getOption('gutter', bp);
	
			// middle wrapper string
			if (TRANSITIONDURATION && middleWrapper && getOption('autoHeight', bp) && 'speed' in opts) {
			  middleWrapperStr = '#' + slideId + '-mw{' + getTransitionDurationStyle(speedBP) + '}';
			}
	
			// inner wrapper string
			if ('edgePadding' in opts || 'gutter' in opts) {
			  innerWrapperStr = '#' + slideId + '-iw{' + getInnerWrapperStyles(edgePaddingBP, gutterBP, fixedWidthBP, speedBP, autoHeightBP) + '}';
			}
	
			// container string
			if (carousel && horizontal && !autoWidth && ('fixedWidth' in opts || 'items' in opts || (fixedWidth && 'gutter' in opts))) {
			  containerStr = 'width:' + getContainerWidth(fixedWidthBP, gutterBP, itemsBP) + ';';
			}
			if (TRANSITIONDURATION && 'speed' in opts) {
			  containerStr += getTransitionDurationStyle(speedBP);
			}
			if (containerStr) {
			  containerStr = '#' + slideId + '{' + containerStr + '}';
			}
	
			// slide string
			if ('fixedWidth' in opts || (fixedWidth && 'gutter' in opts) || !carousel && 'items' in opts) {
			  slideStr += getSlideWidthStyle(fixedWidthBP, gutterBP, itemsBP);
			}
			if ('gutter' in opts) {
			  slideStr += getSlideGutterStyle(gutterBP);
			}
			// set gallery items transition-duration
			if (!carousel && 'speed' in opts) {
			  if (TRANSITIONDURATION) { slideStr += getTransitionDurationStyle(speedBP); }
			  if (ANIMATIONDURATION) { slideStr += getAnimationDurationStyle(speedBP); }
			}
			if (slideStr) { slideStr = '#' + slideId + ' > .tns-item{' + slideStr + '}'; }
	
			// add up
			str = middleWrapperStr + innerWrapperStr + containerStr + slideStr;
	
			if (str) {
			  sheet.insertRule('@media (min-width: ' + bp / 16 + 'em) {' + str + '}', sheet.cssRules.length);
			}
		  }
		}
	  }
	
	  function initTools () {
		// == slides ==
		updateSlideStatus();
	
		// == live region ==
		outerWrapper.insertAdjacentHTML('afterbegin', '<div class="tns-liveregion tns-visually-hidden" aria-live="polite" aria-atomic="true">slide <span class="current">' + getLiveRegionStr() + '</span>  of ' + slideCount + '</div>');
		liveregionCurrent = outerWrapper.querySelector('.tns-liveregion .current');
	
		// == autoplayInit ==
		if (hasAutoplay) {
		  var txt = autoplay ? 'stop' : 'start';
		  if (autoplayButton) {
			setAttrs(autoplayButton, {'data-action': txt});
		  } else if (options.autoplayButtonOutput) {
			outerWrapper.insertAdjacentHTML(getInsertPosition(options.autoplayPosition), '<button type="button" data-action="' + txt + '">' + autoplayHtmlStrings[0] + txt + autoplayHtmlStrings[1] + autoplayText[0] + '</button>');
			autoplayButton = outerWrapper.querySelector('[data-action]');
		  }
	
		  // add event
		  if (autoplayButton) {
			addEvents(autoplayButton, {'click': toggleAutoplay});
		  }
	
		  if (autoplay) {
			startAutoplay();
			if (autoplayHoverPause) { addEvents(container, hoverEvents); }
			if (autoplayResetOnVisibility) { addEvents(container, visibilityEvent); }
		  }
		}
	
		// == navInit ==
		if (hasNav) {
		  var initIndex = !carousel ? 0 : cloneCount;
		  // customized nav
		  // will not hide the navs in case they're thumbnails
		  if (navContainer) {
			setAttrs(navContainer, {'aria-label': 'Carousel Pagination'});
			navItems = navContainer.children;
			forEach(navItems, function(item, i) {
			  setAttrs(item, {
				'data-nav': i,
				'tabindex': '-1',
				'aria-label': navStr + (i + 1),
				'aria-controls': slideId,
			  });
			});
	
		  // generated nav
		  } else {
			var navHtml = '',
				hiddenStr = navAsThumbnails ? '' : 'style="display:none"';
			for (var i = 0; i < slideCount; i++) {
			  // hide nav items by default
			  navHtml += '<button type="button" data-nav="' + i +'" tabindex="-1" aria-controls="' + slideId + '" ' + hiddenStr + ' aria-label="' + navStr + (i + 1) +'"></button>';
			}
			navHtml = '<div class="tns-nav" aria-label="Carousel Pagination">' + navHtml + '</div>';
			outerWrapper.insertAdjacentHTML(getInsertPosition(options.navPosition), navHtml);
	
			navContainer = outerWrapper.querySelector('.tns-nav');
			navItems = navContainer.children;
		  }
	
		  updateNavVisibility();
	
		  // add transition
		  if (TRANSITIONDURATION) {
			var prefix = TRANSITIONDURATION.substring(0, TRANSITIONDURATION.length - 18).toLowerCase(),
				str = 'transition: all ' + speed / 1000 + 's';
	
			if (prefix) {
			  str = '-' + prefix + '-' + str;
			}
	
			addCSSRule(sheet, '[aria-controls^=' + slideId + '-item]', str, getCssRulesLength(sheet));
		  }
	
		  setAttrs(navItems[navCurrentIndex], {'aria-label': navStr + (navCurrentIndex + 1) + navStrCurrent});
		  removeAttrs(navItems[navCurrentIndex], 'tabindex');
		  addClass(navItems[navCurrentIndex], navActiveClass);
	
		  // add events
		  addEvents(navContainer, navEvents);
		}
	
	
	
		// == controlsInit ==
		if (hasControls) {
		  if (!controlsContainer && (!prevButton || !nextButton)) {
			outerWrapper.insertAdjacentHTML(getInsertPosition(options.controlsPosition), '<div class="tns-controls" aria-label="Carousel Navigation" tabindex="0"><button type="button" data-controls="prev" tabindex="-1" aria-controls="' + slideId +'">' + controlsText[0] + '</button><button type="button" data-controls="next" tabindex="-1" aria-controls="' + slideId +'">' + controlsText[1] + '</button></div>');
	
			controlsContainer = outerWrapper.querySelector('.tns-controls');
		  }
	
		  if (!prevButton || !nextButton) {
			prevButton = controlsContainer.children[0];
			nextButton = controlsContainer.children[1];
		  }
	
		  if (options.controlsContainer) {
			setAttrs(controlsContainer, {
			  'aria-label': 'Carousel Navigation',
			  'tabindex': '0'
			});
		  }
	
		  if (options.controlsContainer || (options.prevButton && options.nextButton)) {
			setAttrs([prevButton, nextButton], {
			  'aria-controls': slideId,
			  'tabindex': '-1',
			});
		  }
	
		  if (options.controlsContainer || (options.prevButton && options.nextButton)) {
			setAttrs(prevButton, {'data-controls' : 'prev'});
			setAttrs(nextButton, {'data-controls' : 'next'});
		  }
	
		  prevIsButton = isButton(prevButton);
		  nextIsButton = isButton(nextButton);
	
		  updateControlsStatus();
	
		  // add events
		  if (controlsContainer) {
			addEvents(controlsContainer, controlsEvents);
		  } else {
			addEvents(prevButton, controlsEvents);
			addEvents(nextButton, controlsEvents);
		  }
		}
	
		// hide tools if needed
		disableUI();
	  }
	
	  function initEvents () {
		// add events
		if (carousel && TRANSITIONEND) {
		  var eve = {};
		  eve[TRANSITIONEND] = onTransitionEnd;
		  addEvents(container, eve);
		}
	
		if (touch) { addEvents(container, touchEvents, options.preventScrollOnTouch); }
		if (mouseDrag) { addEvents(container, dragEvents); }
		if (arrowKeys) { addEvents(doc, docmentKeydownEvent); }
	
		if (nested === 'inner') {
		  events.on('outerResized', function () {
			resizeTasks();
			events.emit('innerLoaded', info());
		  });
		} else if (responsive || fixedWidth || autoWidth || autoHeight || !horizontal) {
		  addEvents(win, {'resize': onResize});
		}
	
		if (autoHeight) {
		  if (nested === 'outer') {
			events.on('innerLoaded', doAutoHeight);
		  } else if (!disable) { doAutoHeight(); }
		}
	
		doLazyLoad();
		if (disable) { disableSlider(); } else if (freeze) { freezeSlider(); }
	
		events.on('indexChanged', additionalUpdates);
		if (nested === 'inner') { events.emit('innerLoaded', info()); }
		if (typeof onInit === 'function') { onInit(info()); }
		isOn = true;
	  }
	
	  function destroy () {
		// sheet
		sheet.disabled = true;
		if (sheet.ownerNode) { sheet.ownerNode.remove(); }
	
		// remove win event listeners
		removeEvents(win, {'resize': onResize});
	
		// arrowKeys, controls, nav
		if (arrowKeys) { removeEvents(doc, docmentKeydownEvent); }
		if (controlsContainer) { removeEvents(controlsContainer, controlsEvents); }
		if (navContainer) { removeEvents(navContainer, navEvents); }
	
		// autoplay
		removeEvents(container, hoverEvents);
		removeEvents(container, visibilityEvent);
		if (autoplayButton) { removeEvents(autoplayButton, {'click': toggleAutoplay}); }
		if (autoplay) { clearInterval(autoplayTimer); }
	
		// container
		if (carousel && TRANSITIONEND) {
		  var eve = {};
		  eve[TRANSITIONEND] = onTransitionEnd;
		  removeEvents(container, eve);
		}
		if (touch) { removeEvents(container, touchEvents); }
		if (mouseDrag) { removeEvents(container, dragEvents); }
	
		// cache Object values in options && reset HTML
		var htmlList = [containerHTML, controlsContainerHTML, prevButtonHTML, nextButtonHTML, navContainerHTML, autoplayButtonHTML];
	
		tnsList.forEach(function(item, i) {
		  var el = item === 'container' ? outerWrapper : options[item];
	
		  if (typeof el === 'object' && el) {
			var prevEl = el.previousElementSibling ? el.previousElementSibling : false,
				parentEl = el.parentNode;
			el.outerHTML = htmlList[i];
			options[item] = prevEl ? prevEl.nextElementSibling : parentEl.firstElementChild;
		  }
		});
	
	
		// reset variables
		tnsList = animateIn = animateOut = animateDelay = animateNormal = horizontal = outerWrapper = innerWrapper = container = containerParent = containerHTML = slideItems = slideCount = breakpointZone = windowWidth = autoWidth = fixedWidth = edgePadding = gutter = viewport = items = slideBy = viewportMax = arrowKeys = speed = rewind = loop = autoHeight = sheet = lazyload = slidePositions = slideItemsOut = cloneCount = slideCountNew = hasRightDeadZone = rightBoundary = updateIndexBeforeTransform = transformAttr = transformPrefix = transformPostfix = getIndexMax = index = indexCached = indexMin = indexMax = resizeTimer = swipeAngle = moveDirectionExpected = running = onInit = events = newContainerClasses = slideId = disable = disabled = freezable = freeze = frozen = controlsEvents = navEvents = hoverEvents = visibilityEvent = docmentKeydownEvent = touchEvents = dragEvents = hasControls = hasNav = navAsThumbnails = hasAutoplay = hasTouch = hasMouseDrag = slideActiveClass = imgCompleteClass = imgEvents = imgsComplete = controls = controlsText = controlsContainer = controlsContainerHTML = prevButton = nextButton = prevIsButton = nextIsButton = nav = navContainer = navContainerHTML = navItems = pages = pagesCached = navClicked = navCurrentIndex = navCurrentIndexCached = navActiveClass = navStr = navStrCurrent = autoplay = autoplayTimeout = autoplayDirection = autoplayText = autoplayHoverPause = autoplayButton = autoplayButtonHTML = autoplayResetOnVisibility = autoplayHtmlStrings = autoplayTimer = animating = autoplayHoverPaused = autoplayUserPaused = autoplayVisibilityPaused = initPosition = lastPosition = translateInit = disX = disY = panStart = rafIndex = getDist = touch = mouseDrag = null;
		// check variables
		// [animateIn, animateOut, animateDelay, animateNormal, horizontal, outerWrapper, innerWrapper, container, containerParent, containerHTML, slideItems, slideCount, breakpointZone, windowWidth, autoWidth, fixedWidth, edgePadding, gutter, viewport, items, slideBy, viewportMax, arrowKeys, speed, rewind, loop, autoHeight, sheet, lazyload, slidePositions, slideItemsOut, cloneCount, slideCountNew, hasRightDeadZone, rightBoundary, updateIndexBeforeTransform, transformAttr, transformPrefix, transformPostfix, getIndexMax, index, indexCached, indexMin, indexMax, resizeTimer, swipeAngle, moveDirectionExpected, running, onInit, events, newContainerClasses, slideId, disable, disabled, freezable, freeze, frozen, controlsEvents, navEvents, hoverEvents, visibilityEvent, docmentKeydownEvent, touchEvents, dragEvents, hasControls, hasNav, navAsThumbnails, hasAutoplay, hasTouch, hasMouseDrag, slideActiveClass, imgCompleteClass, imgEvents, imgsComplete, controls, controlsText, controlsContainer, controlsContainerHTML, prevButton, nextButton, prevIsButton, nextIsButton, nav, navContainer, navContainerHTML, navItems, pages, pagesCached, navClicked, navCurrentIndex, navCurrentIndexCached, navActiveClass, navStr, navStrCurrent, autoplay, autoplayTimeout, autoplayDirection, autoplayText, autoplayHoverPause, autoplayButton, autoplayButtonHTML, autoplayResetOnVisibility, autoplayHtmlStrings, autoplayTimer, animating, autoplayHoverPaused, autoplayUserPaused, autoplayVisibilityPaused, initPosition, lastPosition, translateInit, disX, disY, panStart, rafIndex, getDist, touch, mouseDrag ].forEach(function(item) { if (item !== null) { console.log(item); } });
	
		for (var a in this) {
		  if (a !== 'rebuild') { this[a] = null; }
		}
		isOn = false;
	  }
	
	// === ON RESIZE ===
	  // responsive || fixedWidth || autoWidth || !horizontal
	  function onResize (e) {
		raf(function(){ resizeTasks(getEvent(e)); });
	  }
	
	  function resizeTasks (e) {
		if (!isOn) { return; }
		if (nested === 'outer') { events.emit('outerResized', info(e)); }
		windowWidth = getWindowWidth();
		var bpChanged,
			breakpointZoneTem = breakpointZone,
			needContainerTransform = false;
	
		if (responsive) {
		  setBreakpointZone();
		  bpChanged = breakpointZoneTem !== breakpointZone;
		  // if (hasRightDeadZone) { needContainerTransform = true; } // *?
		  if (bpChanged) { events.emit('newBreakpointStart', info(e)); }
		}
	
		var indChanged,
			itemsChanged,
			itemsTem = items,
			disableTem = disable,
			freezeTem = freeze,
			arrowKeysTem = arrowKeys,
			controlsTem = controls,
			navTem = nav,
			touchTem = touch,
			mouseDragTem = mouseDrag,
			autoplayTem = autoplay,
			autoplayHoverPauseTem = autoplayHoverPause,
			autoplayResetOnVisibilityTem = autoplayResetOnVisibility,
			indexTem = index;
	
		if (bpChanged) {
		  var fixedWidthTem = fixedWidth,
			  autoHeightTem = autoHeight,
			  controlsTextTem = controlsText,
			  centerTem = center,
			  autoplayTextTem = autoplayText;
	
		  if (!CSSMQ) {
			var gutterTem = gutter,
				edgePaddingTem = edgePadding;
		  }
		}
	
		// get option:
		// fixed width: viewport, fixedWidth, gutter => items
		// others: window width => all variables
		// all: items => slideBy
		arrowKeys = getOption('arrowKeys');
		controls = getOption('controls');
		nav = getOption('nav');
		touch = getOption('touch');
		center = getOption('center');
		mouseDrag = getOption('mouseDrag');
		autoplay = getOption('autoplay');
		autoplayHoverPause = getOption('autoplayHoverPause');
		autoplayResetOnVisibility = getOption('autoplayResetOnVisibility');
	
		if (bpChanged) {
		  disable = getOption('disable');
		  fixedWidth = getOption('fixedWidth');
		  speed = getOption('speed');
		  autoHeight = getOption('autoHeight');
		  controlsText = getOption('controlsText');
		  autoplayText = getOption('autoplayText');
		  autoplayTimeout = getOption('autoplayTimeout');
	
		  if (!CSSMQ) {
			edgePadding = getOption('edgePadding');
			gutter = getOption('gutter');
		  }
		}
		// update options
		resetVariblesWhenDisable(disable);
	
		viewport = getViewportWidth(); // <= edgePadding, gutter
		if ((!horizontal || autoWidth) && !disable) {
		  setSlidePositions();
		  if (!horizontal) {
			updateContentWrapperHeight(); // <= setSlidePositions
			needContainerTransform = true;
		  }
		}
		if (fixedWidth || autoWidth) {
		  rightBoundary = getRightBoundary(); // autoWidth: <= viewport, slidePositions, gutter
											  // fixedWidth: <= viewport, fixedWidth, gutter
		  indexMax = getIndexMax(); // autoWidth: <= rightBoundary, slidePositions
									// fixedWidth: <= rightBoundary, fixedWidth, gutter
		}
	
		if (bpChanged || fixedWidth) {
		  items = getOption('items');
		  slideBy = getOption('slideBy');
		  itemsChanged = items !== itemsTem;
	
		  if (itemsChanged) {
			if (!fixedWidth && !autoWidth) { indexMax = getIndexMax(); } // <= items
			// check index before transform in case
			// slider reach the right edge then items become bigger
			updateIndex();
		  }
		}
	
		if (bpChanged) {
		  if (disable !== disableTem) {
			if (disable) {
			  disableSlider();
			} else {
			  enableSlider(); // <= slidePositions, rightBoundary, indexMax
			}
		  }
		}
	
		if (freezable && (bpChanged || fixedWidth || autoWidth)) {
		  freeze = getFreeze(); // <= autoWidth: slidePositions, gutter, viewport, rightBoundary
								// <= fixedWidth: fixedWidth, gutter, rightBoundary
								// <= others: items
	
		  if (freeze !== freezeTem) {
			if (freeze) {
			  doContainerTransform(getContainerTransformValue(getStartIndex(0)));
			  freezeSlider();
			} else {
			  unfreezeSlider();
			  needContainerTransform = true;
			}
		  }
		}
	
		resetVariblesWhenDisable(disable || freeze); // controls, nav, touch, mouseDrag, arrowKeys, autoplay, autoplayHoverPause, autoplayResetOnVisibility
		if (!autoplay) { autoplayHoverPause = autoplayResetOnVisibility = false; }
	
		if (arrowKeys !== arrowKeysTem) {
		  arrowKeys ?
			addEvents(doc, docmentKeydownEvent) :
			removeEvents(doc, docmentKeydownEvent);
		}
		if (controls !== controlsTem) {
		  if (controls) {
			if (controlsContainer) {
			  showElement(controlsContainer);
			} else {
			  if (prevButton) { showElement(prevButton); }
			  if (nextButton) { showElement(nextButton); }
			}
		  } else {
			if (controlsContainer) {
			  hideElement(controlsContainer);
			} else {
			  if (prevButton) { hideElement(prevButton); }
			  if (nextButton) { hideElement(nextButton); }
			}
		  }
		}
		if (nav !== navTem) {
		  nav ?
			showElement(navContainer) :
			hideElement(navContainer);
		}
		if (touch !== touchTem) {
		  touch ?
			addEvents(container, touchEvents, options.preventScrollOnTouch) :
			removeEvents(container, touchEvents);
		}
		if (mouseDrag !== mouseDragTem) {
		  mouseDrag ?
			addEvents(container, dragEvents) :
			removeEvents(container, dragEvents);
		}
		if (autoplay !== autoplayTem) {
		  if (autoplay) {
			if (autoplayButton) { showElement(autoplayButton); }
			if (!animating && !autoplayUserPaused) { startAutoplay(); }
		  } else {
			if (autoplayButton) { hideElement(autoplayButton); }
			if (animating) { stopAutoplay(); }
		  }
		}
		if (autoplayHoverPause !== autoplayHoverPauseTem) {
		  autoplayHoverPause ?
			addEvents(container, hoverEvents) :
			removeEvents(container, hoverEvents);
		}
		if (autoplayResetOnVisibility !== autoplayResetOnVisibilityTem) {
		  autoplayResetOnVisibility ?
			addEvents(doc, visibilityEvent) :
			removeEvents(doc, visibilityEvent);
		}
	
		if (bpChanged) {
		  if (fixedWidth !== fixedWidthTem || center !== centerTem) { needContainerTransform = true; }
	
		  if (autoHeight !== autoHeightTem) {
			if (!autoHeight) { innerWrapper.style.height = ''; }
		  }
	
		  if (controls && controlsText !== controlsTextTem) {
			prevButton.innerHTML = controlsText[0];
			nextButton.innerHTML = controlsText[1];
		  }
	
		  if (autoplayButton && autoplayText !== autoplayTextTem) {
			var i = autoplay ? 1 : 0,
				html = autoplayButton.innerHTML,
				len = html.length - autoplayTextTem[i].length;
			if (html.substring(len) === autoplayTextTem[i]) {
			  autoplayButton.innerHTML = html.substring(0, len) + autoplayText[i];
			}
		  }
		} else {
		  if (center && (fixedWidth || autoWidth)) { needContainerTransform = true; }
		}
	
		if (itemsChanged || fixedWidth && !autoWidth) {
		  pages = getPages();
		  updateNavVisibility();
		}
	
		indChanged = index !== indexTem;
		if (indChanged) {
		  events.emit('indexChanged', info());
		  needContainerTransform = true;
		} else if (itemsChanged) {
		  if (!indChanged) { additionalUpdates(); }
		} else if (fixedWidth || autoWidth) {
		  doLazyLoad();
		  updateSlideStatus();
		  updateLiveRegion();
		}
	
		if (itemsChanged && !carousel) { updateGallerySlidePositions(); }
	
		if (!disable && !freeze) {
		  // non-mediaqueries: IE8
		  if (bpChanged && !CSSMQ) {
			// middle wrapper styles
	
			// inner wrapper styles
			if (edgePadding !== edgePaddingTem || gutter !== gutterTem) {
			  innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, gutter, fixedWidth, speed, autoHeight);
			}
	
			if (horizontal) {
			  // container styles
			  if (carousel) {
				container.style.width = getContainerWidth(fixedWidth, gutter, items);
			  }
	
			  // slide styles
			  var str = getSlideWidthStyle(fixedWidth, gutter, items) +
						getSlideGutterStyle(gutter);
	
			  // remove the last line and
			  // add new styles
			  removeCSSRule(sheet, getCssRulesLength(sheet) - 1);
			  addCSSRule(sheet, '#' + slideId + ' > .tns-item', str, getCssRulesLength(sheet));
			}
		  }
	
		  // auto height
		  if (autoHeight) { doAutoHeight(); }
	
		  if (needContainerTransform) {
			doContainerTransformSilent();
			indexCached = index;
		  }
		}
	
		if (bpChanged) { events.emit('newBreakpointEnd', info(e)); }
	  }
	
	
	
	
	
	  // === INITIALIZATION FUNCTIONS === //
	  function getFreeze () {
		if (!fixedWidth && !autoWidth) {
		  var a = center ? items - (items - 1) / 2 : items;
		  return  slideCount <= a;
		}
	
		var width = fixedWidth ? (fixedWidth + gutter) * slideCount : slidePositions[slideCount],
			vp = edgePadding ? viewport + edgePadding * 2 : viewport + gutter;
	
		if (center) {
		  vp -= fixedWidth ? (viewport - fixedWidth) / 2 : (viewport - (slidePositions[index + 1] - slidePositions[index] - gutter)) / 2;
		}
	
		return width <= vp;
	  }
	
	  function setBreakpointZone () {
		breakpointZone = 0;
		for (var bp in responsive) {
		  bp = parseInt(bp); // convert string to number
		  if (windowWidth >= bp) { breakpointZone = bp; }
		}
	  }
	
	  // (slideBy, indexMin, indexMax) => index
	  var updateIndex = (function () {
		return loop ?
		  carousel ?
			// loop + carousel
			function () {
			  var leftEdge = indexMin,
				  rightEdge = indexMax;
	
			  leftEdge += slideBy;
			  rightEdge -= slideBy;
	
			  // adjust edges when has edge paddings
			  // or fixed-width slider with extra space on the right side
			  if (edgePadding) {
				leftEdge += 1;
				rightEdge -= 1;
			  } else if (fixedWidth) {
				if ((viewport + gutter)%(fixedWidth + gutter)) { rightEdge -= 1; }
			  }
	
			  if (cloneCount) {
				if (index > rightEdge) {
				  index -= slideCount;
				} else if (index < leftEdge) {
				  index += slideCount;
				}
			  }
			} :
			// loop + gallery
			function() {
			  if (index > indexMax) {
				while (index >= indexMin + slideCount) { index -= slideCount; }
			  } else if (index < indexMin) {
				while (index <= indexMax - slideCount) { index += slideCount; }
			  }
			} :
		  // non-loop
		  function() {
			index = Math.max(indexMin, Math.min(indexMax, index));
		  };
	  })();
	
	  function disableUI () {
		if (!autoplay && autoplayButton) { hideElement(autoplayButton); }
		if (!nav && navContainer) { hideElement(navContainer); }
		if (!controls) {
		  if (controlsContainer) {
			hideElement(controlsContainer);
		  } else {
			if (prevButton) { hideElement(prevButton); }
			if (nextButton) { hideElement(nextButton); }
		  }
		}
	  }
	
	  function enableUI () {
		if (autoplay && autoplayButton) { showElement(autoplayButton); }
		if (nav && navContainer) { showElement(navContainer); }
		if (controls) {
		  if (controlsContainer) {
			showElement(controlsContainer);
		  } else {
			if (prevButton) { showElement(prevButton); }
			if (nextButton) { showElement(nextButton); }
		  }
		}
	  }
	
	  function freezeSlider () {
		if (frozen) { return; }
	
		// remove edge padding from inner wrapper
		if (edgePadding) { innerWrapper.style.margin = '0px'; }
	
		// add class tns-transparent to cloned slides
		if (cloneCount) {
		  var str = 'tns-transparent';
		  for (var i = cloneCount; i--;) {
			if (carousel) { addClass(slideItems[i], str); }
			addClass(slideItems[slideCountNew - i - 1], str);
		  }
		}
	
		// update tools
		disableUI();
	
		frozen = true;
	  }
	
	  function unfreezeSlider () {
		if (!frozen) { return; }
	
		// restore edge padding for inner wrapper
		// for mordern browsers
		if (edgePadding && CSSMQ) { innerWrapper.style.margin = ''; }
	
		// remove class tns-transparent to cloned slides
		if (cloneCount) {
		  var str = 'tns-transparent';
		  for (var i = cloneCount; i--;) {
			if (carousel) { removeClass(slideItems[i], str); }
			removeClass(slideItems[slideCountNew - i - 1], str);
		  }
		}
	
		// update tools
		enableUI();
	
		frozen = false;
	  }
	
	  function disableSlider () {
		if (disabled) { return; }
	
		sheet.disabled = true;
		container.className = container.className.replace(newContainerClasses.substring(1), '');
		removeAttrs(container, ['style']);
		if (loop) {
		  for (var j = cloneCount; j--;) {
			if (carousel) { hideElement(slideItems[j]); }
			hideElement(slideItems[slideCountNew - j - 1]);
		  }
		}
	
		// vertical slider
		if (!horizontal || !carousel) { removeAttrs(innerWrapper, ['style']); }
	
		// gallery
		if (!carousel) {
		  for (var i = index, l = index + slideCount; i < l; i++) {
			var item = slideItems[i];
			removeAttrs(item, ['style']);
			removeClass(item, animateIn);
			removeClass(item, animateNormal);
		  }
		}
	
		// update tools
		disableUI();
	
		disabled = true;
	  }
	
	  function enableSlider () {
		if (!disabled) { return; }
	
		sheet.disabled = false;
		container.className += newContainerClasses;
		doContainerTransformSilent();
	
		if (loop) {
		  for (var j = cloneCount; j--;) {
			if (carousel) { showElement(slideItems[j]); }
			showElement(slideItems[slideCountNew - j - 1]);
		  }
		}
	
		// gallery
		if (!carousel) {
		  for (var i = index, l = index + slideCount; i < l; i++) {
			var item = slideItems[i],
				classN = i < index + items ? animateIn : animateNormal;
			item.style.left = (i - index) * 100 / items + '%';
			addClass(item, classN);
		  }
		}
	
		// update tools
		enableUI();
	
		disabled = false;
	  }
	
	  function updateLiveRegion () {
		var str = getLiveRegionStr();
		if (liveregionCurrent.innerHTML !== str) { liveregionCurrent.innerHTML = str; }
	  }
	
	  function getLiveRegionStr () {
		var arr = getVisibleSlideRange(),
			start = arr[0] + 1,
			end = arr[1] + 1;
		return start === end ? start + '' : start + ' to ' + end;
	  }
	
	  function getVisibleSlideRange (val) {
		if (val == null) { val = getContainerTransformValue(); }
		var start = index, end, rangestart, rangeend;
	
		// get range start, range end for autoWidth and fixedWidth
		if (center || edgePadding) {
		  if (autoWidth || fixedWidth) {
			rangestart = - (parseFloat(val) + edgePadding);
			rangeend = rangestart + viewport + edgePadding * 2;
		  }
		} else {
		  if (autoWidth) {
			rangestart = slidePositions[index];
			rangeend = rangestart + viewport;
		  }
		}
	
		// get start, end
		// - check auto width
		if (autoWidth) {
		  slidePositions.forEach(function(point, i) {
			if (i < slideCountNew) {
			  if ((center || edgePadding) && point <= rangestart + 0.5) { start = i; }
			  if (rangeend - point >= 0.5) { end = i; }
			}
		  });
	
		// - check percentage width, fixed width
		} else {
	
		  if (fixedWidth) {
			var cell = fixedWidth + gutter;
			if (center || edgePadding) {
			  start = Math.floor(rangestart/cell);
			  end = Math.ceil(rangeend/cell - 1);
			} else {
			  end = start + Math.ceil(viewport/cell) - 1;
			}
	
		  } else {
			if (center || edgePadding) {
			  var a = items - 1;
			  if (center) {
				start -= a / 2;
				end = index + a / 2;
			  } else {
				end = index + a;
			  }
	
			  if (edgePadding) {
				var b = edgePadding * items / viewport;
				start -= b;
				end += b;
			  }
	
			  start = Math.floor(start);
			  end = Math.ceil(end);
			} else {
			  end = start + items - 1;
			}
		  }
	
		  start = Math.max(start, 0);
		  end = Math.min(end, slideCountNew - 1);
		}
	
		return [start, end];
	  }
	
	  function doLazyLoad () {
		if (lazyload && !disable) {
		  var arg = getVisibleSlideRange();
		  arg.push(lazyloadSelector);
	
		  getImageArray.apply(null, arg).forEach(function (img) {
			if (!hasClass(img, imgCompleteClass)) {
			  // stop propagation transitionend event to container
			  var eve = {};
			  eve[TRANSITIONEND] = function (e) { e.stopPropagation(); };
			  addEvents(img, eve);
	
			  addEvents(img, imgEvents);
	
			  // update src
			  img.src = getAttr(img, 'data-src');
	
			  // update srcset
			  var srcset = getAttr(img, 'data-srcset');
			  if (srcset) { img.srcset = srcset; }
	
			  addClass(img, 'loading');
			}
		  });
		}
	  }
	
	  function onImgLoaded (e) {
		imgLoaded(getTarget(e));
	  }
	
	  function onImgFailed (e) {
		imgFailed(getTarget(e));
	  }
	
	  function imgLoaded (img) {
		addClass(img, 'loaded');
		imgCompleted(img);
	  }
	
	  function imgFailed (img) {
		addClass(img, 'failed');
		imgCompleted(img);
	  }
	
	  function imgCompleted (img) {
		addClass(img, imgCompleteClass);
		removeClass(img, 'loading');
		removeEvents(img, imgEvents);
	  }
	
	  function getImageArray (start, end, imgSelector) {
		var imgs = [];
		if (!imgSelector) { imgSelector = 'img'; }
	
		while (start <= end) {
		  forEach(slideItems[start].querySelectorAll(imgSelector), function (img) { imgs.push(img); });
		  start++;
		}
	
		return imgs;
	  }
	
	  // check if all visible images are loaded
	  // and update container height if it's done
	  function doAutoHeight () {
		var imgs = getImageArray.apply(null, getVisibleSlideRange());
		raf(function(){ imgsLoadedCheck(imgs, updateInnerWrapperHeight); });
	  }
	
	  function imgsLoadedCheck (imgs, cb) {
		// execute callback function if all images are complete
		if (imgsComplete) { return cb(); }
	
		// check image classes
		imgs.forEach(function (img, index) {
		  if (!lazyload && img.complete) { imgCompleted(img); } // Check image.complete
		  if (hasClass(img, imgCompleteClass)) { imgs.splice(index, 1); }
		});
	
		// execute callback function if selected images are all complete
		if (!imgs.length) { return cb(); }
	
		// otherwise execute this functiona again
		raf(function(){ imgsLoadedCheck(imgs, cb); });
	  }
	
	  function additionalUpdates () {
		doLazyLoad();
		updateSlideStatus();
		updateLiveRegion();
		updateControlsStatus();
		updateNavStatus();
	  }
	
	
	  function update_carousel_transition_duration () {
		if (carousel && autoHeight) {
		  middleWrapper.style[TRANSITIONDURATION] = speed / 1000 + 's';
		}
	  }
	
	  function getMaxSlideHeight (slideStart, slideRange) {
		var heights = [];
		for (var i = slideStart, l = Math.min(slideStart + slideRange, slideCountNew); i < l; i++) {
		  heights.push(slideItems[i].offsetHeight);
		}
	
		return Math.max.apply(null, heights);
	  }
	
	  // update inner wrapper height
	  // 1. get the max-height of the visible slides
	  // 2. set transitionDuration to speed
	  // 3. update inner wrapper height to max-height
	  // 4. set transitionDuration to 0s after transition done
	  function updateInnerWrapperHeight () {
		var maxHeight = autoHeight ? getMaxSlideHeight(index, items) : getMaxSlideHeight(cloneCount, slideCount),
			wp = middleWrapper ? middleWrapper : innerWrapper;
	
		if (wp.style.height !== maxHeight) { wp.style.height = maxHeight + 'px'; }
	  }
	
	  // get the distance from the top edge of the first slide to each slide
	  // (init) => slidePositions
	  function setSlidePositions () {
		slidePositions = [0];
		var attr = horizontal ? 'left' : 'top',
			attr2 = horizontal ? 'right' : 'bottom',
			base = slideItems[0].getBoundingClientRect()[attr];
	
		forEach(slideItems, function(item, i) {
		  // skip the first slide
		  if (i) { slidePositions.push(item.getBoundingClientRect()[attr] - base); }
		  // add the end edge
		  if (i === slideCountNew - 1) { slidePositions.push(item.getBoundingClientRect()[attr2] - base); }
		});
	  }
	
	  // update slide
	  function updateSlideStatus () {
		var range = getVisibleSlideRange(),
			start = range[0],
			end = range[1];
	
		forEach(slideItems, function(item, i) {
		  // show slides
		  if (i >= start && i <= end) {
			if (hasAttr(item, 'aria-hidden')) {
			  removeAttrs(item, ['aria-hidden', 'tabindex']);
			  addClass(item, slideActiveClass);
			  removeInnerAttrs( item, ['tabindex'] );
			}
		  // hide slides
		  } else {
			if (!hasAttr(item, 'aria-hidden')) {
			  setAttrs(item, {
				'aria-hidden': 'true',
				'tabindex': '-1'
			  });
			  setInnerAttrs( item, {
				'tabindex': '-1'
			  } );
			  removeClass(item, slideActiveClass);
			}
		  }
		});
	  }
	
	  // gallery: update slide position
	  function updateGallerySlidePositions () {
		var l = index + Math.min(slideCount, items);
		for (var i = slideCountNew; i--;) {
		  var item = slideItems[i];
	
		  if (i >= index && i < l) {
			// add transitions to visible slides when adjusting their positions
			addClass(item, 'tns-moving');
	
			item.style.left = (i - index) * 100 / items + '%';
			addClass(item, animateIn);
			removeClass(item, animateNormal);
		  } else if (item.style.left) {
			item.style.left = '';
			addClass(item, animateNormal);
			removeClass(item, animateIn);
		  }
	
		  // remove outlet animation
		  removeClass(item, animateOut);
		}
	
		// removing '.tns-moving'
		setTimeout(function() {
		  forEach(slideItems, function(el) {
			removeClass(el, 'tns-moving');
		  });
		}, 300);
	  }
	
	  // set tabindex on Nav
	  function updateNavStatus () {
		// get current nav
		if (nav) {
		  navCurrentIndex = navClicked >= 0 ? navClicked : getCurrentNavIndex();
		  navClicked = -1;
	
		  if (navCurrentIndex !== navCurrentIndexCached) {
			var navPrev = navItems[navCurrentIndexCached],
				navCurrent = navItems[navCurrentIndex];
	
			setAttrs(navPrev, {
			  'tabindex': '-1',
			  'aria-label': navStr + (navCurrentIndexCached + 1)
			});
			setInnerAttrs(navPrev, {
			'tabindex': '-1',
			});
			removeClass(navPrev, navActiveClass);
	
			setAttrs(navCurrent, {'aria-label': navStr + (navCurrentIndex + 1) + navStrCurrent});
			removeAttrs(navCurrent, 'tabindex');
			removeInnerAttrs(navCurrent, 'tabindex');
			addClass(navCurrent, navActiveClass);
	
			navCurrentIndexCached = navCurrentIndex;
		  }
		}
	  }
	
	  function getLowerCaseNodeName (el) {
		return el.nodeName.toLowerCase();
	  }
	
	  function isButton (el) {
		return getLowerCaseNodeName(el) === 'button';
	  }
	
	  function isAriaDisabled (el) {
		return el.getAttribute('aria-disabled') === 'true';
	  }
	
	  function disEnableElement (isButton, el, val) {
		if (isButton) {
		  el.disabled = val;
		} else {
		  el.setAttribute('aria-disabled', val.toString());
		}
	  }
	
	  // set 'disabled' to true on controls when reach the edges
	  function updateControlsStatus () {
		if (!controls || rewind || loop) { return; }
	
		var prevDisabled = (prevIsButton) ? prevButton.disabled : isAriaDisabled(prevButton),
			nextDisabled = (nextIsButton) ? nextButton.disabled : isAriaDisabled(nextButton),
			disablePrev = (index <= indexMin) ? true : false,
			disableNext = (!rewind && index >= indexMax) ? true : false;
	
		if (disablePrev && !prevDisabled) {
		  disEnableElement(prevIsButton, prevButton, true);
		}
		if (!disablePrev && prevDisabled) {
		  disEnableElement(prevIsButton, prevButton, false);
		}
		if (disableNext && !nextDisabled) {
		  disEnableElement(nextIsButton, nextButton, true);
		}
		if (!disableNext && nextDisabled) {
		  disEnableElement(nextIsButton, nextButton, false);
		}
	  }
	
	  // set duration
	  function resetDuration (el, str) {
		if (TRANSITIONDURATION) { el.style[TRANSITIONDURATION] = str; }
	  }
	
	  function getSliderWidth () {
		return fixedWidth ? (fixedWidth + gutter) * slideCountNew : slidePositions[slideCountNew];
	  }
	
	  function getCenterGap (num) {
		if (num == null) { num = index; }
	
		var gap = edgePadding ? gutter : 0;
		return autoWidth ? ((viewport - gap) - (slidePositions[num + 1] - slidePositions[num] - gutter))/2 :
		  fixedWidth ? (viewport - fixedWidth) / 2 :
			(items - 1) / 2;
	  }
	
	  function getRightBoundary () {
		var gap = edgePadding ? gutter : 0,
			result = (viewport + gap) - getSliderWidth();
	
		if (center && !loop) {
		  result = fixedWidth ? - (fixedWidth + gutter) * (slideCountNew - 1) - getCenterGap() :
			getCenterGap(slideCountNew - 1) - slidePositions[slideCountNew - 1];
		}
		if (result > 0) { result = 0; }
	
		return result;
	  }
	
	  function getContainerTransformValue (num) {
		if (num == null) { num = index; }
	
		var val;
		if (horizontal && !autoWidth) {
		  if (fixedWidth) {
			val = - (fixedWidth + gutter) * num;
			if (center) { val += getCenterGap(); }
		  } else {
			var denominator = TRANSFORM ? slideCountNew : items;
			if (center) { num -= getCenterGap(); }
			val = - num * 100 / denominator;
		  }
		} else {
		  val = - slidePositions[num];
		  if (center && autoWidth) {
			val += getCenterGap();
		  }
		}
	
		if (hasRightDeadZone) { val = Math.max(val, rightBoundary); }
	
		val += (horizontal && !autoWidth && !fixedWidth) ? '%' : 'px';
	
		return val;
	  }
	
	  function doContainerTransformSilent (val) {
		resetDuration(container, '0s');
		doContainerTransform(val);
	  }
	
	  function doContainerTransform (val) {
		if (val == null) { val = getContainerTransformValue(); }
		if (textDirection === 'rtl' && val.charAt(0) === '-') {
			val = val.substr(1)
		}
		container.style[transformAttr] = transformPrefix + val + transformPostfix;
	  }
	
	  function animateSlide (number, classOut, classIn, isOut) {
		var l = number + items;
		if (!loop) { l = Math.min(l, slideCountNew); }
	
		for (var i = number; i < l; i++) {
			var item = slideItems[i];
	
		  // set item positions
		  if (!isOut) { item.style.left = (i - index) * 100 / items + '%'; }
	
		  if (animateDelay && TRANSITIONDELAY) {
			item.style[TRANSITIONDELAY] = item.style[ANIMATIONDELAY] = animateDelay * (i - number) / 1000 + 's';
		  }
		  removeClass(item, classOut);
		  addClass(item, classIn);
	
		  if (isOut) { slideItemsOut.push(item); }
		}
	  }
	
	  // make transfer after click/drag:
	  // 1. change 'transform' property for mordern browsers
	  // 2. change 'left' property for legacy browsers
	  var transformCore = (function () {
		return carousel ?
		  function () {
			resetDuration(container, '');
			if (TRANSITIONDURATION || !speed) {
			  // for morden browsers with non-zero duration or
			  // zero duration for all browsers
			  doContainerTransform();
			  // run fallback function manually
			  // when duration is 0 / container is hidden
			  if (!speed || !isVisible(container)) { onTransitionEnd(); }
	
			} else {
			  // for old browser with non-zero duration
			  jsTransform(container, transformAttr, transformPrefix, transformPostfix, getContainerTransformValue(), speed, onTransitionEnd);
			}
	
			if (!horizontal) { updateContentWrapperHeight(); }
		  } :
		  function () {
			slideItemsOut = [];
	
			var eve = {};
			eve[TRANSITIONEND] = eve[ANIMATIONEND] = onTransitionEnd;
			removeEvents(slideItems[indexCached], eve);
			addEvents(slideItems[index], eve);
	
			animateSlide(indexCached, animateIn, animateOut, true);
			animateSlide(index, animateNormal, animateIn);
	
			// run fallback function manually
			// when transition or animation not supported / duration is 0
			if (!TRANSITIONEND || !ANIMATIONEND || !speed || !isVisible(container)) { onTransitionEnd(); }
		  };
	  })();
	
	  function render (e, sliderMoved) {
		if (updateIndexBeforeTransform) { updateIndex(); }
	
		// render when slider was moved (touch or drag) even though index may not change
		if (index !== indexCached || sliderMoved) {
		  // events
		  events.emit('indexChanged', info());
		  events.emit('transitionStart', info());
		  if (autoHeight) { doAutoHeight(); }
	
		  // pause autoplay when click or keydown from user
		  if (animating && e && ['click', 'keydown'].indexOf(e.type) >= 0) { stopAutoplay(); }
		  running = true;
		  transformCore();
		}
	  }
	
	  /*
	   * Transfer prefixed properties to the same format
	   * CSS: -Webkit-Transform => webkittransform
	   * JS: WebkitTransform => webkittransform
	   * @param {string} str - property
	   *
	   */
	  function strTrans (str) {
		return str.toLowerCase().replace(/-/g, '');
	  }
	
	  // AFTER TRANSFORM
	  // Things need to be done after a transfer:
	  // 1. check index
	  // 2. add classes to visible slide
	  // 3. disable controls buttons when reach the first/last slide in non-loop slider
	  // 4. update nav status
	  // 5. lazyload images
	  // 6. update container height
	  function onTransitionEnd (event) {
		// check running on gallery mode
		// make sure trantionend/animationend events run only once
		if (carousel || running) {
		  events.emit('transitionEnd', info(event));
	
		  if (!carousel && slideItemsOut.length > 0) {
			for (var i = 0; i < slideItemsOut.length; i++) {
			  var item = slideItemsOut[i];
			  // set item positions
			  item.style.left = '';
	
			  if (ANIMATIONDELAY && TRANSITIONDELAY) {
				item.style[ANIMATIONDELAY] = '';
				item.style[TRANSITIONDELAY] = '';
			  }
			  removeClass(item, animateOut);
			  addClass(item, animateNormal);
			}
		  }
	
		  /* update slides, nav, controls after checking ...
		   * => legacy browsers who don't support 'event'
		   *    have to check event first, otherwise event.target will cause an error
		   * => or 'gallery' mode:
		   *   + event target is slide item
		   * => or 'carousel' mode:
		   *   + event target is container,
		   *   + event.property is the same with transform attribute
		   */
		  if (!event ||
			  !carousel && event.target.parentNode === container ||
			  event.target === container && strTrans(event.propertyName) === strTrans(transformAttr)) {
	
			if (!updateIndexBeforeTransform) {
			  var indexTem = index;
			  updateIndex();
			  if (index !== indexTem) {
				events.emit('indexChanged', info());
	
				doContainerTransformSilent();
			  }
			}
	
			if (nested === 'inner') { events.emit('innerLoaded', info()); }
			running = false;
			indexCached = index;
		  }
		}
	
	  }
	
	  // # ACTIONS
	  function goTo (targetIndex, e) {
		if (freeze) { return; }
	
		// prev slideBy
		if (targetIndex === 'prev') {
		  onControlsClick(e, -1);
	
		// next slideBy
		} else if (targetIndex === 'next') {
		  onControlsClick(e, 1);
	
		// go to exact slide
		} else {
		  if (running) {
			if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
		  }
	
		  var absIndex = getAbsIndex(),
			  indexGap = 0;
	
		  if (targetIndex === 'first') {
			indexGap = - absIndex;
		  } else if (targetIndex === 'last') {
			indexGap = carousel ? slideCount - items - absIndex : slideCount - 1 - absIndex;
		  } else {
			if (typeof targetIndex !== 'number') { targetIndex = parseInt(targetIndex); }
	
			if (!isNaN(targetIndex)) {
			  // from directly called goTo function
			  if (!e) { targetIndex = Math.max(0, Math.min(slideCount - 1, targetIndex)); }
	
			  indexGap = targetIndex - absIndex;
			}
		  }
	
		  // gallery: make sure new page won't overlap with current page
		  if (!carousel && indexGap && Math.abs(indexGap) < items) {
			var factor = indexGap > 0 ? 1 : -1;
			indexGap += (index + indexGap - slideCount) >= indexMin ? slideCount * factor : slideCount * 2 * factor * -1;
		  }
	
		  index += indexGap;
	
		  // make sure index is in range
		  if (carousel && loop) {
			if (index < indexMin) { index += slideCount; }
			if (index > indexMax) { index -= slideCount; }
		  }
	
		  // if index is changed, start rendering
		  if (getAbsIndex(index) !== getAbsIndex(indexCached)) {
			render(e);
		  }
	
		}
	  }
	
	  // on controls click
	  function onControlsClick (e, dir) {
		if (running) {
		  if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
		}
		var passEventObject;
	
		if (!dir) {
		  e = getEvent(e);
		  var target = getTarget(e);
	
		  while (target !== controlsContainer && [prevButton, nextButton].indexOf(target) < 0) { target = target.parentNode; }
	
		  var targetIn = [prevButton, nextButton].indexOf(target);
		  if (targetIn >= 0) {
			passEventObject = true;
			dir = targetIn === 0 ? -1 : 1;
		  }
		}
	
		if (rewind) {
		  if (index === indexMin && dir === -1) {
			goTo('last', e);
			return;
		  } else if (index === indexMax && dir === 1) {
			goTo('first', e);
			return;
		  }
		}
	
		if (dir) {
		  index += slideBy * dir;
		  if (autoWidth) { index = Math.floor(index); }
		  // pass e when click control buttons or keydown
		  render((passEventObject || (e && e.type === 'keydown')) ? e : null);
		}
	  }
	
	  // on nav click
	  function onNavClick (e) {
		if (running) {
		  if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
		}
	
		e = getEvent(e);
		var target = getTarget(e), navIndex;
	
		// find the clicked nav item
		while (target !== navContainer && !hasAttr(target, 'data-nav')) { target = target.parentNode; }
		if (hasAttr(target, 'data-nav')) {
		  var navIndex = navClicked = Number(getAttr(target, 'data-nav')),
			  targetIndexBase = fixedWidth || autoWidth ? navIndex * slideCount / pages : navIndex * items,
			  targetIndex = navAsThumbnails ? navIndex : Math.min(Math.ceil(targetIndexBase), slideCount - 1);
		  goTo(targetIndex, e);
	
		  if (navCurrentIndex === navIndex) {
			if (animating) { stopAutoplay(); }
			navClicked = -1; // reset navClicked
		  }
		}
	  }
	
	  // autoplay functions
	  function setAutoplayTimer () {
		autoplayTimer = setInterval(function () {
		  onControlsClick(null, autoplayDirection);
		}, autoplayTimeout);
	
		animating = true;
	  }
	
	  function stopAutoplayTimer () {
		clearInterval(autoplayTimer);
		animating = false;
	  }
	
	  function updateAutoplayButton (action, txt) {
		setAttrs(autoplayButton, {'data-action': action});
		autoplayButton.innerHTML = autoplayHtmlStrings[0] + action + autoplayHtmlStrings[1] + txt;
	  }
	
	  function startAutoplay () {
		setAutoplayTimer();
		if (autoplayButton) { updateAutoplayButton('stop', autoplayText[1]); }
	  }
	
	  function stopAutoplay () {
		stopAutoplayTimer();
		if (autoplayButton) { updateAutoplayButton('start', autoplayText[0]); }
	  }
	
	  // programaitcally play/pause the slider
	  function play () {
		if (autoplay && !animating) {
		  startAutoplay();
		  autoplayUserPaused = false;
		}
	  }
	  function pause () {
		if (animating) {
		  stopAutoplay();
		  autoplayUserPaused = true;
		}
	  }
	
	  function toggleAutoplay () {
		if (animating) {
		  stopAutoplay();
		  autoplayUserPaused = true;
		} else {
		  startAutoplay();
		  autoplayUserPaused = false;
		}
	  }
	
	  function onVisibilityChange () {
		if (doc.hidden) {
		  if (animating) {
			stopAutoplayTimer();
			autoplayVisibilityPaused = true;
		  }
		} else if (autoplayVisibilityPaused) {
		  setAutoplayTimer();
		  autoplayVisibilityPaused = false;
		}
	  }
	
	  function mouseoverPause () {
		if (animating) {
		  stopAutoplayTimer();
		  autoplayHoverPaused = true;
		}
	  }
	
	  function mouseoutRestart () {
		if (autoplayHoverPaused) {
		  setAutoplayTimer();
		  autoplayHoverPaused = false;
		}
	  }
	
	  // keydown events on document
	  function onDocumentKeydown (e) {
		e = getEvent(e);
		var keyIndex = [KEYS.LEFT, KEYS.RIGHT].indexOf(e.keyCode);
	
		if (keyIndex >= 0) {
		  onControlsClick(e, keyIndex === 0 ? -1 : 1);
		}
	  }
	
	  // on key control
	  function onControlsKeydown (e) {
		e = getEvent(e);
		var keyIndex = [KEYS.LEFT, KEYS.RIGHT].indexOf(e.keyCode);
	
		if (keyIndex >= 0) {
		  if (keyIndex === 0) {
			if (!prevButton.disabled) { onControlsClick(e, -1); }
		  } else if (!nextButton.disabled) {
			onControlsClick(e, 1);
		  }
		}
	  }
	
	  // set focus
	  function setFocus (el) {
		el.focus();
	  }
	
	  // on key nav
	  function onNavKeydown (e) {
		e = getEvent(e);
		var curElement = doc.activeElement;
		if (!hasAttr(curElement, 'data-nav')) { return; }
	
		// var code = e.keyCode,
		var keyIndex = [KEYS.LEFT, KEYS.RIGHT, KEYS.ENTER, KEYS.SPACE].indexOf(e.keyCode),
			navIndex = Number(getAttr(curElement, 'data-nav'));
	
		if (keyIndex >= 0) {
		  if (keyIndex === 0) {
			if (navIndex > 0) { setFocus(navItems[navIndex - 1]); }
		  } else if (keyIndex === 1) {
			if (navIndex < pages - 1) { setFocus(navItems[navIndex + 1]); }
		  } else {
			navClicked = navIndex;
			goTo(navIndex, e);
		  }
		}
	  }
	
	  function getEvent (e) {
		e = e || win.event;
		return isTouchEvent(e) ? e.changedTouches[0] : e;
	  }
	  function getTarget (e) {
		return e.target || win.event.srcElement;
	  }
	
	  function isTouchEvent (e) {
		return e.type.indexOf('touch') >= 0;
	  }
	
	  function preventDefaultBehavior (e) {
		e.preventDefault ? e.preventDefault() : e.returnValue = false;
	  }
	
	  function getMoveDirectionExpected () {
		return getTouchDirection(toDegree(lastPosition.y - initPosition.y, lastPosition.x - initPosition.x), swipeAngle) === options.axis;
	  }
	
	  function onPanStart (e) {
		if (running) {
		  if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
		}
	
		if (autoplay && animating) { stopAutoplayTimer(); }
	
		panStart = true;
		if (rafIndex) {
		  caf(rafIndex);
		  rafIndex = null;
		}
	
		var $ = getEvent(e);
		events.emit(isTouchEvent(e) ? 'touchStart' : 'dragStart', info(e));
	
		if (!isTouchEvent(e) && ['img', 'a'].indexOf(getLowerCaseNodeName(getTarget(e))) >= 0) {
		  preventDefaultBehavior(e);
		}
	
		lastPosition.x = initPosition.x = $.clientX;
		lastPosition.y = initPosition.y = $.clientY;
		if (carousel) {
		  translateInit = parseFloat(container.style[transformAttr].replace(transformPrefix, ''));
		  resetDuration(container, '0s');
		}
	  }
	
	  function onPanMove (e) {
		if (panStart) {
		  var $ = getEvent(e);
		  lastPosition.x = $.clientX;
		  lastPosition.y = $.clientY;
	
		  if (carousel) {
			if (!rafIndex) { rafIndex = raf(function(){ panUpdate(e); }); }
		  } else {
			if (moveDirectionExpected === '?') { moveDirectionExpected = getMoveDirectionExpected(); }
			if (moveDirectionExpected) { preventScroll = true; }
		  }
	
		  if ((typeof e.cancelable !== 'boolean' || e.cancelable) && preventScroll) {
			e.preventDefault();
		  }
		}
	  }
	
	  function panUpdate (e) {
		if (!moveDirectionExpected) {
		  panStart = false;
		  return;
		}
		caf(rafIndex);
		if (panStart) { rafIndex = raf(function(){ panUpdate(e); }); }
	
		if (moveDirectionExpected === '?') { moveDirectionExpected = getMoveDirectionExpected(); }
		if (moveDirectionExpected) {
		  if (!preventScroll && isTouchEvent(e)) { preventScroll = true; }
	
		  try {
			if (e.type) { events.emit(isTouchEvent(e) ? 'touchMove' : 'dragMove', info(e)); }
		  } catch(err) {}
	
		  var x = translateInit,
			  dist = getDist(lastPosition, initPosition);
		  if (!horizontal || fixedWidth || autoWidth) {
			x += dist;
			x += 'px';
		  } else {
			var percentageX = TRANSFORM ? dist * items * 100 / ((viewport + gutter) * slideCountNew): dist * 100 / (viewport + gutter);
			x += percentageX;
			x += '%';
		  }
	
		  container.style[transformAttr] = transformPrefix + x + transformPostfix;
		}
	  }
	
	  function onPanEnd (e) {
		if (panStart) {
		  if (rafIndex) {
			caf(rafIndex);
			rafIndex = null;
		  }
		  if (carousel) { resetDuration(container, ''); }
		  panStart = false;
	
		  var $ = getEvent(e);
		  lastPosition.x = $.clientX;
		  lastPosition.y = $.clientY;
		  var dist = getDist(lastPosition, initPosition);

		  if (Math.abs(dist)) {
			// drag vs click
			if (!isTouchEvent(e)) {
			  // prevent "click"
			  var target = getTarget(e);
			  addEvents(target, {'click': function preventClick (e) {
				preventDefaultBehavior(e);
				removeEvents(target, {'click': preventClick});
			  }});
			}
	
			if (carousel) {
			  rafIndex = raf(function() {
				if (horizontal && !autoWidth) {
				  var indexMoved = - dist * items / (viewport + gutter);
				  indexMoved = dist > 0 ? Math.floor(indexMoved) : Math.ceil(indexMoved);
				  index += indexMoved;
				  if (textDirection === 'rtl') { 
					index += indexMoved * -1;
				  }
				} else {
				  var moved = - (translateInit + dist);
				  if (moved <= 0) {
					index = indexMin;
				  } else if (moved >= slidePositions[slideCountNew - 1]) {
					index = indexMax;
				  } else {
					var i = 0;
					while (i < slideCountNew && moved >= slidePositions[i]) {
					  index = i;
					  if (moved > slidePositions[i] && dist < 0) { index += 1; }
					  i++;
					}
				  }
				}
				render(e, dist);
				events.emit(isTouchEvent(e) ? 'touchEnd' : 'dragEnd', info(e));
			  });
			} else {
			  if (moveDirectionExpected) {
				onControlsClick(e, dist > 0 ? -1 : 1);
			  }
			}
		  }
		}
	
		// reset
		if (options.preventScrollOnTouch === 'auto') { preventScroll = false; }
		if (swipeAngle) { moveDirectionExpected = '?'; }
		if (autoplay && !animating) { setAutoplayTimer(); }
	  }
	
	  // === RESIZE FUNCTIONS === //
	  // (slidePositions, index, items) => vertical_conentWrapper.height
	  function updateContentWrapperHeight () {
		var wp = middleWrapper ? middleWrapper : innerWrapper;
		wp.style.height = slidePositions[index + items] - slidePositions[index] + 'px';
	  }
	
	  function getPages () {
		var rough = fixedWidth ? (fixedWidth + gutter) * slideCount / viewport : slideCount / items;
		return Math.min(Math.ceil(rough), slideCount);
	  }
	
	  /*
	   * 1. update visible nav items list
	   * 2. add "hidden" attributes to previous visible nav items
	   * 3. remove "hidden" attrubutes to new visible nav items
	   */
	  function updateNavVisibility () {
		if (!nav || navAsThumbnails) { return; }
	
		if (pages !== pagesCached) {
		  var min = pagesCached,
			  max = pages,
			  fn = showElement;
	
		  if (pagesCached > pages) {
			min = pages;
			max = pagesCached;
			fn = hideElement;
		  }
	
		  while (min < max) {
			fn(navItems[min]);
			min++;
		  }
	
		  // cache pages
		  pagesCached = pages;
		}
	  }
	
	  function info (e) {
		return {
		  container: container,
		  slideItems: slideItems,
		  navContainer: navContainer,
		  navItems: navItems,
		  controlsContainer: controlsContainer,
		  hasControls: hasControls,
		  prevButton: prevButton,
		  nextButton: nextButton,
		  items: items,
		  slideBy: slideBy,
		  cloneCount: cloneCount,
		  slideCount: slideCount,
		  slideCountNew: slideCountNew,
		  index: index,
		  indexCached: indexCached,
		  displayIndex: getCurrentSlide(),
		  navCurrentIndex: navCurrentIndex,
		  navCurrentIndexCached: navCurrentIndexCached,
		  pages: pages,
		  pagesCached: pagesCached,
		  sheet: sheet,
		  isOn: isOn,
		  event: e || {},
		};
	  }
	
	  return {
		version: '2.9.2',
		getInfo: info,
		events: events,
		goTo: goTo,
		play: play,
		pause: pause,
		isOn: isOn,
		updateSliderHeight: updateInnerWrapperHeight,
		refresh: initSliderTransform,
		destroy: destroy,
		rebuild: function() {
		  return tns(extend(options, optionsElements));
		}
	  };
	};
	
	return tns;
	})();