PageSourceSearch

https://trangotech.com/blog/wp-content/themes/trangoblog/assets/js/sly-slider.js

js trangotech.com collected 2026-10-02 14:41:20 UTC 82,194 bytes, 2,819 lines download raw bytes

vendor: 6,366 bytes, lines 1-177
1/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
2 * Build: http://modernizr.com/download/#-csstransforms-csstransforms3d-shiv-cssclasses-prefixed-teststyles-testprop-testallprops-prefixes-domprefixes
3 */
4;window.Modernizr = function(a, b, c) {
5    function z(a) {
6        j.cssText = a
7    }
8    function A(a, b) {
9        return z(m.join(a + ";") + (b || ""))
10    }
11    function B(a, b) {
12        return typeof a === b
13    }
14    function C(a, b) {
15        return !!~("" + a).indexOf(b)
16    }
17    function D(a, b) {
18        for (var d in a) {
19            var e = a[d];
20            if (!C(e, "-") && j[e] !== c)
21                return b == "pfx" ? e : !0
22        }
23        return !1
24    }
25    function E(a, b, d) {
26        for (var e in a) {
27            var f = b[a[e]];
28            if (f !== c)
29                return d === !1 ? a[e] : B(f, "function") ? f.bind(d || b) : f
30        }
31        return !1
32    }
33    function F(a, b, c) {
34        var d = a.charAt(0).toUpperCase() + a.slice(1)
35          , e = (a + " " + o.join(d + " ") + d).split(" ");
36        return B(b, "string") || B(b, "undefined") ? D(e, b) : (e = (a + " " + p.join(d + " ") + d).split(" "),
37        E(e, b, c))
38    }
39    var d = "2.6.2", e = {}, f = !0, g = b.documentElement, h = "modernizr", i = b.createElement(h), j = i.style, k, l = {}.toString, m = " -webkit- -moz- -o- -ms- ".split(" "), n = "Webkit Moz O ms", o = n.split(" "), p = n.toLowerCase().split(" "), q = {}, r = {}, s = {}, t = [], u = t.slice, v, w = function(a, c, d, e) {
40        var f, i, j, k, l = b.createElement("div"), m = b.body, n = m || b.createElement("body");
41        if (parseInt(d, 10))
42            while (d--)
43                j = b.createElement("div"),
44                j.id = e ? e[d] : h + (d + 1),
45                l.appendChild(j);
46        return f = ["&#173;", '<style id="s', h, '">', a, "</style>"].join(""),
47        l.id = h,
48        (m ? l : n).innerHTML += f,
49        n.appendChild(l),
50        m || (n.style.background = "",
51        n.style.overflow = "hidden",
52        k = g.style.overflow,
53        g.style.overflow = "hidden",
54        g.appendChild(n)),
55        i = c(l, a),
56        m ? l.parentNode.removeChild(l) : (n.parentNode.removeChild(n),
57        g.style.overflow = k),
58        !!i
59    }, x = {}.hasOwnProperty, y;
60    !B(x, "undefined") && !B(x.call, "undefined") ? y = function(a, b) {
61        return x.call(a, b)
62    }
63    : y = function(a, b) {
64        return b in a && B(a.constructor.prototype[b], "undefined")
65    }
66    ,
67    Function.prototype.bind || (Function.prototype.bind = function(b) {
68        var c = this;
69        if (typeof c != "function")
70            throw new TypeError;
71        var d = u.call(arguments, 1)
72          , e = function() {
73            if (this instanceof e) {
74                var a = function() {};
75                a.prototype = c.prototype;
76                var f = new a
77                  , g = c.apply(f, d.concat(u.call(arguments)));
78                return Object(g) === g ? g : f
79            }
80            return c.apply(b, d.concat(u.call(arguments)))
81        };
82        return e
83    }
84    ),
85    q.csstransforms = function() {
86        return !!F("transform")
87    }
88    ,
89    q.csstransforms3d = function() {
90        var a = !!F("perspective");
91        return a && "webkitPerspective"in g.style && w("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}", function(b, c) {
92            a = b.offsetLeft === 9 && b.offsetHeight === 3
93        }),
94        a
95    }
96    ;
97    for (var G in q)
98        y(q, G) && (v = G.toLowerCase(),
99        e[v] = q[G](),
100        t.push((e[v] ? "" : "no-") + v));
101    return e.addTest = function(a, b) {
102        if (typeof a == "object")
103            for (var d in a)
104                y(a, d) && e.addTest(d, a[d]);
105        else {
106            a = a.toLowerCase();
107            if (e[a] !== c)
108                return e;
109            b = typeof b == "function" ? b() : b,
110            typeof f != "undefined" && f && (g.className += " " + (b ? "" : "no-") + a),
111            e[a] = b
112        }
113        return e
114    }
115    ,
116    z(""),
117    i = k = null,
118    function(a, b) {
119        function k(a, b) {
120            var c = a.createElement("p")
121              , d = a.getElementsByTagName("head")[0] || a.documentElement;
122            return c.innerHTML = "x<style>" + b + "</style>",
123            d.insertBefore(c.lastChild, d.firstChild)
124        }
125        function l() {
126            var a = r.elements;
127            return typeof a == "string" ? a.split(" ") : a
128        }
129        function m(a) {
130            var b = i[a[g]];
131            return b || (b = {},
132            h++,
133            a[g] = h,
134            i[h] = b),
135            b
136        }
137        function n(a, c, f) {
138            c || (c = b);
139            if (j)
140                return c.createElement(a);
141            f || (f = m(c));
142            var g;
143            return f.cache[a] ? g = f.cache[a].cloneNode() : e.test(a) ? g = (f.cache[a] = f.createElem(a)).cloneNode() : g = f.createElem(a),
144            g.canHaveChildren && !d.test(a) ? f.frag.appendChild(g) : g
145        }
146        function o(a, c) {
147            a || (a = b);
148            if (j)
149                return a.createDocumentFragment();
150            c = c || m(a);
151            var d = c.frag.cloneNode()
152              , e = 0
153              , f = l()
154              , g = f.length;
155            for (; e < g; e++)
156                d.createElement(f[e]);
157            return d
158        }
159        function p(a, b) {
160            b.cache || (b.cache = {},
161            b.createElem = a.createElement,
162            b.createFrag = a.createDocumentFragment,
163            b.frag = b.createFrag()),
164            a.createElement = function(c) {
165                return r.shivMethods ? n(c, a, b) : b.createElem(c)
166            }
167            ,
168            a.createDocumentFragment = Function("h,f", "return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(" + l().join().replace(/\w+/g, function(a) {
169                return b.createElem(a),
170                b.frag.createElement(a),
171                'c("' + a + '")'
172            }) + ");return n}")(r, b.frag)
173        }
174        function q(a) {
175            a || (a = b);
176            var c = m(a);
177            return r.shivCSS && !f && !c.hasCSS && (c.hasCSS = !!k(a, "article,aside,figcaption,figure,footer,header,hgroup,nav,section{dis
177play:block}mark{background:#FF0;color:#000}")),
178            j || p(a, c),
179            a
180        }
181        var c = a.html5 || {}, d = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i, e = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i, f, g = "_html5shiv", h = 0, i = {}, j;
182        (function() {
183            try {
184                var a = b.createElement("a");
185                a.innerHTML = "<xyz></xyz>",
186                f = "hidden"in a,
187                j = a.childNodes.length == 1 || function() {
188                    b.createElement("a");
189                    var a = b.createDocumentFragment();
190                    return typeof a.cloneNode == "undefined" || typeof a.createDocumentFragment == "undefined" || typeof a.createElement == "undefined"
191                }()
192            } catch (c) {
193                f = !0,
194                j = !0
195            }
196        }
197        )();
198        var r = {
199            elements: c.elements || "abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",
200            shivCSS: c.shivCSS !== !1,
201            supportsUnknownElements: j,
202            shivMethods: c.shivMethods !== !1,
203            type: "default",
204            shivDocument: q,
205            createElement: n,
206            createDocumentFragment: o
207        };
208        a.html5 = r,
209        q(b)
210    }(this, b),
211    e._version = d,
212    e._prefixes = m,
213    e._domPrefixes = p,
214    e._cssomPrefixes = o,
215    e.testProp = function(a) {
216        return D([a])
217    }
218    ,
219    e.testAllProps = F,
220    e.testStyles = w,
221    e.prefixed = function(a, b, c) {
222        return b ? F(a, b, c) : F(a, "pfx")
223    }
224    ,
225    g.className = g.className.replace(/(^|\s)no-js(\s|$)/, "$1$2") + (f ? " js " + t.join(" ") : ""),
226    e
227}(this, this.document);
228
229// Add test for transform-style: preserve-3d;
230Modernizr.addTest('preserve3d', Modernizr.testAllProps('transformStyle', 'preserve-3d'));
231
232
233// =================next js file ================== //
234// Avoid `console` errors in browsers that lack a console.
235(function(){for(var a,e=function(){},b="assert clear count debug dir dirxml error exception group groupCollapsed groupEnd info log markTimeline profile profileEnd table time timeEnd timeStamp trace warn".split(" "),c=b.length,d=window.console=window.console||{};c--;)a=b[c],d[a]||(d[a]=e)})();
236
237// LoremImages
238(function(b){b.fn.loremImages=function(e,d,j){var a=b.extend({},b.fn.loremImages.defaults,j);return this.each(function(c,k){var f=b(k),g="";for(c=0;c<a.count;c++){var h=e+Math.round(Math.random()*a.randomWidth),i=d+Math.round(Math.random()*a.randomHeight);g+=a.itemBuilder.call(f,c,"//lorempixel.com/"+(a.grey?"g/":"")+h+"/"+i+"/"+(a.category?a.category+"/":"")+"?"+Math.round(Math.random()*1E3),h,i)}f.append(g)})};b.fn.loremImages.defaults={count:10,grey:0,randomWidth:0,randomHeight:0,category:0,itemBuilder:function(e,
239d){return'<img src="'+d+'" alt="Lorempixel">'}}})(jQuery);
240
241// jQuery easing 1.3
242jQuery.easing.jswing=jQuery.easing.swing;
243jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,a,c,b,d){return jQuery.easing[jQuery.easing.def](e,a,c,b,d)},easeInQuad:function(e,a,c,b,d){return b*(a/=d)*a+c},easeOutQuad:function(e,a,c,b,d){return-b*(a/=d)*(a-2)+c},easeInOutQuad:function(e,a,c,b,d){return 1>(a/=d/2)?b/2*a*a+c:-b/2*(--a*(a-2)-1)+c},easeInCubic:function(e,a,c,b,d){return b*(a/=d)*a*a+c},easeOutCubic:function(e,a,c,b,d){return b*((a=a/d-1)*a*a+1)+c},easeInOutCubic:function(e,a,c,b,d){return 1>(a/=d/2)?b/2*a*a*a+c:
244b/2*((a-=2)*a*a+2)+c},easeInQuart:function(e,a,c,b,d){return b*(a/=d)*a*a*a+c},easeOutQuart:function(e,a,c,b,d){return-b*((a=a/d-1)*a*a*a-1)+c},easeInOutQuart:function(e,a,c,b,d){return 1>(a/=d/2)?b/2*a*a*a*a+c:-b/2*((a-=2)*a*a*a-2)+c},easeInQuint:function(e,a,c,b,d){return b*(a/=d)*a*a*a*a+c},easeOutQuint:function(e,a,c,b,d){return b*((a=a/d-1)*a*a*a*a+1)+c},easeInOutQuint:function(e,a,c,b,d){return 1>(a/=d/2)?b/2*a*a*a*a*a+c:b/2*((a-=2)*a*a*a*a+2)+c},easeInSine:function(e,a,c,b,d){return-b*Math.cos(a/
245d*(Math.PI/2))+b+c},easeOutSine:function(e,a,c,b,d){return b*Math.sin(a/d*(Math.PI/2))+c},easeInOutSine:function(e,a,c,b,d){return-b/2*(Math.cos(Math.PI*a/d)-1)+c},easeInExpo:function(e,a,c,b,d){return 0==a?c:b*Math.pow(2,10*(a/d-1))+c},easeOutExpo:function(e,a,c,b,d){return a==d?c+b:b*(-Math.pow(2,-10*a/d)+1)+c},easeInOutExpo:function(e,a,c,b,d){return 0==a?c:a==d?c+b:1>(a/=d/2)?b/2*Math.pow(2,10*(a-1))+c:b/2*(-Math.pow(2,-10*--a)+2)+c},easeInCirc:function(e,a,c,b,d){return-b*(Math.sqrt(1-(a/=d)*
246a)-1)+c},easeOutCirc:function(e,a,c,b,d){return b*Math.sqrt(1-(a=a/d-1)*a)+c},easeInOutCirc:function(e,a,c,b,d){return 1>(a/=d/2)?-b/2*(Math.sqrt(1-a*a)-1)+c:b/2*(Math.sqrt(1-(a-=2)*a)+1)+c},easeInElastic:function(e,a,c,b,d){var e=1.70158,f=0,g=b;if(0==a)return c;if(1==(a/=d))return c+b;f||(f=0.3*d);g<Math.abs(b)?(g=b,e=f/4):e=f/(2*Math.PI)*Math.asin(b/g);return-(g*Math.pow(2,10*(a-=1))*Math.sin((a*d-e)*2*Math.PI/f))+c},easeOutElastic:function(e,a,c,b,d){var e=1.70158,f=0,g=b;if(0==a)return c;if(1==
247(a/=d))return c+b;f||(f=0.3*d);g<Math.abs(b)?(g=b,e=f/4):e=f/(2*Math.PI)*Math.asin(b/g);return g*Math.pow(2,-10*a)*Math.sin((a*d-e)*2*Math.PI/f)+b+c},easeInOutElastic:function(e,a,c,b,d){var e=1.70158,f=0,g=b;if(0==a)return c;if(2==(a/=d/2))return c+b;f||(f=d*0.3*1.5);g<Math.abs(b)?(g=b,e=f/4):e=f/(2*Math.PI)*Math.asin(b/g);return 1>a?-0.5*g*Math.pow(2,10*(a-=1))*Math.sin((a*d-e)*2*Math.PI/f)+c:0.5*g*Math.pow(2,-10*(a-=1))*Math.sin((a*d-e)*2*Math.PI/f)+b+c},easeInBack:function(e,a,c,b,d,f){void 0==
248f&&(f=1.70158);return b*(a/=d)*a*((f+1)*a-f)+c}
248,easeOutBack:function(e,a,c,b,d,f){void 0==f&&(f=1.70158);return b*((a=a/d-1)*a*((f+1)*a+f)+1)+c},easeInOutBack:function(e,a,c,b,d,f){void 0==f&&(f=1.70158);return 1>(a/=d/2)?b/2*a*a*(((f*=1.525)+1)*a-f)+c:b/2*((a-=2)*a*(((f*=1.525)+1)*a+f)+2)+c},easeInBounce:function(e,a,c,b,d){return b-jQuery.easing.easeOutBounce(e,d-a,0,b,d)+c},easeOutBounce:function(e,a,c,b,d){return(a/=d)<1/2.75?b*7.5625*a*a+c:a<2/2.75?b*(7.5625*(a-=1.5/2.75)*a+0.75)+c:a<2.5/2.75?
249b*(7.5625*(a-=2.25/2.75)*a+0.9375)+c:b*(7.5625*(a-=2.625/2.75)*a+0.984375)+c},easeInOutBounce:function(e,a,c,b,d){return a<d/2?0.5*jQuery.easing.easeInBounce(e,2*a,0,b,d)+c:0.5*jQuery.easing.easeOutBounce(e,2*a-d,0,b,d)+0.5*b+c}});
250
251// jQuery throttle / debounce - v1.1 - 3/7/2010
252(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);
253
254// ===================  next sly.js file ================= //
255/*!
256 * sly 1.6.1 - 8th Aug 2015
257 * https://github.com/darsain/sly
258 *
259 * Licensed under the MIT license.
260 * http://opensource.org/licenses/MIT
261 */
262
263;(function ($, w, undefined) {
264	'use strict';
265
266	var pluginName = 'sly';
267	var className  = 'Sly';
268	var namespace  = pluginName;
269
270	// Local WindowAnimationTiming interface
271	var cAF = w.cancelAnimationFrame || w.cancelRequestAnimationFrame;
272	var rAF = w.requestAnimationFrame;
273
274	// Support indicators
275	var transform, gpuAcceleration;
276
277	// Other global values
278	var $doc = $(document);
279	var dragInitEvents = 'touchstart.' + namespace + ' mousedown.' + namespace;
280	var dragMouseEvents = 'mousemove.' + namespace + ' mouseup.' + namespace;
281	var dragTouchEvents = 'touchmove.' + namespace + ' touchend.' + namespace;
282	var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel.' : 'mousewheel.') + namespace;
283	var clickEvent = 'click.' + namespace;
284	var mouseDownEvent = 'mousedown.' + namespace;
285	var interactiveElements = ['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA'];
286	var tmpArray = [];
287	var time;
288
289	// Math shorthands
290	var abs = Math.abs;
291	var sqrt = Math.sqrt;
292	var pow = Math.pow;
293	var round = Math.round;
294	var max = Math.max;
295	var min = Math.min;
296
297	// Keep track of last fired global wheel event
298	var lastGlobalWheel = 0;
299	$doc.on(wheelEvent, function (event) {
300		var sly = event.originalEvent[namespace];
301		var time = +new Date();
302		// Update last global wheel time, but only when event didn't originate
303		// in Sly frame, or the origin was less than scrollHijack time ago
304		if (!sly || sly.options.scrollHijack < time - lastGlobalWheel) lastGlobalWheel = time;
305	});
306
307	/**
308	 * Sly.
309	 *
310	 * @class
311	 *
312	 * @param {Element} frame       DOM element of sly container.
313	 * @param {Object}  options     Object with options.
314	 * @param {Object}  callbackMap Callbacks map.
315	 */
316	function Sly(frame, options, callbackMap) {
317		if (!(this instanceof Sly)) return new Sly(frame, options, callbackMap);
318
319		// Extend options
320		var o = $.extend({}, Sly.defaults, options);
321
322		// Private variables
323		var self = this;
324		var parallax = isNumber(frame);
325
326		// Frame
327		var $frame = $(frame);
328		var $slidee = o.slidee ? $(o.slidee).eq(0) : $frame.children().eq(0);
329		var frameSize = 0;
330		var slideeSize = 0;
331		var pos = {
332			start: 0,
333			center: 0,
334			end: 0,
335			cur: 0,
336			dest: 0
337		};
338
339		// Scrollbar
340		var $sb = $(o.scrollBar).eq(0);
341		var $handle = $sb.children().eq(0);
342		var sbSize = 0;
343		var handleSize = 0;
344		var hPos = {
345			start: 0,
346			end: 0,
347			cur: 0
348		};
349
350		// Pagesbar
351		var $pb = $(o.pagesBar);
352		var $pages = 0;
353		var pages = [];
354
355		// Items
356		var $items = 0;
357		var items = [];
358		var rel = {
359			firstItem: 0,
360			lastItem: 0,
361			centerItem: 0,
362			activeItem: null,
363			activePage: 0
364		};
365
366		// Styles
367		var frameStyles = new StyleRestorer($frame[0]);
368		var slideeStyles = new StyleRestorer($slidee[0]);
369		var sbStyles = new StyleRestorer($sb[0]);
370		var handleStyles = new StyleRestorer($handle[0]);
371
372		// Navigation type booleans
373		var basicNav = o.itemNav === 'basic';
374		var forceCenteredNav = o.itemNav === 'forceCentered';
375		var centeredNav = o.itemNav === 'centered' || forceCenteredNav;
376		var itemNav = !parallax && (basicNav || centeredNav || forceCenteredNav);
377
378		// Miscellaneous
379		var $scrollSource = o.scrollSource ? $(o.scrollSource) : $frame;
380		var $dragSource = o.dragSource ? $(o.dragSource) : $frame;
381		var $forwardButton = $(o.forward);
382		var $backwardButton = $(o.backward);
383		var $prevButton = $(o.prev);
384		var $nextButton = $(o.next);
385		var $prevPageButton = $(o.prevPage);
386		var $nextPageButton = $(o.nextPage);
387		var callbacks = {};
388		var last = {};
389		var animation = {};
390		var move = {};
391		var dragging = {
392			released: 1
393		};
394		var scrolling = {
395			last: 0,
396			delta: 0,
397			resetTime: 200
398		};
399		var renderID = 0;
400		var historyID = 0;
401		var cycleID = 0;
402		var continuousID = 0;
403		var i, l;
404
405		// Normalizing frame
406		if (!parallax) {
407			frame = $frame[0];
408		}
409
410		// Expose properties
411		self.initialized = 0;
412		self.frame = frame;
413		self.slidee = $slidee[0];
414		self.pos = pos;
415		self.rel = rel;
416		self.items = items;
417		self.pages = pages;
418		self.isPaused = 0;
419		self.options = o;
420		self.dragging = dragging;
421
422		/**
423		 * Loading function.
424		 *
425		 * Populate arrays, set sizes, bind events, ...
426		 *
427		 * @param {Boolean} [isInit] Whether load is called from within self.init().
428		 * @return {Void}
429		 */
430		function load(isInit) {
431			// Local variables
432			var lastItemsCount = 0;
433			var lastPagesCount = pages.length;
434
435			// Save old position
436			pos.old = $.extend({}, pos);
437
438			// Reset global variables
439			frameSize = parallax ? 0 : $frame[o.horizontal ? 'width' : 'height']();
440			sbSize = $sb[o.horizontal ? 'width' : 'height']();
441			slideeSize = parallax ? frame : $slidee[o.horizontal ? 'outerWidth' : 'outerHeight']();
442			pages.length = 0;
443
444			// Set position limits & relatives
445			pos.start = 0;
446			pos.end = max(slideeSize - frameSize, 0);
447
448			// Sizes & offsets for item based navigations
449			if (itemNav) {
450				// Save the number of current items
451				lastItemsCount = items.length;
452
453				// Reset itemNav related variables
454				$items = $slidee.children(o.itemSelector);
455				items.length = 0;
456
457				// Needed variables
458				var paddingStart = getPx($slidee, o.horizontal ? 'paddingLeft' : 'paddingTop');
459				var paddingEnd = getPx($slidee, o.horizontal ? 'paddingRight' : 'paddingBottom');
460				var borderBox = $($items).css('boxSizing') === 'border-box';
461				var areFloated = $items.css('float') !== 'none';
462				var ignoredMargin = 0;
463				var lastItemIndex = $items.length - 1;
464				var lastItem;
465
466				// Reset slideeSize
467				slideeSize = 0;
468
469				// Iterate through items
470				$items.each(function (i, element) {
471					// Item
472					var $item = $(element);
473					var rect = element.getBoundingClientRect();
474					var itemSize = round(o.horizontal ? rect.width || rect.right - rect.left : rect.height || rect.bottom - rect.top);
475					var itemMarginStart = getPx($item, o.horizontal ? 'marginLeft' : 'marginTop');
476					var itemMarginEnd = getPx($item, o.horizontal ? 'marginRight' : 'marginBottom');
477					var itemSizeFull = itemSize + itemMarginStart + itemMarginEnd;
478					var singleSpaced = !itemMarginStart || !itemMarginEnd;
479					var item = {};
480					item.el = element;
481					item.size = singleSpaced ? itemSize : itemSizeFull;
482					item.half = item.size / 2;
483					item.start = slideeSize + (singleSpaced ? itemMarginStart : 0);
484					item.center = item.start - round(frameSize / 2 - item.size / 2);
485					item.end = item.start - frameSize + item.size;
486
487					// Account for slidee padding
488					if (!i) {
489						slideeSize += paddingStart;
490					}
491
492					// Increment slidee size for size of the active element
493					slideeSize += itemSizeFull;
494
495					// Try to account for vertical margin collapsing in vertical mode
496					// It's not bulletproof, but should work in 99% of cases
497					if (!o.horizontal && !areFloated) {
498						// Subtract smaller margin, but only when top margin is not 0, and this is not the first element
499						if (itemMarginEnd && itemMarginStart && i > 0) {
500							slideeSize -= min(itemMarginStart, itemMarginEnd);
501						}
502					}
503
504					// Things to be done on last item
505					if (i === lastItemIndex) {
506						item.end += paddingEnd;
507						slideeSize += paddingEnd;
508						ignoredMargin = singleSpaced ? itemMarginEnd : 0;
509					}
510
511					// Add item object to items array
512					items.push(item);
513					lastItem = item;
514				});
515
516				// Resize SLIDEE to fit all items
517				$slidee[0].style[o.horizontal ? 'width' : 'height'] = (borderBox ? slideeSize: slideeSize - paddingStart - paddingEnd) + 'px';
518
519				// Adjust internal SLIDEE size for last margin
520				slideeSize -= ignoredMargin;
521
522				// Set limits
523				if (items.length) {
524					pos.start =  items[0][forceCenteredNav ? 'center' : 'start'];
525					pos.end = forceCenteredNav ? lastItem.center : frameSize < slideeSize ? lastItem.end : pos.start;
526				} else {
527					pos.start = pos.end = 0;
528				}
529			}
530
531			// Calculate SLIDEE center position
532			pos.center = round(pos.end / 2 + pos.start / 2);
533
534			// Update relative positions
535			updateRelatives();
536
537			// Scrollbar
538			if ($handle.length && sbSize > 0) {
539				// Stretch scrollbar handle to represent the visible area
540				if (o.dynamicHandle) {
541					handleSize = pos.start === pos.end ? sbSize : round(sbSize * frameSize / slideeSize);
542					handleSize = within(handleSize, o.minHandleSize, sbSize);
543					$handle[0].style[o.horizontal ? 'width' : 'height'] = handleSize + 'px';
544				} else {
545					handleSize = $handle[o.horizontal ? 'outerWidth' : 'outerHeight']();
546				}
547
548				hPos.end = sbSize - handleSize;
549
550				if (!renderID) {
551					syncScrollbar();
552				}
553			}
554
555			// Pages
556			if (!parallax && frameSize > 0) {
557				var tempPagePos = pos.start;
558				var pagesHtml = '';
559
560				// Populate pages array
561				if (itemNav) {
562					$.each(items, function (i, item) {
563						if (forceCenteredNav) {
564							pages.push(item.center);
565						} else if (item.start + item.size > tempPagePos && tempPagePos <= pos.end) {
566							tempPagePos = item.start;
567							pages.push(tempPagePos);
568							tempPagePos += frameSize;
569							if (tempPagePos > pos.end && tempPagePos < pos.end + frameSize) {
570								pages.push(pos.end);
571							}
572						}
573					});
574				} else {
575					while (tempPagePos - frameSize < pos.end) {
576						pages.push(tempPagePos);
577						tempPagePos += frameSize;
578					}
579				}
580
581				// Pages bar
582				if ($pb[0] && lastPagesCount !== pages.length) {
583					for (var i = 0; i < pages.length; i++) {
584						pagesHtml += o.pageBuilder.call(self, i);
585					}
586					$pages = $pb.html(pagesHtml).children();
587					$pages.eq(rel.activePage).addClass(o.activeClass);
588				}
589			}
590
591			// Extend relative variables object with some useful info
592			rel.slideeSize = slideeSize;
593			rel.frameSize = frameSize;
594			rel.sbSize = sbSize;
595			rel.handleSize = handleSize;
596
597			// Activate requested position
598			if (itemNav) {
599				if (isInit && o.startAt != null) {
600					activate(o.startAt);
601					self[centeredNav ? 'toCenter' : 'toStart'](o.startAt);
602				}
603				// Fix possible overflowing
604				var activeItem = items[rel.activeItem];
605				slideTo(centeredNav && activeItem ? activeItem.center : within(pos.dest, pos.start, pos.end));
606			} else {
607				if (isInit) {
608					if (o.startAt != null) slideTo(o.startAt, 1);
609				} else {
610					// Fix possible overflowing
611					slideTo(within(pos.dest, pos.start, pos.end));
612				}
613			}
614
615			// Trigger load event
616			trigger('load');
617		}
618		self.reload = function () { load(); };
619
620		/**
621		 * Animate to a position.
622		 *
623		 * @param {Int}  newPos    New position.
624		 * @param {Bool} immediate Reposition immediately without an animation.
625		 * @param {Bool}
625 dontAlign Do not align items, use the raw position passed in first argument.
626		 *
627		 * @return {Void}
628		 */
629		function slideTo(newPos, immediate, dontAlign) {
630			// Align items
631			if (itemNav && dragging.released && !dontAlign) {
632				var tempRel = getRelatives(newPos);
633				var isNotBordering = newPos > pos.start && newPos < pos.end;
634
635				if (centeredNav) {
636					if (isNotBordering) {
637						newPos = items[tempRel.centerItem].center;
638					}
639					if (forceCenteredNav && o.activateMiddle) {
640						activate(tempRel.centerItem);
641					}
642				} else if (isNotBordering) {
643					newPos = items[tempRel.firstItem].start;
644				}
645			}
646
647			// Handle overflowing position limits
648			if (dragging.init && dragging.slidee && o.elasticBounds) {
649				if (newPos > pos.end) {
650					newPos = pos.end + (newPos - pos.end) / 6;
651				} else if (newPos < pos.start) {
652					newPos = pos.start + (newPos - pos.start) / 6;
653				}
654			} else {
655				newPos = within(newPos, pos.start, pos.end);
656			}
657
658			// Update the animation object
659			animation.start = +new Date();
660			animation.time = 0;
661			animation.from = pos.cur;
662			animation.to = newPos;
663			animation.delta = newPos - pos.cur;
664			animation.tweesing = dragging.tweese || dragging.init && !dragging.slidee;
665			animation.immediate = !animation.tweesing && (immediate || dragging.init && dragging.slidee || !o.speed);
666
667			// Reset dragging tweesing request
668			dragging.tweese = 0;
669
670			// Start animation rendering
671			if (newPos !== pos.dest) {
672				pos.dest = newPos;
673				trigger('change');
674				if (!renderID) {
675					render();
676				}
677			}
678
679			// Reset next cycle timeout
680			resetCycle();
681
682			// Synchronize states
683			updateRelatives();
684			updateButtonsState();
685			syncPagesbar();
686		}
687
688		/**
689		 * Render animation frame.
690		 *
691		 * @return {Void}
692		 */
693		function render() {
694			if (!self.initialized) {
695				return;
696			}
697
698			// If first render call, wait for next animationFrame
699			if (!renderID) {
700				renderID = rAF(render);
701				if (dragging.released) {
702					trigger('moveStart');
703				}
704				return;
705			}
706
707			// If immediate repositioning is requested, don't animate.
708			if (animation.immediate) {
709				pos.cur = animation.to;
710			}
711			// Use tweesing for animations without known end point
712			else if (animation.tweesing) {
713				animation.tweeseDelta = animation.to - pos.cur;
714				// Fuck Zeno's paradox
715				if (abs(animation.tweeseDelta) < 0.1) {
716					pos.cur = animation.to;
717				} else {
718					pos.cur += animation.tweeseDelta * (dragging.released ? o.swingSpeed : o.syncSpeed);
719				}
720			}
721			// Use tweening for basic animations with known end point
722			else {
723				animation.time = min(+new Date() - animation.start, o.speed);
724				pos.cur = animation.from + animation.delta * $.easing[o.easing](animation.time/o.speed, animation.time, 0, 1, o.speed);
725			}
726
727			// If there is nothing more to render break the rendering loop, otherwise request new animation frame.
728			if (animation.to === pos.cur) {
729				pos.cur = animation.to;
730				dragging.tweese = renderID = 0;
731			} else {
732				renderID = rAF(render);
733			}
734
735			trigger('move');
736
737			// Update SLIDEE position
738			if (!parallax) {
739				if (transform) {
740					$slidee[0].style[transform] = gpuAcceleration + (o.horizontal ? 'translateX' : 'translateY') + '(' + (-pos.cur) + 'px)';
741				} else {
742					$slidee[0].style[o.horizontal ? 'left' : 'top'] = -round(pos.cur) + 'px';
743				}
744			}
745
746			// When animation reached the end, and dragging is not active, trigger moveEnd
747			if (!renderID && dragging.released) {
748				trigger('moveEnd');
749			}
750
751			syncScrollbar();
752		}
753
754		/**
755		 * Synchronizes scrollbar with the SLIDEE.
756		 *
757		 * @return {Void}
758		 */
759		function syncScrollbar() {
760			if ($handle.length) {
761				hPos.cur = pos.start === pos.end ? 0 : (((dragging.init && !dragging.slidee) ? pos.dest : pos.cur) - pos.start) / (pos.end - pos.start) * hPos.end;
762				hPos.cur = within(round(hPos.cur), hPos.start, hPos.end);
763				if (last.hPos !== hPos.cur) {
764					last.hPos = hPos.cur;
765					if (transform) {
766						$handle[0].style[transform] = gpuAcceleration + (o.horizontal ? 'translateX' : 'translateY') + '(' + hPos.cur + 'px)';
767					} else {
768						$handle[0].style[o.horizontal ? 'left' : 'top'] = hPos.cur + 'px';
769					}
770				}
771			}
772		}
773
774		/**
775		 * Synchronizes pagesbar with SLIDEE.
776		 *
777		 * @return {Void}
778		 */
779		function syncPagesbar() {
780			if ($pages[0] && last.page !== rel.activePage) {
781				last.page = rel.activePage;
782				$pages.removeClass(o.activeClass).eq(rel.activePage).addClass(o.activeClass);
783				trigger('activePage', last.page);
784			}
785		}
786
787		/**
788		 * Returns the position object.
789		 *
790		 * @param {Mixed} item
791		 *
792		 * @return {Object}
793		 */
794		self.getPos = function (item) {
795			if (itemNav) {
796				var index = getIndex(item);
797				return index !== -1 ? items[index] : false;
798			} else {
799				var $item = $slidee.find(item).eq(0);
800
801				if ($item[0]) {
802					var offset = o.horizontal ? $item.offset().left - $slidee.offset().left : $item.offset().top - $slidee.offset().top;
803					var size = $item[o.horizontal ? 'outerWidth' : 'outerHeight']();
804
805					return {
806						start: offset,
807						center: offset - frameSize / 2 + size / 2,
808						end: offset - frameSize + size,
809						size: size
810					};
811				} else {
812					return false;
813				}
814			}
815		};
816
817		/**
818		 * Continuous move in a specified direction.
819		 *
820		 * @param  {Bool} forward True for forward movement, otherwise it'll go backwards.
821		 * @param  {Int}  speed   Movement speed in pixels per frame. Overrides options.moveBy value.
822		 *
823		 * @return {Void}
824		 */
825		self.moveBy = function (speed) {
826			move.speed = speed;
827			// If already initiated, or there is nowhere to move, abort
828			if (dragging.init || !move.speed || pos.cur === (move.speed > 0 ? pos.end : pos.start)) {
829				return;
830			}
831			// Initiate move object
832			move.lastTime = +new Date();
833			move.startPos = pos.cur;
834			// Set dragging as initiated
835			continuousInit('button');
836			dragging.init = 1;
837			// Start movement
838			trigger('moveStart');
839			cAF(continuousID);
840			moveLoop();
841		};
842
843		/**
844		 * Continuous movement loop.
845		 *
846		 * @return {Void}
847		 */
848		function moveLoop() {
849			// If there is nowhere to move anymore, stop
850			if (!move.speed || pos.cur === (move.speed > 0 ? pos.end : pos.start)) {
851				self.stop();
852			}
853			// Request new move loop if it hasn't been stopped
854			continuousID = dragging.init ? rAF(moveLoop) : 0;
855			// Update move object
856			move.now = +new Date();
857			move.pos = pos.cur + (move.now - move.lastTime) / 1000 * move.speed;
858			// Slide
859			slideTo(dragging.init ? move.pos : round(move.pos));
860			// Normally, this is triggered in render(), but if there
861			// is nothing to render, we have to do it manually here.
862			if (!dragging.init && pos.cur === pos.dest) {
863				trigger('moveEnd');
864			}
865			// Update times for future iteration
866			move.lastTime = move.now;
867		}
868
869		/**
870		 * Stops continuous movement.
871		 *
872		 * @return {Void}
873		 */
874		self.stop = function () {
875			if (dragging.source === 'button') {
876				dragging.init = 0;
877				dragging.released = 1;
878			}
879		};
880
881		/**
882		 * Activate previous item.
883		 *
884		 * @return {Void}
885		 */
886		self.prev = function () {
887			self.activate(rel.activeItem == null ? 0 : rel.activeItem - 1);
888		};
889
890		/**
891		 * Activate next item.
892		 *
893		 * @return {Void}
894		 */
895		self.next = function () {
896			self.activate(rel.activeItem == null ? 0 : rel.activeItem + 1);
897		};
898
899		/**
900		 * Activate previous page.
901		 *
902		 * @return {Void}
903		 */
904		self.prevPage = function () {
905			self.activatePage(rel.activePage - 1);
906		};
907
908		/**
909		 * Activate next page.
910		 *
911		 * @return {Void}
912		 */
913		self.nextPage = function () {
914			self.activatePage(rel.activePage + 1);
915		};
916
917		/**
918		 * Slide SLIDEE by amount of pixels.
919		 *
920		 * @param {Int}  delta     Pixels/Items. Positive means forward, negative means backward.
921		 * @param {Bool} immediate Reposition immediately without an animation.
922		 *
923		 * @return {Void}
924		 */
925		self.slideBy = function (delta, immediate) {
926			if (!delta) {
927				return;
928			}
929			if (itemNav) {
930				self[centeredNav ? 'toCenter' : 'toStart'](
931					within((centeredNav ? rel.centerItem : rel.firstItem) + o.scrollBy * delta, 0, items.length)
932				);
933			} else {
934				slideTo(pos.dest + delta, immediate);
935			}
936		};
937
938		/**
939		 * Animate SLIDEE to a specific position.
940		 *
941		 * @param {Int}  pos       New position.
942		 * @param {Bool} immediate Reposition immediately without an animation.
943		 *
944		 * @return {Void}
945		 */
946		self.slideTo = function (pos, immediate) {
947			slideTo(pos, immediate);
948		};
949
950		/**
951		 * Core method for handling `toLocation` methods.
952		 *
953		 * @param  {String} location
954		 * @param  {Mixed}  item
955		 * @param  {Bool}   immediate
956		 *
957		 * @return {Void}
958		 */
959		function to(location, item, immediate) {
960			// Optional arguments logic
961			if (type(item) === 'boolean') {
962				immediate = item;
963				item = undefined;
964			}
965
966			if (item === undefined) {
967				slideTo(pos[location], immediate);
968			} else {
969				// You can't align items to sides of the frame
970				// when centered navigation type is enabled
971				if (centeredNav && location !== 'center') {
972					return;
973				}
974
975				var itemPos = self.getPos(item);
976				if (itemPos) {
977					slideTo(itemPos[location], immediate, !centeredNav);
978				}
979			}
980		}
981
982		/**
983		 * Animate element or the whole SLIDEE to the start of the frame.
984		 *
985		 * @param {Mixed} item      Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
986		 * @param {Bool}  immediate Reposition immediately without an animation.
987		 *
988		 * @return {Void}
989		 */
990		self.toStart = function (item, immediate) {
991			to('start', item, immediate);
992		};
993
994		/**
995		 * Animate element or the whole SLIDEE to the end of the frame.
996		 *
997		 * @param {Mixed} item      Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
998		 * @param {Bool}  immediate Reposition immediately without an animation.
999		 *
1000		 * @return {Void}
1001		 */
1002		self.toEnd = function (item, immediate) {
1003			to('end', item, immediate);
1004		};
1005
1006		/**
1007		 * Animate element or the whole SLIDEE to the center of the frame.
1008		 *
1009		 * @param {Mixed} item      Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
1010		 * @param {Bool}  immediate Reposition immediately without an animation.
1011		 *
1012		 * @return {Void}
1013		 */
1014		self.toCenter = function (item, immediate) {
1015			to('center', item, immediate);
1016		};
1017
1018		/**
1019		 * Get the index of an item in SLIDEE.
1020		 *
1021		 * @param {Mixed} item     Item DOM element.
1022		 *
1023		 * @return {Int}  Item index, or -1 if not found.
1024		 */
1025		function getIndex(item) {
1026			return item != null ?
1027					isNumber(item) ?
1028						item >= 0 && item < items.length ? item : -1 :
1029						$items.index(item) :
1030					-1;
1031		}
1032		// Expose getIndex without lowering the compressibility of it,
1033		// as it is used quite often throughout Sly.
1034		self.getIndex = getIndex;
1035
1036		/**
1037		 * Get index of an item in SLIDEE based on a variety of input types.
1038		 *
1039		 * @param  {Mixed} item DOM element, positive or negative integer.
1040		 *
1041		 * @return {Int}   Item index, or -1 if not found.
1042		 */
1043		function getRelativeIndex(item) {
1044			return getIndex(isNumber(item) && item < 0 ? item + items.length : item);
1045		}
1046
1047		/**
1048		 * Activates an item.
1049		 *
1050		 * @param  {Mixed} item Item DOM element, or index starting at 0.
1051		 *
1052		 * @return {Mixed} Activated item index or false on fail.
1053		 */
1054		function activate(item, force) {
1055			var index = getIndex(item);
1056
1057			if (!itemNav || index < 0) {
1058				return false;
1059			}
1060
1061			// Update classes, last active index, and trigger active event only when there
1062			// has been a change. Otherwise just return the current active index.
1063			if (last.active !== index || force) {
1064				// Update classes
1065				$items.eq(rel.activeItem).removeClass(o.activeClass);
1066				$items.eq(index).addClass(o.activeClass);
1067
1068				last.active = rel.activeItem = index;
1069
1070				updateButtonsState();
1071				trigger('active', index);
1072			}
1073
1074			return index;
1075		}
1076
1077		/**
1078		 * Activates an item and helps with further navigation when o.smart is enabled.
1079		 *
1080		 * @param {Mixed} item      Item DOM element, or index starting at 0.
1081		 * @param {Bool}  immediate Whether to reposition immediately in smart navigation.
1082		 *
1083		 * @return {Void}
1084		 */
1085		self.activate = function (item, immediate) {
1086			var index = activate(item);
1087
1088			// Smart navigation
1089			if (o.smart && index !== false) {
1090				// When centeredNav is enabled, center the element.
1091				// Otherwise, determine where to position the element based on its current position.
1092				// If the element is currently on the far end side of the frame, assume that user is
1093				// moving forward and animate it to the start of the visible frame, and vice versa.
1094				if (centeredNav) {
1095					self.toCenter(index, immediate);
1096				} else if (index >= rel.lastItem) {
1097					self.toStart(index, immediate);
1098				} else if (index <= rel.firstItem) {
1099					self.toEnd(index, immediate);
1100				} else {
1101					resetCycle();
1102				}
1103			}
1104		};
1105
1106		/**
1107		 * Activates a page.
1108		 *
1109		 * @param {Int}  index     Page index, starting from 0.
1110		 * @param {Bool} immediate Whether to reposition immediately without animation.
1111		 *
1112		 * @return {Void}
1113		 */
1114		self.activatePage = function (index, immediate) {
1115			if (isNumber(index)) {
1116				slideTo(pages[within(index, 0, pages.length - 1)], immediate);
1117			}
1118		};
1119
1120		/**
1121		 * Return relative positions of items based on their visibility within FRAME.
1122		 *
1123		 * @param {Int} slideePos Position of SLIDEE.
1124		 *
1125		 * @return {Void}
1126		 */
1127		function getRelatives(slideePos) {
1128			slideePos = within(isNumber(slideePos) ? slideePos : pos.dest, pos.start, pos.end);
1129
1130			var relatives = {};
1131			var centerOffset = forceCenteredNav ? 0 : frameSize / 2;
1132
1133			// Determine active page
1134			if (!parallax) {
1135				for (var p = 0, pl = pages.length; p < pl; p++) {
1136					if (slideePos >= pos.end || p === pages.length - 1) {
1137						relatives.activePage = pages.length - 1;
1138						break;
1139					}
1140
1141					if (slideePos <= pages[p] + centerOffset) {
1142						relatives.activePage = p;
1143						break;
1144					}
1145				}
1146			}
1147
1148			// Relative item indexes
1149			if (itemNav) {
1150				var first = false;
1151				var last = false;
1152				var center = false;
1153
1154				// From start
1155				for (var i = 0, il = items.length; i < il; i++) {
1156					// First item
1157					if (first === false && slideePos <= items[i].start + items[i].half) {
1158						first = i;
1159					}
1160
1161					// Center item
1162					if (center === false && slideePos <= items[i].center + items[i].half) {
1163						center = i;
1164					}
1165
1166					// Last item
1167					if (i === il - 1 || slideePos <= items[i].end + items[i].half) {
1168						last = i;
1169						break;
1170					}
1171				}
1172
1173				// Safe assignment, just to be sure the false won't be returned
1174				relatives.firstItem = isNumber(first) ? first : 0;
1175				relatives.centerItem = isNumber(center) ? center : relatives.firstItem;
1176				relatives.lastItem = isNumber(last) ? last : relatives.centerItem;
1177			}
1178
1179			return relatives;
1180		}
1181
1182		/**
1183		 * Update object with relative positions.
1184		 *
1185		 * @param {Int} newPos
1186		 *
1187		 * @return {Void}
1188		 */
1189		function updateRelatives(newPos) {
1190			$.extend(rel, getRelatives(newPos));
1191		}
1192
1193		/**
1194		 * Disable navigation buttons when needed.
1195		 *
1196		 * Adds disabledClass, and when the button is <button> or <input>, activates :disabled state.
1197		 *
1198		 * @return {Void}
1199		 */
1200		function updateButtonsState() {
1201			var isStart = pos.dest <= pos.start;
1202			var isEnd = pos.dest >= pos.end;
1203			var slideePosState = (isStart ? 1 : 0) | (isEnd ? 2 : 0);
1204
1205			// Update paging buttons only if there has been a change in SLIDEE position
1206			if (last.slideePosState !== slideePosState) {
1207				last.slideePosState = slideePosState;
1208
1209				if ($prevPageButton.is('button,input')) {
1210					$prevPageButton.prop('disabled', isStart);
1211				}
1212
1213				if ($nextPageButton.is('button,input')) {
1214					$nextPageButton.prop('disabled', isEnd);
1215				}
1216
1217				$prevPageButton.add($backwardButton)[isStart ? 'addClass' : 'removeClass'](o.disabledClass);
1218				$nextPageButton.add($forwardButton)[isEnd ? 'addClass' : 'removeClass'](o.disabledClass);
1219			}
1220
1221			// Forward & Backward buttons need a separate state caching because we cannot "property disable"
1222			// them while they are being used, as disabled buttons stop emitting mouse events.
1223			if (last.fwdbwdState !== slideePosState && dragging.released) {
1224				last.fwdbwdState = slideePosState;
1225
1226				if ($backwardButton.is('button,input')) {
1227					$backwardButton.prop('disabled', isStart);
1228				}
1229
1230				if ($forwardButton.is('button,input')) {
1231					$forwardButton.prop('disabled', isEnd);
1232				}
1233			}
1234
1235			// Item navigation
1236			if (itemNav && rel.activeItem != null) {
1237				var isFirst = rel.activeItem === 0;
1238				var isLast = rel.activeItem >= items.length - 1;
1239				var itemsButtonState = (isFirst ? 1 : 0) | (isLast ? 2 : 0);
1240
1241				if (last.itemsButtonState !== itemsButtonState) {
1242					last.itemsButtonState = itemsButtonState;
1243
1244					if ($prevButton.is('button,input')) {
1245						$prevButton.prop('disabled', isFirst);
1246					}
1247
1248					if ($nextButton.is('button,input')) {
1249						$nextButton.prop('disabled', isLast);
1250					}
1251
1252					$prevButton[isFirst ? 'addClass' : 'removeClass'](o.disabledClass);
1253					$nextButton[isLast ? 'addClass' : 'removeClass'](o.disabledClass);
1254				}
1255			}
1256		}
1257
1258		/**
1259		 * Resume cycling.
1260		 *
1261		 * @param {Int} priority Resume pause with priority lower or equal than this. Used internally for pauseOnHover.
1262		 *
1263		 * @return {Void}
1264		 */
1265		self.resume = function (priority) {
1266			if (!o.cycleBy || !o.cycleInterval || o.cycleBy === 'items' && (!items[0] || rel.activeItem == null) || priority < self.isPaused) {
1267				return;
1268			}
1269
1270			self.isPaused = 0;
1271
1272			if (cycleID) {
1273				cycleID = clearTimeout(cycleID);
1274			} else {
1275				trigger('resume');
1276			}
1277
1278			cycleID = setTimeout(function () {
1279				trigger('cycle');
1280				switch (o.cycleBy) {
1281					case 'items':
1282						self.activate(rel.activeItem >= items.length - 1 ? 0 : rel.activeItem + 1);
1283						break;
1284
1285					case 'pages':
1286						self.activatePage(rel.activePage >
1286= pages.length - 1 ? 0 : rel.activePage + 1);
1287						break;
1288				}
1289			}, o.cycleInterval);
1290		};
1291
1292		/**
1293		 * Pause cycling.
1294		 *
1295		 * @param {Int} priority Pause priority. 100 is default. Used internally for pauseOnHover.
1296		 *
1297		 * @return {Void}
1298		 */
1299		self.pause = function (priority) {
1300			if (priority < self.isPaused) {
1301				return;
1302			}
1303
1304			self.isPaused = priority || 100;
1305
1306			if (cycleID) {
1307				cycleID = clearTimeout(cycleID);
1308				trigger('pause');
1309			}
1310		};
1311
1312		/**
1313		 * Toggle cycling.
1314		 *
1315		 * @return {Void}
1316		 */
1317		self.toggle = function () {
1318			self[cycleID ? 'pause' : 'resume']();
1319		};
1320
1321		/**
1322		 * Updates a signle or multiple option values.
1323		 *
1324		 * @param {Mixed} name  Name of the option that should be updated, or object that will extend the options.
1325		 * @param {Mixed} value New option value.
1326		 *
1327		 * @return {Void}
1328		 */
1329		self.set = function (name, value) {
1330			if ($.isPlainObject(name)) {
1331				$.extend(o, name);
1332			} else if (o.hasOwnProperty(name)) {
1333				o[name] = value;
1334			}
1335		};
1336
1337		/**
1338		 * Add one or multiple items to the SLIDEE end, or a specified position index.
1339		 *
1340		 * @param {Mixed} element Node element, or HTML string.
1341		 * @param {Int}   index   Index of a new item position. By default item is appended at the end.
1342		 *
1343		 * @return {Void}
1344		 */
1345		self.add = function (element, index) {
1346			var $element = $(element);
1347
1348			if (itemNav) {
1349				// Insert the element(s)
1350				if (index == null || !items[0] || index >= items.length) {
1351					$element.appendTo($slidee);
1352				} else if (items.length) {
1353					$element.insertBefore(items[index].el);
1354				}
1355
1356				// Adjust the activeItem index
1357				if (rel.activeItem != null && index <= rel.activeItem) {
1358					last.active = rel.activeItem += $element.length;
1359				}
1360			} else {
1361				$slidee.append($element);
1362			}
1363
1364			// Reload
1365			load();
1366		};
1367
1368		/**
1369		 * Remove an item from SLIDEE.
1370		 *
1371		 * @param {Mixed} element Item index, or DOM element.
1372		 * @param {Int}   index   Index of a new item position. By default item is appended at the end.
1373		 *
1374		 * @return {Void}
1375		 */
1376		self.remove = function (element) {
1377			if (itemNav) {
1378				var index = getRelativeIndex(element);
1379
1380				if (index > -1) {
1381					// Remove the element
1382					$items.eq(index).remove();
1383
1384					// If the current item is being removed, activate new one after reload
1385					var reactivate = index === rel.activeItem;
1386
1387					// Adjust the activeItem index
1388					if (rel.activeItem != null && index < rel.activeItem) {
1389						last.active = --rel.activeItem;
1390					}
1391
1392					// Reload
1393					load();
1394
1395					// Activate new item at the removed position
1396					if (reactivate) {
1397						last.active = null;
1398						self.activate(rel.activeItem);
1399					}
1400				}
1401			} else {
1402				$(element).remove();
1403				load();
1404			}
1405		};
1406
1407		/**
1408		 * Helps re-arranging items.
1409		 *
1410		 * @param  {Mixed} item     Item DOM element, or index starting at 0. Use negative numbers to select items from the end.
1411		 * @param  {Mixed} position Item insertion anchor. Accepts same input types as item argument.
1412		 * @param  {Bool}  after    Insert after instead of before the anchor.
1413		 *
1414		 * @return {Void}
1415		 */
1416		function moveItem(item, position, after) {
1417			item = getRelativeIndex(item);
1418			position = getRelativeIndex(position);
1419
1420			// Move only if there is an actual change requested
1421			if (item > -1 && position > -1 && item !== position && (!after || position !== item - 1) && (after || position !== item + 1)) {
1422				$items.eq(item)[after ? 'insertAfter' : 'insertBefore'](items[position].el);
1423
1424				var shiftStart = item < position ? item : (after ? position : position - 1);
1425				var shiftEnd = item > position ? item : (after ? position + 1 : position);
1426				var shiftsUp = item > position;
1427
1428				// Update activeItem index
1429				if (rel.activeItem != null) {
1430					if (item === rel.activeItem) {
1431						last.active = rel.activeItem = after ? (shiftsUp ? position + 1 : position) : (shiftsUp ? position : position - 1);
1432					} else if (rel.activeItem > shiftStart && rel.activeItem < shiftEnd) {
1433						last.active = rel.activeItem += shiftsUp ? 1 : -1;
1434					}
1435				}
1436
1437				// Reload
1438				load();
1439			}
1440		}
1441
1442		/**
1443		 * Move item after the target anchor.
1444		 *
1445		 * @param  {Mixed} item     Item to be moved. Can be DOM element or item index.
1446		 * @param  {Mixed} position Target position anchor. Can be DOM element or item index.
1447		 *
1448		 * @return {Void}
1449		 */
1450		self.moveAfter = function (item, position) {
1451			moveItem(item, position, 1);
1452		};
1453
1454		/**
1455		 * Move item before the target anchor.
1456		 *
1457		 * @param  {Mixed} item     Item to be moved. Can be DOM element or item index.
1458		 * @param  {Mixed} position Target position anchor. Can be DOM element or item index.
1459		 *
1460		 * @return {Void}
1461		 */
1462		self.moveBefore = function (item, position) {
1463			moveItem(item, position);
1464		};
1465
1466		/**
1467		 * Registers callbacks.
1468		 *
1469		 * @param  {Mixed}
1469 name  Event name, or callbacks map.
1470		 * @param  {Mixed} fn    Callback, or an array of callback functions.
1471		 *
1472		 * @return {Void}
1473		 */
1474		self.on = function (name, fn) {
1475			// Callbacks map
1476			if (type(name) === 'object') {
1477				for (var key in name) {
1478					if (name.hasOwnProperty(key)) {
1479						self.on(key, name[key]);
1480					}
1481				}
1482			// Callback
1483			} else if (type(fn) === 'function') {
1484				var names = name.split(' ');
1485				for (var n = 0, nl = names.length; n < nl; n++) {
1486					callbacks[names[n]] = callbacks[names[n]] || [];
1487					if (callbackIndex(names[n], fn) === -1) {
1488						callbacks[names[n]].push(fn);
1489					}
1490				}
1491			// Callbacks array
1492			} else if (type(fn) === 'array') {
1493				for (var f = 0, fl = fn.length; f < fl; f++) {
1494					self.on(name, fn[f]);
1495				}
1496			}
1497		};
1498
1499		/**
1500		 * Registers callbacks to be executed only once.
1501		 *
1502		 * @param  {Mixed} name  Event name, or callbacks map.
1503		 * @param  {Mixed} fn    Callback, or an array of callback functions.
1504		 *
1505		 * @return {Void}
1506		 */
1507		self.one = function (name, fn) {
1508			function proxy() {
1509				fn.apply(self, arguments);
1510				self.off(name, proxy);
1511			}
1512			self.on(name, proxy);
1513		};
1514
1515		/**
1516		 * Remove one or all callbacks.
1517		 *
1518		 * @param  {String} name Event name.
1519		 * @param  {Mixed}  fn   Callback, or an array of callback functions. Omit to remove all callbacks.
1520		 *
1521		 * @return {Void}
1522		 */
1523		self.off = function (name, fn) {
1524			if (fn instanceof Array) {
1525				for (var f = 0, fl = fn.length; f < fl; f++) {
1526					self.off(name, fn[f]);
1527				}
1528			} else {
1529				var names = name.split(' ');
1530				for (var n = 0, nl = names.length; n < nl; n++) {
1531					callbacks[names[n]] = callbacks[names[n]] || [];
1532					if (fn == null) {
1533						callbacks[names[n]].length = 0;
1534					} else {
1535						var index = callbackIndex(names[n], fn);
1536						if (index !== -1) {
1537							callbacks[names[n]].splice(index, 1);
1538						}
1539					}
1540				}
1541			}
1542		};
1543
1544		/**
1545		 * Returns callback array index.
1546		 *
1547		 * @param  {String}   name Event name.
1548		 * @param  {Function} fn   Function
1549		 *
1550		 * @return {Int} Callback array index, or -1 if isn't registered.
1551		 */
1552		function callbackIndex(name, fn) {
1553			for (var i = 0, l = callbacks[name].length; i < l; i++) {
1554				if (callbacks[name][i] === fn) {
1555					return i;
1556				}
1557			}
1558			return -1;
1559		}
1560
1561		/**
1562		 * Reset next cycle timeout.
1563		 *
1564		 * @return {Void}
1565		 */
1566		function resetCycle() {
1567			if (dragging.released && !self.isPaused) {
1568				self.resume();
1569			}
1570		}
1571
1572		/**
1573		 * Calculate SLIDEE representation of handle position.
1574		 *
1575		 * @param  {Int} handlePos
1576		 *
1577		 * @return {Int}
1578		 */
1579		function handleToSlidee(handlePos) {
1580			return round(within(handlePos, hPos.start, hPos.end) / hPos.end * (pos.end - pos.start)) + pos.start;
1581		}
1582
1583		/**
1584		 * Keeps track of a dragging delta history.
1585		 *
1586		 * @return {Void}
1587		 */
1588		function draggingHistoryTick() {
1589			// Looking at this, I know what you're thinking :) But as we need only 4 history states, doing it this way
1590			// as opposed to a proper loop is ~25 bytes smaller (when minified with GCC), a lot faster, and doesn't
1591			// generate garbage. The loop version would create 2 new variables on every tick. Unexaptable!
1592			dragging.history[0] = dragging.history[1];
1593			dragging.history[1] = dragging.history[2];
1594			dragging.history[2] = dragging.history[3];
1595			dragging.history[3] = dragging.delta;
1596		}
1597
1598		/**
1599		 * Initialize continuous movement.
1600		 *
1601		 * @return {Void}
1602		 */
1603		function continuousInit(source) {
1604			dragging.released = 0;
1605			dragging.source = source;
1606			dragging.slidee = source === 'slidee';
1607		}
1608
1609		/**
1610		 * Dragging initiator.
1611		 *
1612		 * @param  {Event} event
1613		 *
1614		 * @return {Void}
1615		 */
1616		function dragInit(event) {
1617			var isTouch = event.type === 'touchstart';
1618			var source = event.data.source;
1619			var isSlidee = source === 'slidee';
1620
1621			// Ignore when already in progress, or interactive element in non-touch navivagion
1622			if (dragging.init || !isTouch && isInteractive(event.target)) {
1623				return;
1624			}
1625
1626			// Handle dragging conditions
1627			if (source === 'handle' && (!o.dragHandle || hPos.start === hPos.end)) {
1628				return;
1629			}
1630
1631			// SLIDEE dragging conditions
1632			if (isSlidee && !(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) {
1633				return;
1634			}
1635
1636			if (!isTouch) {
1637				// prevents native image dragging in Firefox
1638				stopDefault(event);
1639			}
1640
1641			// Reset dragging object
1642			continuousInit(source);
1643
1644			// Properties used in dragHandler
1645			dragging.init = 0;
1646			dragging.$source = $(event.target);
1647			dragging.touch = isTouch;
1648			dragging.pointer = isTouch ? event.originalEvent.touches[0] : event;
1649			dragging.initX = dragging.pointer.pageX;
1650			dragging.initY = dragging.pointer.pageY;
1651			dragging.initPos = isSlidee ? pos.cur : hPos.cur;
1652			dragging.start = +new Date();
1653			dragging.time = 0;
1654			dragging.path = 0;
1655			dragging.delta = 0;
1656			dragging.locked = 0;
1657			dragging.history = [0, 0, 0, 0];
1658			dragging.pathToLock = isSlidee ? isTouch ? 30 : 10 : 0;
1659
1660			// Bind dragging events
1661			$doc.on(isTouch ? dragTouchEvents : dragMouseEvents, dragHandler);
1662
1663			// Pause ongoing cycle
1664			self.pause(1);
1665
1666			// Add dragging class
1667			(isSlidee ? $slidee : $handle).addClass(o.draggedClass);
1668
1669			// Trigger moveStart event
1670			trigger('moveStart');
1671
1672			// Keep track of a dragging path history. This is later used in the
1673			// dragging release swing calculation when dragging SLIDEE.
1674			if (isSlidee) {
1675				historyID = setInterval(draggingHistoryTick, 10);
1676			}
1677		}
1678
1679		/**
1680		 * Handler for dragging scrollbar handle or SLIDEE.
1681		 *
1682		 * @param  {Event} event
1683		 *
1684		 * @return {Void}
1685		 */
1686		function dragHandler(event) {
1687			dragging.released = event.type === 'mouseup' || event.type === 'touchend';
1688			dragging.pointer = dragging.touch ? event.originalEvent[dragging.released ? 'changedTouches' : 'touches'][0] : event;
1689			dragging.pathX = dragging.pointer.pageX - dragging.initX;
1690			dragging.pathY = dragging.pointer.pageY - dragging.initY;
1691			dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2));
1692			dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY;
1693
1694			if (!dragging.released && dragging.path < 1) return;
1695
1696			// We haven't decided whether this is a drag or not...
1697			if (!dragging.init) {
1698				// If the drag path was very short, maybe it's not a drag?
1699				if (dragging.path < o.dragThreshold) {
1700					// If the pointer was released, the path will not become longer and it's
1701					// definitely not a drag. If not released yet, decide on next iteration
1702					return dragging.released ? dragEnd() : undefined;
1703				}
1704				else {
1705					// If dragging path is sufficiently long we can confidently start a drag
1706					// if drag is in different direction than scroll, ignore it
1707					if (o.horizontal ? abs(dragging.pathX) > abs(dragging.pathY) : abs(dragging.pathX) < abs(dragging.pathY)) {
1708						dragging.init = 1;
1709					} else {
1710						return dragEnd();
1711					}
1712				}
1713			}
1714
1715			stopDefault(event);
1716
1717			// Disable click on a source element, as it is unwelcome when dragging
1718			if (!dragging.locked && dragging.path > dragging.pathToLock && dragging.slidee) {
1719				dragging.locked = 1;
1720				dragging.$source.on(clickEvent, disableOneEvent);
1721			}
1722
1723			// Cancel dragging on release
1724			if (dragging.released) {
1725				dragEnd();
1726
1727				// Adjust path with a swing on mouse release
1728				if (o.releaseSwing && dragging.slidee) {
1729					dragging.swing = (dragging.delta - dragging.history[0]) / 40 * 300;
1730					dragging.delta += dragging.swing;
1731					dragging.tweese = abs(dragging.swing) > 10;
1732				}
1733			}
1734
1735			slideTo(dragging.slidee ? round(dragging.initPos - dragging.delta) : handleToSlidee(dragging.initPos + dragging.delta));
1736		}
1737
1738		/**
1739		 * Stops dragging and cleans up after it.
1740		 *
1741		 * @return {Void}
1742		 */
1743		function dragEnd() {
1744			clearInterval(historyID);
1745			dragging.released = true;
1746			$doc.off(dragging.touch ? dragTouchEvents : dragMouseEvents, dragHandler);
1747			(dragging.slidee ? $slidee : $handle).removeClass(o.draggedClass);
1748
1749			// Make sure that disableOneEvent is not active in next tick.
1750			setTimeout(function () {
1751				dragging.$source.off(clickEvent, disableOneEvent);
1752			});
1753
1754			// Normally, this is triggered in render(), but if there
1755			// is nothing to render, we have to do it manually here.
1756			if (pos.cur === pos.dest && dragging.init) {
1757				trigger('moveEnd');
1758			}
1759
1760			// Resume ongoing cycle
1761			self.resume(1);
1762
1763			dragging.init = 0;
1764		}
1765
1766		/**
1767		 * Check whether element is interactive.
1768		 *
1769		 * @return {Boolean}
1770		 */
1771		function isInteractive(element) {
1772			return ~$.inArray(element.nodeName, interactiveElements) || $(element).is(o.interactive);
1773		}
1774
1775		/**
1776		 * Continuous movement cleanup on mouseup.
1777		 *
1778		 * @return {Void}
1779		 */
1780		function movementReleaseHandler() {
1781			self.stop();
1782			$doc.off('mouseup', movementReleaseHandler);
1783		}
1784
1785		/**
1786		 * Buttons navigation handler.
1787		 *
1788		 * @param  {Event} event
1789		 *
1790		 * @return {Void}
1791		 */
1792		function buttonsHandler(event) {
1793			/*jshint validthis:true */
1794			stopDefault(event);
1795			switch (this) {
1796				case $forwardButton[0]:
1797				case $backwardButton[0]:
1798					self.moveBy($forwardButton.is(this) ? o.moveBy : -o.moveBy);
1799					$doc.on('mouseup', movementReleaseHandler);
1800					break;
1801
1802				case $prevButton[0]:
1803					self.prev();
1804					break;
1805
1806				case $nextButton[0]:
1807					self.next();
1808					break;
1809
1810				case $prevPageButton[0]:
1811					self.prevPage();
1812					break;
1813
1814				case $nextPageButton[0]:
1815					self.nextPage();
1816					break;
1817			}
1818		}
1819
1820		/**
1821		 * Mouse wheel delta normalization.
1822		 *
1823		 * @param  {Event} event
1824		 *
1825		 * @return {Int}
1826		 */
1827		function normalizeWheelDelta(event) {
1828			// wheelDelta needed only for IE8-
1829			scrolling.curDelta = ((o.horizontal ? event.deltaY || event.deltaX : event.deltaY) || -event.wheelDelta);
1830			scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100;
1831			if (!itemNav) {
1832				return scrolling.curDelta;
1833			}
1834			time = +new Date();
1835			if (scrolling.last < time - scrolling.resetTime) {
1836				scrolling.delta = 0;
1837			}
1838			scrolling.last = time;
1839			scrolling.delta += scrolling.curDelta;
1840			if (abs(scrolling.delta) < 1) {
1841				scrolling.finalDelta = 0;
1842			} else {
1843				scrolling.finalDelta = round(scrolling.delta / 1);
1844				scrolling.delta %= 1;
1845			}
1846			return scrolling.finalDelta;
1847		}
1848
1849		/**
1850		 * Mouse scrolling handler.
1851		 *
1852		 * @param  {Event} event
1853		 *
1854		 * @return {Void}
1855		 */
1856		function scrollHandler(event) {
1857			// Mark event as originating in a Sly instance
1858			event.originalEvent[namespace] = self;
1859			// Don't hijack global scrolling
1860			var time = +new Date();
1861			if (lastGlobalWheel + o.scrollHijack > time && $scrollSource[0] !== document && $scrollSource[0] !== window) {
1862				lastGlobalWheel = time;
1863				return;
1864			}
1865			// Ignore if there is no scrolling to be done
1866			if (!o.scrollBy || pos.start === pos.end) {
1867				return;
1868			}
1869			var delta = normalizeWheelDelta(event.originalEvent);
1870			// Trap scrolling only when necessary and/or requested
1871			if (o.scrollTrap || delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) {
1872				stopDefault(event, 1);
1873			}
1874			self.slideBy(o.scrollBy * delta);
1875		}
1876
1877		/**
1878		 * Scrollbar click handler.
1879		 *
1880		 * @param  {Event} event
1881		 *
1882		 * @return {Void}
1883		 */
1884		function scrollbarHandler(event) {
1885			// Only clicks on scroll bar. Ignore the handle.
1886			if (o.clickBar && event.target === $sb[0]) {
1887				stopDefault(event);
1888				// Calculate new handle position and sync SLIDEE to it
1889				slideTo(handleToSlidee((o.horizontal ? event.pageX - $sb.offset().left : event.pageY - $sb.offset().top) - handleSize / 2));
1890			}
1891		}
1892
1893		/**
1894		 * Keyboard input handler.
1895		 *
1896		 * @param  {Event} event
1897		 *
1898		 * @return {Void}
1899		 */
1900		function keyboardHandler(event) {
1901			if (!o.keyboardNavBy) {
1902				return;
1903			}
1904
1905			switch (event.which) {
1906				// Left or Up
1907				case o.horizontal ? 37 : 38:
1908					stopDefault(event);
1909					self[o.keyboardNavBy === 'pages' ? 'prevPage' : 'prev']();
1910					break;
1911
1912				// Right or Down
1913				case o.horizontal ? 39 : 40:
1914					stopDefault(event);
1915					self[o.keyboardNavBy === 'pages' ? 'nextPage' : 'next']();
1916					break;
1917			}
1918		}
1919
1920		/**
1921		 * Click on item activation handler.
1922		 *
1923		 * @param  {Event} event
1924		 *
1925		 * @return {Void}
1926		 */
1927		function activateHandler(event) {
1928			/*jshint validthis:true */
1929
1930			// Ignore clicks on interactive elements.
1931			if (isInteractive(this)) {
1932				event.originalEvent[namespace + 'ignore'] = true;
1933				return;
1934			}
1935
1936			// Ignore events that:
1937			// - are not originating from direct SLIDEE children
1938			// - originated from interactive elements
1939			if (this.parentNode !== $slidee[0] || event.originalEvent[namespace + 'ignore']) return;
1940
1941			self.activate(this);
1942		}
1943
1944		/**
1945		 * Click on page button handler.
1946		 *
1947		 * @param {Event} event
1948		 *
1949		 * @return {Void}
1950		 */
1951		function activatePageHandler() {
1952			/*jshint validthis:true */
1953			// Accept only events from direct pages bar children.
1954			if (this.parentNode === $pb[0]) {
1955				self.activatePage($pages.index(this));
1956			}
1957		}
1958
1959		/**
1960		 * Pause on hover handler.
1961		 *
1962		 * @param  {Event} event
1963		 *
1964		 * @return {Void}
1965		 */
1966		function pauseOnHoverHandler(event) {
1967			if (o.pauseOnHover) {
1968				self[event.type === 'mouseenter' ? 'pause' : 'resume'](2);
1969			}
1970		}
1971
1972		/**
1973		 * Trigger callbacks for event.
1974		 *
1975		 * @param  {String} name Event name.
1976		 * @param  {Mixed}  argX Arguments passed to callbacks.
1977		 *
1978		 * @return {Void}
1979		 */
1980		function trigger(name, arg1) {
1981			if (callbacks[name]) {
1982				l = callbacks[name].length;
1983				// Callbacks will be stored and executed from a temporary array to not
1984				// break the execution queue when one of the callbacks unbinds itself.
1985				tmpArray.length = 0;
1986				for (i = 0; i < l; i++) {
1987					tmpArray.push(callbacks[name][i]);
1988				}
1989				// Execute the callbacks
1990				for (i = 0; i < l; i++) {
1991					tmpArray[i].call(self, name, arg1);
1992				}
1993			}
1994		}
1995
1996		/**
1997		 * Destroys instance and everything it created.
1998		 *
1999		 * @return {Void}
2000		 */
2001		self.destroy = function () {
2002			// Remove the reference to itself
2003			Sly.removeInstance(frame);
2004
2005			// Unbind all events
2006			$scrollSource
2007				.add($handle)
2008				.add($sb)
2009				.add($pb)
2010				.add($forwardButton)
2011				.add($backwardButton)
2012				.add($prevButton)
2013				.add($nextButton)
2014				.add($prevPageButton)
2015				.add($nextPageButton)
2016				.off('.' + namespace);
2017
2018			// Unbinding specifically as to not nuke out other instances
2019			$doc.off('keydown', keyboardHandler);
2020
2021			// Remove classes
2022			$prevButton
2023				.add($nextButton)
2024				.add($prevPageButton)
2025				.add($nextPageButton)
2026				.removeClass(o.disabledClass);
2027
2028			if ($items && rel.activeItem != null) {
2029				$items.eq(rel.activeItem).removeClass(o.activeClass);
2030			}
2031
2032			// Remove page items
2033			$pb.empty();
2034
2035			if (!parallax) {
2036				// Unbind events from frame
2037				$frame.off('.' + namespace);
2038				// Restore original styles
2039				frameStyles.restore();
2040				slideeStyles.restore();
2041				sbStyles.restore();
2042				handleStyles.restore();
2043				// Remove the instance from element data storage
2044				$.removeData(frame, namespace);
2045			}
2046
2047			// Clean up collections
2048			items.length = pages.length = 0;
2049			last = {};
2050
2051			// Reset initialized status and return the instance
2052			self.initialized = 0;
2053			return self;
2054		};
2055
2056		/**
2057		 * Initialize.
2058		 *
2059		 * @return {Object}
2060		 */
2061		self.init = function () {
2062			if (self.initialized) {
2063				return;
2064			}
2065
2066			// Disallow multiple instances on the same element
2067			if (Sly.getInstance(frame)) throw new Error('There is already a Sly instance on this element');
2068
2069			// Store the reference to itself
2070			Sly.storeInstance(frame, self);
2071
2072			// Register callbacks map
2073			self.on(callbackMap);
2074
2075			// Save styles
2076			var holderProps = ['overflow', 'position'];
2077			var movableProps = ['position', 'webkitTransform', 'msTransform', 'transform', 'left', 'top', 'width', 'height'];
2078			frameStyles.save.apply(frameStyles, holderProps);
2079			sbStyles.save.apply(sbStyles, holderProps);
2080			slideeStyles.save.apply(slideeStyles, movableProps);
2081			handleStyles.save.apply(handleStyles, movableProps);
2082
2083			// Set required styles
2084			var $movables = $handle;
2085			if (!parallax) {
2086				$movables = $movables.add($slidee);
2087				$frame.css('overflow', 'hidden');
2088				if (!transform && $frame.css('position') === 'static') {
2089					$frame.css('position', 'relative');
2090				}
2091			}
2092			if (transform) {
2093				if (gpuAcceleration) {
2094					$movables.css(transform, gpuAcceleration);
2095				}
2096			} else {
2097				if ($sb.css('position') === 'static') {
2098					$sb.css('position', 'relative');
2099				}
2100				$movables.css({ position: 'absolute' });
2101			}
2102
2103			// Navigation buttons
2104			if (o.forward) {
2105				$forwardButton.on(mouseDownEvent, buttonsHandler);
2106			}
2107			if (o.backward) {
2108				$backwardButton.on(mouseDownEvent, buttonsHandler);
2109			}
2110			if (o.prev) {
2111				$prevButton.on(clickEvent, buttonsHandler);
2112			}
2113			if (o.next) {
2114				$nextButton.on(clickEvent, buttonsHandler);
2115			}
2116			if (o.prevPage) {
2117				$prevPageButton.on(clickEvent, buttonsHandler);
2118			}
2119			if (o.nextPage) {
2120				$nextPageButton.on(clickEvent, buttonsHandler);
2121			}
2122
2123			// Scrolling navigation
2124			$scrollSource.on(wheelEvent, scrollHandler);
2125
2126			// Clicking on scrollbar navigation
2127			if ($sb[0]) {
2128				$sb.on(clickEvent, scrollbarHandler);
2129			}
2130
2131			// Click on items navigation
2132			if (itemNav && o.activateOn) {
2133				$frame.on(o.activateOn + '.' + namespace, '*', activateHandler);
2134			}
2135
2136			// Pages navigation
2137			if ($pb[0] && o.activatePageOn) {
2138				$pb.on(o.activatePageOn + '.' + namespace, '*', activatePageHandler);
2139			}
2140
2141			// Dragging navigation
2142			$dragSource.on(dragInitEvents, { source: 'slidee' }, dragInit);
2143
2144			// Scrollbar dragging navigation
2145			if ($handle) {
2146				$handle.on(dragInitEvents, { source: 'handle' }, dragInit);
2147			}
2148
2149			// Keyboard navigation
2150			$doc.on('keydown', keyboardHandler);
2151
2152			if (!parallax) {
2153				// Pause on hover
2154				$frame.on('mouseenter.' + namespace + ' mouseleave.' + namespace, pauseOnHoverHandler);
2155				// Reset native FRAME element scroll
2156				$frame.on('scroll.' + namespace, resetScroll);
2157			}
2158
2159			// Mark instance as initialized
2160			self.initialized = 1;
2161
2162			// Load
2163			load(true);
2164
2165			// Initiate automatic cycling
2166			if (o.cycleBy && !parallax) {
2167				self[o.startPaused ? 'pause' : 'resume']();
2168			}
2169
2170			// Return instance
2171			return self;
2172		};
2173	}
2174
2175	Sly.getInstance = function (element) {
2176		return $.data(element, namespace);
2177	};
2178
2179	Sly.storeInstance = function (element, sly) {
2180		return $.data(element, namespace, sly);
2181	};
2182
2183	Sly.removeInstance = function (element) {
2184		return $.removeData(element, namespace);
2185	};
2186
2187	/**
2188	 * Return type of the value.
2189	 *
2190	 * @param  {Mixed} value
2191	 *
2192	 * @return {String}
2193	 */
2194	function type(value) {
2195		if (value == null) {
2196			return String(value);
2197		}
2198
2199		if (typeof value === 'object' || typeof value === 'function') {
2200			return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object';
2201		}
2202
2203		return typeof value;
2204	}
2205
2206	/**
2207	 * Event preventDefault & stopPropagation helper.
2208	 *
2209	 * @param {Event} event     Event object.
2210	 * @param {Bool}  noBubbles Cancel event bubbling.
2211	 *
2212	 * @return {Void}
2213	 */
2214	function stopDefault(event, noBubbles) {
2215		event.preventDefault();
2216		if (noBubbles) {
2217			event.stopPropagation();
2218		}
2219	}
2220
2221	/**
2222	 * Disables an event it was triggered on and unbinds itself.
2223	 *
2224	 * @param  {Event} event
2225	 *
2226	 * @return {Void}
2227	 */
2228	function disableOneEvent(event) {
2229		/*jshint validthis:true */
2230		stopDefault(event, 1);
2231		$(this).off(event.type, disableOneEvent);
2232	}
2233
2234	/**
2235	 * Resets native element scroll values to 0.
2236	 *
2237	 * @return {Void}
2238	 */
2239	function resetScroll() {
2240		/*jshint validthis:true */
2241		this.scrollLeft = 0;
2242		this.scrollTop = 0;
2243	}
2244
2245	/**
2246	 * Check if variable is a number.
2247	 *
2248	 * @param {Mixed} value
2249	 *
2250	 * @return {Boolean}
2251	 */
2252	function isNumber(value) {
2253		return !isNaN(parseFloat(value)) && isFinite(value);
2254	}
2255
2256	/**
2257	 * Parse style to pixels.
2258	 *
2259	 * @param {Object}   $item    jQuery object with element.
2260	 * @param {Property} property CSS property to get the pixels from.
2261	 *
2262	 * @return {Int}
2263	 */
2264	function getPx($item, property) {
2265		return 0 | round(String($item.css(property)).replace(/[^\-0-9.]/g, ''));
2266	}
2267
2268	/**
2269	 * Make sure that number is within the limits.
2270	 *
2271	 * @param {Number} number
2272	 * @param {Number} min
2273	 * @param {Number} max
2274	 *
2275	 * @return {Number}
2276	 */
2277	function within(number, min, max) {
2278		return number < min ? min : number > max ? max : number;
2279	}
2280
2281	/**
2282	 * Saves element styles for later restoration.
2283	 *
2284	 * Example:
2285	 *   var styles = new StyleRestorer(frame);
2286	 *   styles.save('position');
2287	 *   element.style.position = 'absolute';
2288	 *   styles.restore(); // restores to state before the assignment above
2289	 *
2290	 * @param {Element} element
2291	 */
2292	function StyleRestorer(element) {
2293		var self = {};
2294		self.style = {};
2295		self.save = function () {
2296			if (!element || !element.nodeType) return;
2297			for (var i = 0; i < arguments.length; i++) {
2298				self.style[arguments[i]] = element.style[arguments[i]];
2299			}
2300			return self;
2301		};
2302		self.restore = function () {
2303			if (!element || !element.nodeType) return;
2304			for (var prop in self.style) {
2305				if (self.style.hasOwnProperty(prop)) element.style[prop] = self.style[prop];
2306			}
2307			return self;
2308		};
2309		return self;
2310	}
2311
2312	// Local WindowAnimationTiming interface polyfill
2313	(function (w) {
2314		rAF = w.requestAnimationFrame
2315			|| w.webkitRequestAnimationFrame
2316			|| fallback;
2317
2318		/**
2319		* Fallback implementation.
2320		*/
2321		var prev = new Date().getTime();
2322		function fallback(fn) {
2323			var curr = new Date().getTime();
2324			var ms = Math.max(0, 16 - (curr - prev));
2325			var req = setTimeout(fn, ms);
2326			prev = curr;
2327			return req;
2328		}
2329
2330		/**
2331		* Cancel.
2332		*/
2333		var cancel = w.cancelAnimationFrame
2334			|| w.webkitCancelAnimationFrame
2335			|| w.clearTimeout;
2336
2337		cAF = function(id){
2338			cancel.call(w, id);
2339		};
2340	}(window));
2341
2342	// Feature detects
2343	(function () {
2344		var prefixes = ['', 'Webkit', 'Moz', 'ms', 'O'];
2345		var el = document.createElement('div');
2346
2347		function testProp(prop) {
2348			for (var p = 0, pl = prefixes.length; p < pl; p++) {
2349				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
2350				if (el.style[prefixedProp] != null) {
2351					return prefixedProp;
2352				}
2353			}
2354		}
2355
2356		// Global support indicators
2357		transform = testProp('transform');
2358		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
2359	}());
2360
2361	// Expose class globally
2362	w[className] = Sly;
2363
2364	// jQuery proxy
2365	$.fn[pluginName] = function (options, callbackMap) {
2366		var method, methodArgs;
2367
2368		// Attributes logic
2369		if (!$.isPlainObject(options)) {
2370			if (type(options) === 'string' || options === false) {
2371				method = options === false ? 'destroy' : options;
2372				methodArgs = Array.prototype.slice.call(arguments, 1);
2373			}
2374			options = {};
2375		}
2376
2377		// Apply to all elements
2378		return this.each(function (i, element) {
2379			// Call with prevention against multiple instantiations
2380			var plugin = Sly.getInstance(element);
2381
2382			if (!plugin && !method) {
2383				// Create a new object if it doesn't exist yet
2384				plugin = new Sly(element, options, callbackMap).init();
2385			} else if (plugin && method) {
2386				// Call method
2387				if (plugin[method]) {
2388					plugin[method].apply(plugin, methodArgs);
2389				}
2390			}
2391		});
2392	};
2393
2394	// Default options
2395	Sly.defaults = {
2396		slidee:     null,  // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
2397		horizontal: false, // Switch to horizontal mode.
2398
2399		// Item based navigation
2400		itemNav:        null,  // Item navigation type. Can be: 'basic', 'centered', 'forceCentered'.
2401		itemSelector:   null,  // Select only items that match this selector.
2402		smart:          false, // Repositions the activated item to help with further navigation.
2403		activateOn:     null,  // Activate an item on this event. Can be: 'click', 'mouseenter', ...
2404		activateMiddle: false, // Always activate the item in the middle of the FRAME. forceCentered only.
2405
2406		// Scrolling
2407		scrollSource: null,  // Element for catching the mouse wheel scrolling. Default is FRAME.
2408		scrollBy:     0,     // Pixels or items to move per one mouse scroll. 0 to disable scrolling.
2409		scrollHijack: 300,   // Milliseconds since last wheel event after which it is acceptable to hijack global scroll.
2410		scrollTrap:   false, // Don't bubble scrolling when hitting scrolling limits.
2411
2412		// Dragging
2413		dragSource:    null,  // Selector or DOM element for catching dragging events. Default is FRAME.
2414		mouseDragging: false, // Enable navigation by dragging the SLIDEE with mouse cursor.
2415		touchDragging: false, // Enable navigation by dragging the SLIDEE with touch events.
2416		releaseSwing:  false, // Ease out on dragging swing release.
2417		swingSpeed:    0.2,   // Swing synchronization speed, where: 1 = instant, 0 = infinite.
2418		elasticBounds: false, // Stretch SLIDEE position limits when dragging past FRAME boundaries.
2419		dragThreshold: 3,     // Distance in pixels before Sly recognizes dragging.
2420		interactive:   null,  // Selector for special interactive elements.
2421
2422		// Scrollbar
2423		scrollBar:     null,  // Selector or DOM element for scrollbar container.
2424		dragHandle:    false, // Whether the scrollbar handle should be draggable.
2425		dynamicHandle: false, // Scrollbar handle represents the ratio between hidden and visible content.
2426		minHandleSize: 50,    // Minimal height or width (depends on sly direction) of a handle in pixels.
2427		clickBar:      false, // Enable navigation by clicking on scrollbar.
2428		syncSpeed:     0.5,   // Handle =>
2428 SLIDEE synchronization speed, where: 1 = instant, 0 = infinite.
2429
2430		// Pagesbar
2431		pagesBar:       null, // Selector or DOM element for pages bar container.
2432		activatePageOn: null, // Event used to activate page. Can be: click, mouseenter, ...
2433		pageBuilder:          // Page item generator.
2434			function (index) {
2435				return '<li>' + (index + 1) + '</li>';
2436			},
2437
2438		// Navigation buttons
2439		forward:  null, // Selector or DOM element for "forward movement" button.
2440		backward: null, // Selector or DOM element for "backward movement" button.
2441		prev:     null, // Selector or DOM element for "previous item" button.
2442		next:     null, // Selector or DOM element for "next item" button.
2443		prevPage: null, // Selector or DOM element for "previous page" button.
2444		nextPage: null, // Selector or DOM element for "next page" button.
2445
2446		// Automated cycling
2447		cycleBy:       null,  // Enable automatic cycling by 'items' or 'pages'.
2448		cycleInterval: 5000,  // Delay between cycles in milliseconds.
2449		pauseOnHover:  false, // Pause cycling when mouse hovers over the FRAME.
2450		startPaused:   false, // Whether to start in paused sate.
2451
2452		// Mixed options
2453		moveBy:        300,     // Speed in pixels per second used by forward and backward buttons.
2454		speed:         0,       // Animations speed in milliseconds. 0 to disable animations.
2455		easing:        'swing', // Easing for duration based (tweening) animations.
2456		startAt:       null,    // Starting offset in pixels or items.
2457		keyboardNavBy: null,    // Enable keyboard navigation by 'items' or 'pages'.
2458
2459		// Classes
2460		draggedClass:  'dragged', // Class for dragged elements (like SLIDEE or scrollbar handle).
2461		activeClass:   'active',  // Class for active items and pages.
2462		disabledClass: 'disabled' // Class for disabled navigation elements.
2463	};
2464}(jQuery, window));
2465
2466// ==================== horisontal.js ================
2467jQuery(function($){
2468	'use strict';
2469
2470	// -------------------------------------------------------------
2471	//   Basic Navigation
2472	// -------------------------------------------------------------
2473	(function () {
2474		var $frame  = $('#basic');
2475		var $slidee = $frame.children('ul').eq(0);
2476		var $wrap   = $frame.parent();
2477
2478		// Call Sly on frame
2479		$frame.sly({
2480			horizontal: 1,
2481			itemNav: 'basic',
2482			smart: 1,
2483			activateOn: 'click',
2484			mouseDragging: 1,
2485			touchDragging: 1,
2486			releaseSwing: 1,
2487			startAt: 3,
2488			scrollBar: $wrap.find('.scrollbar'),
2489			scrollBy: 1,
2490			pagesBar: $wrap.find('.pages'),
2491			activatePageOn: 'click',
2492			speed: 300,
2493			elasticBounds: 1,
2494			easing: 'easeOutExpo',
2495			dragHandle: 1,
2496			dynamicHandle: 1,
2497			clickBar: 1,
2498
2499			// Buttons
2500			forward: $wrap.find('.forward'),
2501			backward: $wrap.find('.backward'),
2502			prev: $wrap.find('.prev'),
2503			next: $wrap.find('.next'),
2504			prevPage: $wrap.find('.prevPage'),
2505			nextPage: $wrap.find('.nextPage')
2506		});
2507
2508		// To Start button
2509		$wrap.find('.toStart').on('click', function () {
2510			var item = $(this).data('item');
2511			// Animate a particular item to the start of the frame.
2512			// If no item is provided, the whole content will be animated.
2513			$frame.sly('toStart', item);
2514		});
2515
2516		// To Center button
2517		$wrap.find('.toCenter').on('click', function () {
2518			var item = $(this).data('item');
2519			// Animate a particular item to the center of the frame.
2520			// If no item is provided, the whole content will be animated.
2521			$frame.sly('toCenter', item);
2522		});
2523
2524		// To End button
2525		$wrap.find('.toEnd').on('click', function () {
2526			var item = $(this).data('item');
2527			// Animate a particular item to the end of the frame.
2528			// If no item is provided, the whole content will be animated.
2529			$frame.sly('toEnd', item);
2530		});
2531
2532		// Add item
2533		$wrap.find('.add').on('click', function () {
2534			$frame.sly('add', '<li>' + $slidee.children().length + '</li>');
2535		});
2536
2537		// Remove item
2538		$wrap.find('.remove').on('click', function () {
2539			$frame.sly('remove', -1);
2540		});
2541	}());
2542
2543	// -------------------------------------------------------------
2544	//   Centered Navigation
2545	// -------------------------------------------------------------
2546	(function () {
2547		var $frame = $('#centered');
2548		var $wrap  = $frame.parent();
2549
2550		// Call Sly on frame
2551		$frame.sly({
2552			horizontal: 1,
2553			itemNav: 'centered',
2554			smart: 1,
2555			activateOn: 'click',
2556			mouseDragging: 1,
2557			touchDragging: 1,
2558			releaseSwing: 1,
2559			startAt: 4,
2560			scrollBar: $wrap.find('.scrollbar'),
2561			scrollBy: 1,
2562			speed: 300,
2563			elasticBounds: 1,
2564			easing: 'easeOutExpo',
2565			dragHandle: 1,
2566			dynamicHandle: 1,
2567			clickBar: 1,
2568
2569			// Buttons
2570			prev: $wrap.find('.prev'),
2571			next: $wrap.find('.next')
2572		});
2573	}());
2574
2575	// -------------------------------------------------------------
2576	//   Force Centered Navigation
2577	// -------------------------------------------------------------
2578	(function () {
2579		var $frame = $('#forcecentered');
2580		var $wrap  = $frame.parent();
2581
2582		// Call Sly on frame
2583		$frame.sly({
2584			horizontal: 1,
2585			itemNav: 'forceCentered',
2586			smart: 1,
2587			activateMiddle: 1,
2588			activateOn: 'click',
2589			mouseDragging: 1,
2590			touchDragging: 1,
2591			releaseSwing: 1,
2592			startAt: 2,
2593			scrollBar: $wrap.find('.scrollbar'),
2594			scrollBy: 1,
2595			speed: 300,
2596			elasticBounds: 1,
2597			easing: 'easeOutExpo',
2598			dragHandle: 1,
2599			dynamicHandle: 1,
2600			clickBar: 1,
2601
2602			// Buttons
2603			prev: $wrap.find('.prev'),
2604			next: $wrap.find('.next')
2605		});
2606	}());
2607
2608	// -------------------------------------------------------------
2609	//   Cycle By Items
2610	// -------------------------------------------------------------
2611	(function () {
2612		var $frame = $('#cycleitems');
2613		var $wrap  = $frame.parent();
2614
2615		// Call Sly on frame
2616		$frame.sly({
2617			horizontal: 1,
2618			itemNav: 'basic',
2619			smart: 1,
2620			activateOn: 'click',
2621			mouseDragging: 1,
2622			touchDragging: 1,
2623			releaseSwing: 1,
2624			startAt: 0,
2625			scrollBar: $wrap.find('.scrollbar'),
2626			scrollBy: 1,
2627			speed: 300,
2628			elasticBounds: 1,
2629			easing: 'easeOutExpo',
2630			dragHandle: 1,
2631			dynamicHandle: 1,
2632			clickBar: 1,
2633
2634			// Cycling
2635			cycleBy: 'items',
2636			cycleInterval: 1000,
2637			pauseOnHover: 1,
2638
2639			// Buttons
2640			prev: $wrap.find('.prev'),
2641			next: $wrap.find('.next')
2642		});
2643
2644		// Pause button
2645		$wrap.find('.pause').on('click', function () {
2646			$frame.sly('pause');
2647		});
2648
2649		// Resume button
2650		$wrap.find('.resume').on('click', function () {
2651			$frame.sly('resume');
2652		});
2653
2654		// Toggle button
2655		$wrap.find('.toggle').on('click', function () {
2656			$frame.sly('toggle');
2657		});
2658	}());
2659
2660	// -------------------------------------------------------------
2661	//   Cycle By Pages
2662	// -------------------------------------------------------------
2663	(function () {
2664		var $frame = $('#cyclepages');
2665		var $wrap  = $frame.parent();
2666
2667		// Call Sly on frame
2668		$frame.sly({
2669			horizontal: 1,
2670			itemNav: 'basic',
2671			smart: 1,
2672			activateOn: 'click',
2673			mouseDragging: 1,
2674			touchDragging: 1,
2675			releaseSwing: 1,
2676			startAt: 0,
2677			scrollBar: $wrap.find('.scrollbar'),
2678			scrollBy: 1,
2679			pagesBar: $wrap.find('.pages'),
2680			activatePageOn: 'click',
2681			speed: 300,
2682			elasticBounds: 1,
2683			easing: 'easeOutExpo',
2684			dragHandle: 1,
2685			dynamicHandle: 1,
2686			clickBar: 1,
2687
2688			// Cycling
2689			cycleBy: 'pages',
2690			cycleInterval: 1000,
2691			pauseOnHover: 1,
2692			startPaused: 1,
2693
2694			// Buttons
2695			prevPage: $wrap.find('.prevPage'),
2696			nextPage: $wrap.find('.nextPage')
2697		});
2698
2699		// Pause button
2700		$wrap.find('.pause').on('click', function () {
2701			$frame.sly('pause');
2702		});
2703
2704		// Resume button
2705		$wrap.find('.resume').on('click', function () {
2706			$frame.sly('resume');
2707		});
2708
2709		// Toggle button
2710		$wrap.find('.toggle').on('click', function () {
2711			$frame.sly('toggle');
2712		});
2713	}());
2714
2715	// -------------------------------------------------------------
2716	//   One Item Per Frame
2717	// -------------------------------------------------------------
2718	(function () {
2719		var $frame = $('#oneperframe');
2720		var $wrap  = $frame.parent();
2721
2722		// Call Sly on frame
2723		$frame.sly({
2724			horizontal: 1,
2725			itemNav: 'forceCentered',
2726			smart: 1,
2727			activateMiddle: 1,
2728			mouseDragging: 1,
2729			touchDragging: 1,
2730			releaseSwing: 1,
2731			startAt: 0,
2732			scrollBar: $wrap.find('.scrollbar'),
2733			scrollBy: 1,
2734			speed: 300,
2735			elasticBounds: 1,
2736			easing: 'easeOutExpo',
2737			dragHandle: 1,
2738			dynamicHandle: 1,
2739			clickBar: 1,
2740
2741			// Buttons
2742			prev: $wrap.find('.prev'),
2743			next: $wrap.find('.next')
2744		});
2745	}());
2746
2747	// -------------------------------------------------------------
2748	//   Crazy
2749	// -------------------------------------------------------------
2750	(function () {
2751		var $frame  = $('#crazy');
2752		var $slidee = $frame.children('ul').eq(0);
2753		var $wrap   = $frame.parent();
2754
2755		// Call Sly on frame
2756		$frame.sly({
2757			horizontal: 1,
2758			itemNav: 'basic',
2759			smart: 1,
2760			activateOn: 'click',
2761			mouseDragging: 1,
2762			touchDragging: 1,
2763			releaseSwing: 1,
2764			startAt: 3,
2765			scrollBar: $wrap.find('.scrollbar'),
2766			scrollBy: 1,
2767			pagesBar: $wrap.find('.pages'),
2768			activatePageOn: 'click',
2769			speed: 300,
2770			elasticBounds: 1,
2771			easing: 'easeOutExpo',
2772			dragHandle: 1,
2773			dynamicHandle: 1,
2774			clickBar: 1,
2775
2776			// Buttons
2777			forward: $wrap.find('.forward'),
2778			backward: $wrap.find('.backward'),
2779			prev: $wrap.find('.prev'),
2780			next: $wrap.find('.next'),
2781			prevPage: $wrap.find('.prevPage'),
2782			nextPage: $wrap.find('.nextPage')
2783		});
2784
2785		// To Start button
2786		$wrap.find('.toStart').on('click', function () {
2787			var item = $(this).data('item');
2788			// Animate a particular item to the start of the frame.
2789			// If no item is provided, the whole content will be animated.
2790			$frame.sly('toStart', item);
2791		});
2792
2793		// To Center button
2794		$wrap.find('.toCenter').on('click', function () {
2795			var item = $(this).data('item');
2796			// Animate a particular item to the center of the frame.
2797			// If no item is provided, the whole content will be animated.
2798			$frame.sly('toCenter', item);
2799		});
2800
2801		// To End button
2802		$wrap.find('.toEnd').on('click', function () {
2803			var item = $(this).data('item');
2804			// Animate a particular item to the end of the frame.
2805			// If no item is provided, the whole content will be animated.
2806			$frame.sly('toEnd', item);
2807		});
2808
2809		// Add item
2810		$wrap.find('.add').on('click', function () {
2811			$frame.sly('add', '<li>' + $slidee.children().length + '</li>');
2812		});
2813
2814		// Remove item
2815		$wrap.find('.remove').on('click', function () {
2816			$frame.sly('remove', -1);
2817		});
2818	}());
2819});

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