/**
Script: Slideshow.js
	Slideshow - A javascript class for Mootools to stream and animate the presentation of images on your website.

License:
	MIT-style license.

Copyright:
	Copyright (c) 2008 [Aeron Glemann](http://www.electricprism.com/aeron/).

Dependencies:
	Mootools 1.2 Core: Fx.Morph, Fx.Tween, Selectors, Element.Dimensions.
	Mootools 1.2 More: Assets.
*/
/*
Slideshow=new Class({Implements:[Chain,Events,Options],options:{captions:false,center:true,classes:[],controller:false,delay:2000,duration:750,fast:false,height:false,href:"",hu:"",linked:false,loader:{animate:["/img/frontend/loader-#.png",12]},loop:true,match:/\?slide=(\d+)$/,overlap:true,paused:false,properties:["href","rel","rev","title"],random:false,replace:[/(\.[^\.]+)$/,"t$1"],resize:"width",slide:0,thumbnails:false,titles:true,transition:function(A){return -(Math.cos(Math.PI*A)-1)/2},width:false},initialize:function(C,F,L){this.setOptions(L);this.slideshow=$(C);if(!this.slideshow){return }this.slideshow.set("styles",{display:"block",position:"relative","z-index":0});var H=window.location.href.match(this.options.match);this.slide=(this.options.match&&H)?H[1].toInt():this.options.slide;this.counter=this.delay=this.transition=0;this.direction="left";this.paused=false;if(!this.options.overlap){this.options.duration*=2}var G=this.slideshow.getElement("a")||new Element("a");if(!this.options.href){this.options.href=G.get("href")||""}if(this.options.hu.length&&!this.options.hu.test(/\/$/)){this.options.hu+="/"}if(this.options.fast===true){this.options.fast=2}var K=["slideshow","first","prev","play","pause","next","last","images","captions","controller","thumbnails","hidden","visible","inactive","active","loader"];var J=K.map(function(N,M){return this.options.classes[M]||N},this);this.classes=J.associate(K);this.classes.get=function(){var O="."+this.slideshow;for(var N=0,M=arguments.length;N<M;N++){O+=("-"+this[arguments[N]])}return O}.bind(this.classes);if(!F){this.options.hu="";F={};var D=this.slideshow.getElements(this.classes.get("thumbnails")+" img");this.slideshow.getElements(this.classes.get("images")+" img").each(function(O,Q){var S=O.get("src");var N=$pick(O.get("alt"),O.get("title"),"");var R=O.getParent();var P=(R.get("tag")=="a")?R.getProperties:{};var M=O.getParent().get("href")||"";var T=(D[Q])?D[Q].get("src"):"";F[S]={caption:N,href:M,thumbnail:T}})}var E=this.load(F);if(!E){return }this.events=$H({keydown:[],keyup:[],mousemove:[]});var B=function(M){switch(M.key){case"left":this.prev(M.shift);break;case"right":this.next(M.shift);break;case"p":this.pause();break}}.bind(this);this.events.keyup.push(B);document.addEvent("keyup",B);var C=this.slideshow.getElement(this.classes.get("images"));var I=(C)?C.empty():new Element("div",{"class":this.classes.get("images").substr(1)}).inject(this.slideshow);var A=I.getSize();this.height=this.options.height||A.y;this.width=this.options.width||A.x;I.set({styles:{display:"block",height:this.height,overflow:"hidden",position:"relative",width:this.width}});this.slideshow.store("images",I);this.a=this.image=this.slideshow.getElement("img")||new Element("img");if(Browser.Engine.trident&&Browser.Engine.version>4){this.a.style.msInterpolationMode="bicubic"}this.a.set("styles",{display:"none",position:"absolute",zIndex:1});this.b=this.a.clone();[this.a,this.b].each(function(M){G.clone().cloneEvents(G).grab(M).inject(I)});if(this.options.captions){this._captions()}if(this.options.controller){this._controller()}if(this.options.loader){this._loader()}if(this.options.thumbnails){this._thumbnails()}this._preload()},go:function(B,A){if((this.slide-1+this.data.images.length)%this.data.images.length==B||$time()<this.transition){return }$clear(this.timer);this.delay=0;this.direction=(A)?A:((B<this.slide)?"right":"left");this.slide=B;if(this.preloader){this.preloader=this.preloader.destroy()}this._preload(this.options.fast==2||(this.options.fast==1&&this.paused))},first:function(){this.prev(true)},prev:function(A){var B=0;if(!A){if(this.options.random){if(this.showed.i<2){return }this.showed.i-=2;B=this.showed.array[this.showed.i]}else{B=(this.slide-2+this.data.images.length)%this.data.images.length}}this.go(B,"right")},pause:function(A){if($chk(A)){this.paused=(A)?false:true}if(this.paused){this.paused=false;this.delay=this.transition=0;this.timer=this._preload.delay(100,this);[this.a,this.b].each(function(B){["morph","tween"].each(function(C){if(this.retrieve(C)){this.get(C).resume()}},B)});if(this.options.controller){this.slideshow.getElement("."+this.classes.pause).removeClass(this.classes.play)}}else{this.paused=true;this.delay=Number.MAX_VALUE;this.transition=0;$clear(this.timer);[this.a,this.b].each(function(B){["morph","tween"].each(function(C){if(this.retrieve(C)){this.get(C).pause()}},B)});if(this.options.controller){this.slideshow.getElement("."+this.classes.pause).addClass(this.classes.play)}}},next:function(A){var B=(A)?this.data.images.length-1:this.slide;this.go(B,"left")},last:function(){this.next(true)},load:function(C){this.firstrun=true;this.showed={array:[],i:0};if($type(C)=="array"){this.options.captions=false;C=new Array(C.length).associate(C.map(function(H,G){return H+"?"+G}))}this.data={images:[],captions:[],hrefs:[],thumbnails:[]};for(var E in C){var D=C[E]||{};var B=(D.caption)?D.caption.trim():"";var A=(D.href)?D.href.trim():((this.options.linked)?this.options.hu+E:this.options.href);var F=(D.thumbnail)?D.thumbnail.trim():E.replace(this.options.replace[0],this.options.replace[1]);this.data.images.push(E);this.data.captions.push(B);this.data.hrefs.push(A);this.data.thumbnails.push(F)}if(this.options.random){this.slide=$random(0,this.data.images.length-1)}if(this.options.thumbnails&&this.slideshow.retrieve("thumbnails")){this._thumbnails()}if(this.slideshow.retrieve("images")){[this.a,this.b].each(function(G){["morph","tween"].each(function(H){if(this.retrieve(H)){this.get(H).cancel()}},G)});this.slide=this.transition=0;this.go(0)}return this.data.images.length},destroy:function(A){this.events.each(function(C,B){C.each(function(D){document.removeEvent(B,D)})});this.pause(1);if(this.options.loader){$clear(this.slideshow.retrieve("loader").retrieve("timer"))}if(this.options.thumbnails){$clear(this.slideshow.retrieve("thumbnails").retrieve("timer"))}this.slideshow.uid=Native.UID++;if(A){this.slideshow[A]()}},_preload:function(A){if(!this.preloader){this.preloader=new Asset.image(this.options.hu+this.data.images[this.slide],{onload:function(){this.store("loaded",true)}})}if(this.preloader.retrieve("loaded")&&$time()>this.delay&&$time()>this.transition){if(this.stopped){if(this.options.captions){this.slideshow.retrieve("captions").get("morph").cancel().start(this.classes.get("captions","hidden"))}this.pause(1);if(this.end){this.fireEvent("end")}this.stopped=this.end=false;return }this.image=(this.counter%2)?this.b:this.a;this.image.set("styles",{display:"block",height:"auto",visibility:"hidden",width:"auto",zIndex:this.counter});["src","height","width"].each(function(D){this.image.set(D,this.preloader.get(D))},this);this._resize(this.image);this._center(this.image);var B=this.image.getParent();if(this.data.hrefs[this.slide]){ B.set("href",this.data.hrefs[this.slide]); B.set("target", "_blank");}else{B.erase("href")}var C=(this.data.captions[this.slide])?this.data.captions[this.slide].replace(/<.+?>/gm,"").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"'"):"";this.image.set("alt",C);if(this.options.titles){B.set("title",C)}if(this.options.loader){this.slideshow.retrieve("loader").fireEvent("hide")}if(this.options.captions){this.slideshow.retrieve("captions").fireEvent("update",A)}if(this.options.thumbnails){this.slideshow.retrieve("thumbnails").fireEvent("update",A)}this._show(A);this._loaded()}else{if($time()>this.delay&&this.options.loader){this.slideshow.retrieve("loader").fireEvent("show")}this.timer=(this.paused&&this.preloader.retrieve("loaded"))?null:this._preload.delay(100,this,A)}},_show:function(B){if(!this.image.retrieve("morph")){var C=(this.options.overlap)?{duration:this.options.duration,link:"cancel"}:{duration:this.options.duration/2,link:"chain"};$$(this.a,this.b).set("morph",$merge(C,{onStart:this._start.bind(this),onComplete:this._complete.bind(this),transition:this.options.transition}))}var E=this.classes.get("images",((this.direction=="left")?"next":"prev"));var F=this.classes.get("images","visible");var A=(this.counter%2)?this.a:this.b;if(B){A.get("morph").cancel().set(E);this.image.get("morph").cancel().set(F)}else{if(this.options.overlap){A.get("morph").set(F);this.image.get("morph").set(E).start(F)}else{var D=function(G,H){this.image.get("morph").set(G).start(H)}.pass([E,F],this);E=this.classes.get("images",((this.direction=="left")?"prev":"next"));A.get("morph").set(F).start(E).chain(D)}}},_loaded:function(){this.counter++;this.delay=(this.paused)?Number.MAX_VALUE:$time()+this.options.duration+this.options.delay;this.direction="left";this.transition=(this.options.fast==2||(this.options.fast==1&&this.paused))?0:$time()+this.options.duration;if(this.slide+1==this.data.images.length&&!this.options.loop&&!this.options.random){this.stopped=this.end=true}if(this.options.random){this.showed.i++;if(this.showed.i>=this.showed.array.length){var A=this.slide;if(this.showed.array.getLast()!=A){this.showed.array.push(A)}while(this.slide==A){this.slide=$random(0,this.data.images.length-1)}}else{this.slide=this.showed.array[this.showed.i]}}else{this.slide=(this.slide+1)%this.data.images.length}if(this.image.getStyle("visibility")!="visible"){(function(){this.image.setStyle("visibility","visible")}).delay(1,this)}if(this.preloader){this.preloader=this.preloader.destroy()}this._preload()},_center:function(A){if(this.options.center){var B=A.getSize();A.set("styles",{left:(B.x-this.width)/-2,top:(B.y-this.height)/-2})}},_resize:function(B){if(this.options.resize){var D=this.preloader.get("height"),A=this.preloader.get("width");var E=this.height/D,C=this.width/A,F;if(this.options.resize=="length"){F=(E>C)?C:E}else{F=(E>C)?E:C}B.set("styles",{height:Math.ceil(D*F),width:Math.ceil(A*F)})}},_start:function(){this.fireEvent("start")},_complete:function(){if(this.firstrun&&this.options.paused){this.firstrun=false;this.pause(1)}this.fireEvent("complete")},_captions:function(){if(this.options.captions===true){this.options.captions={}}var B=this.slideshow.getElement(this.classes.get("captions"));var A=(B)?B.empty():new Element("div",{"class":this.classes.get("captions").substr(1)}).inject(this.slideshow);A.set({events:{update:function(D){var C=this.slideshow.retrieve("captions");var F=(this.data.captions[this.slide]==="");if(D){var G=(F)?"hidden":"visible";C.set("html",this.data.captions[this.slide]).get("morph").cancel().set(this.classes.get("captions",G))}else{var E=(F)?$empty:function(H){this.slideshow.retrieve("captions").set("html",this.data.captions[H]).morph(this.classes.get("captions","visible"))}.pass(this.slide,this);C.get("morph").cancel().start(this.classes.get("captions","hidden")).chain(E)}}.bind(this)},morph:$merge(this.options.captions,{link:"chain"})});this.slideshow.store("captions",A)},_controller:function(){if(this.options.controller===true){this.options.controller={}}var E=this.slideshow.getElement(this.classes.get("controller"));var A=(E)?E.empty():new Element("div",{"class":this.classes.get("controller").substr(1)}).inject(this.slideshow);var C=new Element("ul").inject(A);$H({first:"Shift + Leftwards Arrow",prev:"Leftwards Arrow",pause:"P",next:"Rightwards Arrow",last:"Shift + Rightwards Arrow"}).each(function(J,I){var G=new Element("li",{"class":(I=="pause"&&this.options.paused)?this.classes.play+" "+this.classes[I]:this.classes[I]}).inject(C);var H=this.slideshow.retrieve(I,new Element("a",{title:((I=="pause")?this.classes.play.capitalize()+" / ":"")+this.classes[I].capitalize()+" ["+J+"]"}).inject(G));H.set("events",{click:function(K){this[K]()}.pass(I,this),mouseenter:function(K){this.addClass(K)}.pass(this.classes.active,H),mouseleave:function(K){this.removeClass(K)}.pass(this.classes.active,H)})},this);A.set({events:{hide:function(G){if(!this.retrieve("hidden")){this.store("hidden",true).morph(G)}}.pass(this.classes.get("controller","hidden"),A),show:function(G){if(this.retrieve("hidden")){this.store("hidden",false).morph(G)}}.pass(this.classes.get("controller","visible"),A)},morph:$merge(this.options.controller,{link:"cancel"})}).store("hidden",false);var B=function(H){if(["left","right","p"].contains(H.key)){var G=this.slideshow.retrieve("controller");if(G.retrieve("hidden")){G.get("morph").set(this.classes.get("controller","visible"))}switch(H.key){case"left":this.slideshow.retrieve((H.shift)?"first":"prev").fireEvent("mouseenter");break;case"right":this.slideshow.retrieve((H.shift)?"last":"next").fireEvent("mouseenter");break;default:this.slideshow.retrieve("pause").fireEvent("mouseenter");break}}}.bind(this);this.events.keydown.push(B);var F=function(H){if(["left","right","p"].contains(H.key)){var G=this.slideshow.retrieve("controller");if(G.retrieve("hidden")){G.store("hidden",false).fireEvent("hide")}switch(H.key){case"left":this.slideshow.retrieve((H.shift)?"first":"prev").fireEvent("mouseleave");break;case"right":this.slideshow.retrieve((H.shift)?"last":"next").fireEvent("mouseleave");break;default:this.slideshow.retrieve("pause").fireEvent("mouseleave");break}}}.bind(this);this.events.keyup.push(F);var D=function(H){var G=this.slideshow.retrieve("images").getCoordinates();if(H.page.x>G.left&&H.page.x<G.right&&H.page.y>G.top&&H.page.y<G.bottom){this.slideshow.retrieve("controller").fireEvent("show")}else{this.slideshow.retrieve("controller").fireEvent("hide")}}.bind(this);this.events.mousemove.push(D);document.addEvents({keydown:B,keyup:F,mousemove:D});this.slideshow.retrieve("controller",A).fireEvent("hide")},_loader:function(){if(this.options.loader===true){this.options.loader={}}var A=new Element("div",{"class":this.classes.get("loader").substr(1),morph:$merge(this.options.loader,{link:"cancel"})}).store("hidden",false).store("i",1).inject(this.slideshow.retrieve("images"));if(this.options.loader.animate){for(var B=0;B<this.options.loader.animate[1];B++){img=new Asset.image(this.options.loader.animate[0].replace(/#/,B))}if(Browser.Engine.trident4&&this.options.loader.animate[0].contains("png")){A.setStyle("backgroundImage","none")}}A.set("events",{animate:function(){var C=this.slideshow.retrieve("loader");var E=(C.retrieve("i").toInt()+1)%this.options.loader.animate[1];C.store("i",E);var D=this.options.loader.animate[0].replace(/#/,E);if(Browser.Engine.trident4&&this.options.loader.animate[0].contains("png")){C.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+D+'", sizingMethod="scale")'}else{C.setStyle("backgroundImage","url("+D+")")}}.bind(this),hide:function(){var C=this.slideshow.retrieve("loader");if(!C.retrieve("hidden")){C.store("hidden",true).morph(this.classes.get("loader","hidden"));if(this.options.loader.animate){$clear(C.retrieve("timer"))}}}.bind(this),show:function(){var C=this.slideshow.retrieve("loader");if(C.retrieve("hidden")){C.store("hidden",false).morph(this.classes.get("loader","visible"));if(this.options.loader.animate){C.store("timer",function(){this.fireEvent("animate")}.periodical(50,C))}}}.bind(this)});this.slideshow.retrieve("loader",A).fireEvent("hide")},_thumbnails:function(){if(this.options.thumbnails===true){this.options.thumbnails={}}var C=this.slideshow.getElement(this.classes.get("thumbnails"));var E=(C)?C.empty():new Element("div",{"class":this.classes.get("thumbnails").substr(1)}).inject(this.slideshow);E.setStyle("overflow","hidden");var A=new Element("ul",{tween:{link:"cancel"}}).inject(E);this.data.thumbnails.each(function(J,I){var F=new Element("li").inject(A);var G=new Element("a",{events:{click:function(K){this.go(K);return false}.pass(I,this),loaded:function(){this.data.thumbnails.pop();if(!this.data.thumbnails.length){var O=E.getCoordinates();var M=E.retrieve("props");var K=0,N=M[1],L=M[2];E.getElements("li").each(function(P){var P=P.getCoordinates();if(P[N]>K){K=P[N]}},this);E.store("limit",O[L]+O[M[0]]-K)}}.bind(this)},href:this.options.hu+this.data.images[I],morph:$merge(this.options.thumbnails,{link:"cancel"})}).inject(F);if(this.data.captions[I]&&this.options.titles){G.set("title",this.data.captions[I].replace(/<.+?>/gm,"").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"'"))}var H=new Asset.image(this.options.hu+J,{onload:function(){this.fireEvent("loaded")}.bind(G)}).inject(G)},this);E.set("events",{scroll:function(H,K){var F=this.getCoordinates();var L=this.getElement("ul").getPosition();var N=this.retrieve("props");var I=N[3],R,O=N[0],T=N[2],P;var S=this.getElement("ul").get("tween",{property:O});if($chk(H)){var Q=this.getElements("li")[H].getCoordinates();R=F[O]+(F[T]/2)-(Q[T]/2)-Q[O];P=(L[I]-F[O]+R).limit(this.retrieve("limit"),0);if(K){S.set(P)}else{S.start(P)}}else{var G=F[N[2]]/3,M=this.retrieve("page"),J=-0.2;if(M[I]<(F[O]+G)){R=(M[I]-F[O]-G)*J}else{if(M[I]>(F[O]+F[T]-G)){R=(M[I]-F[O]-F[T]+G)*J}}if(R){P=(L[I]-F[O]+R).limit(this.retrieve("limit"),0);S.set(P)}}}.bind(E),update:function(F){var G=this.slideshow.retrieve("thumbnails");G.getElements("a").each(function(H,I){if(I==this.slide){if(!H.retrieve("active",false)){H.store("active",true);var K=this.classes.get("thumbnails","active");if(F){H.get("morph").set(K)}else{H.morph(K)}}}else{if(H.retrieve("active",true)){H.store("active",false);var J=this.classes.get("thumbnails","inactive");if(F){H.get("morph").set(J)}else{H.morph(J)}}}},this);if(!G.retrieve("mouseover")){G.fireEvent("scroll",[this.slide,F])}}.bind(this)});var D=E.getCoordinates();E.store("props",(D.height>D.width)?["top","bottom","height","y"]:["left","right","width","x"]);var B=function(F){var G=this.getCoordinates();if(F.page.x>G.left&&F.page.x<G.right&&F.page.y>G.top&&F.page.y<G.bottom){this.store("page",F.page);if(!this.retrieve("mouseover")){this.store("mouseover",true);this.store("timer",function(){this.fireEvent("scroll")}.periodical(50,this))}}else{if(this.retrieve("mouseover")){this.store("mouseover",false);$clear(this.retrieve("timer"))}}}.bind(E);this.events.mousemove.push(B);document.addEvent("mousemove",B);this.slideshow.store("thumbnails",E)}});
*/

(function(){
	Slideshow = new Class({
		Implements: [Chain, Events, Options],

		options: {/*
			onComplete: $empty,
			onEnd: $empty,
			onStart: $empty,*/
		    accesskeys: {'first': {'key': 'shift left', 'label': 'Shift + Leftwards Arrow'}, 'prev': {'key': 'left', 'label': 'Leftwards Arrow'}, 'pause': {'key': 'p', 'label': 'P'}, 'next': {'key': 'right', 'label': 'Rightwards Arrow'}, 'last': {'key': 'shift right', 'label': 'Shift + Rightwards Arrow'}},
			captions: true,
			center: true,
			classes: [],
			controller: true,
			data: null,
			delay: 2000,
			duration: 1000,
			fast: false,
			height: false,
			href: '',
			hu: '',
			linked: false,
			loader: true,
			loop: true,
			match: /\?slide=(\d+)$/,
			overlap: true,
			paused: false,
			random: false,
			replace: [/(\.[^\.]+)$/, 't$1'],
			resize: 'fill',
			slide: 0,
			thumbnails: true,
			titles: false,
			transition: 'sine:in:out',
			width: false
		},

	/**
	Constructor: initialize
		Creates an instance of the Slideshow class.

	Arguments:
		element - (element) The wrapper element.
		data - (array or object) The images and optional thumbnails, captions and links for the show.
		options - (object) The options below.

	Syntax:
		var myShow = new Slideshow(element, data, options);
	*/

		initialize: function(el, data, options){
			this.setOptions(options);
			this.el = document.id(el);
			if (!this.el)
				return;
			var match = window.location.href.match(this.options.match);
			this.slide = this._slide = this.options.match && match ? match[1].toInt() : this.options.slide;
			this.counter = this.delay = this.duration = 0;
			this.direction = 'left';
			this.cache = {};
			this.paused = false;
			if (!this.options.overlap)
				this.options.duration *= 2;
			var anchor = this.el.getElement('a') || new Element('a');
			if (!this.options.href)
				this.options.href = anchor.get('href') || '';
			if (this.options.hu.length && !this.options.hu.test(/\/$/))
				this.options.hu += '/';
			if (this.options.fast === true)
				this.options.fast = 2;

			// styles

			var keys = ['slideshow', 'first', 'prev', 'play', 'pause', 'next', 'last', 'images', 'captions', 'controller', 'thumbnails', 'hidden', 'visible', 'inactive', 'active', 'loader'],
				values = keys.map(function(key, i){
				return this.options.classes[i] || key;
			}, this);
			this.classes = values.associate(keys);
			this.classes.get = function(){
				var str = '.' + this.slideshow;
				for (var i = 0, l = arguments.length; i < l; i++)
					str += '-' + this[arguments[i]];
				return str;
			}.bind(this.classes);

			// data

			if (!data){
				this.options.hu = '';
				data = {};
				var thumbnails = this.el.getElements(this.classes.get('thumbnails') + ' img');
				this.el.getElements(this.classes.get('images') + ' img').each(function(img, i){
					var src = img.src,
						caption = img.alt || img.title,
						href = img.getParent().href,
						thumbnail = thumbnails[i] ? thumbnails[i].src : '';
					data[src] = {'caption': caption, 'href': href, 'thumbnail': thumbnail};
				});
			}
			var loaded = this.load(data);
			if (!loaded)
				return;

			// events

			this.events = {};
			this.events.push = function(type, fn){
				if (!this[type])
					this[type] = [];
				this[type].push(fn);
				document.addEvent(type, fn);
				return this;
			}.bind(this.events);

			this.accesskeys = {};
			for (action in this.options.accesskeys){
				var obj = this.options.accesskeys[action];
				this.accesskeys[action] = accesskey = {'label': obj.label};
				['shift', 'control', 'alt'].each(function(modifier){
					var re = new RegExp(modifier, 'i');
					accesskey[modifier] = obj.key.test(re);
					obj.key = obj.key.replace(re, '');
				});
				accesskey.key = obj.key.trim();
			}

			this.events.push('keyup', function(e){
				Object.each(this.accesskeys, function(accesskey, action){
					if (e.key == accesskey.key && e.shift == accesskey.shift && e.control == accesskey.control && e.alt == accesskey.alt)
						this[action]();
				}, this);
			}.bind(this));

			// required elements

			var el = this.el.getElement(this.classes.get('images')),
				img = this.el.getElement('img') || new Element('img'),
				images = el ? el.empty() : new Element('div', {'class': this.classes.get('images').substr(1)}).inject(this.el),
				div = images.getSize();
			this.height = this.options.height || div.y;
			this.width = this.options.width || div.x;
			images.set({'styles': {'height': this.height, 'width': this.width}});
			this.el.store('images', images);
			this.a = this.image = img;
			if (Browser.ie && Browser.version >= 7)
				this.a.style.msInterpolationMode = 'bicubic';
			this.a.set('styles', {'display': 'none'});
			this.b = this.a.clone();
			[this.a, this.b].each(function(img){
				anchor.clone().cloneEvents(anchor).grab(img).inject(images);
			});

			// optional elements

			if (this.options.captions)
	 			new Caption(this);
			if (this.options.controller)
				new Controller(this);
			if (this.options.loader)
	 			new Loader(this);
			if (this.options.thumbnails)
				new Thumbnails(this);

			// begin show

			this._preload();
		},

	/**
	Public method: go
		Jump directly to a slide in the show.

	Arguments:
		n - (integer) The index number of the image to jump to, 0 being the first image in the show.

	Syntax:
		myShow.go(n);
	*/

		go: function(n, direction){
			if ((this.slide + this.data.images.length) % this.data.images.length == n || Date.now() < this.duration)
				return;
			clearTimeout(this.timer);
			this.delay = 0;
			this.direction = direction ? direction : (n < this._slide ? 'right' : 'left');
			this.slide = this._slide = n;
			if (this.preloader)
				this.preloader = this.preloader.destroy();
			this._preload(this.options.fast == 2 || (this.options.fast == 1 && this.paused));
		},

	/**
	Public method: first
		Goes to the first image in the show.

	Syntax:
		myShow.first();
	*/

		first: function(){
			this.prev(true);
		},

	/**
	Public method: prev
		Goes to the previous image in the show.

	Syntax:
		myShow.prev();
	*/

		prev: function(first){
			var n = 0;
			if (!first){
				if (this.options.random){
					if (this.showed.i < 2)
						return;
					this.showed.i -= 2;
					n = this.showed.array[this.showed.i];
				}
				else
					n = (this.slide - 1 + this.data.images.length) % this.data.images.length;
			}
			this.go(n, 'right');
		},

	/**
	Public method: pause
		Toggles play / pause state of the show.

	Arguments:
		p - (undefined, 1 or 0) Call pause with no arguments to toggle the pause state. Call pause(1) to force pause, or pause(0) to force play.

	Syntax:
		myShow.pause(p);
	*/

		pause: function(p){
			if (p != undefined)
				this.paused = p ? false : true;
			if (this.paused){
				this.paused = false;
				this.duration = Date.now() + this.duration;
				this.timer = this._preload.delay(100, this);
				[this.a, this.b].each(function(img){
					['morph', 'tween'].each(function(p){
						if (this.retrieve(p)) this.get(p).resume();
					}, img);
				});
				if (this.controller)
					this.el.retrieve('pause').getParent().removeClass(this.classes.play);
			}
			else {
				this.paused = true;
				this.duration = this.duration - Date.now();
				clearTimeout(this.timer);
				[this.a, this.b].each(function(img){
					['morph', 'tween'].each(function(p){
						if (this.retrieve(p)) this.get(p).pause();
					}, img);
				});
				if (this.controller)
					this.el.retrieve('pause').getParent().addClass(this.classes.play);
			}
		},

	/**
	Public method: next
		Goes to the next image in the show.

	Syntax:
		myShow.next();
	*/

		next: function(last){
			var n = last ? this.data.images.length - 1 : this._slide;
			this.go(n, 'left');
		},

	/**
	Public method: last
		Goes to the last image in the show.

	Syntax:
		myShow.last();
	*/

		last: function(){
			this.next(true);
		},

	/**
	Public method: load
		Loads a new data set into the show: will stop the current show, rewind and rebuild thumbnails if applicable.

	Arguments:
		data - (array or object) The images and optional thumbnails, captions and links for the show.

	Syntax:
		myShow.load(data);
	*/

		load: function(data){
			this.firstrun = true;
			this.showed = {'array': [], 'i': 0};
			if (typeOf(data) == 'array'){
				this.options.captions = false;
				data = new Array(data.length).associate(data.map(function(image, i){ return image + '?' + i }));
			}
			this.data = {'images': [], 'captions': [], 'hrefs': [], 'thumbnails': [], 'targets': [], 'titles': []};
			for (var image in data){
				var obj = data[image] || {},
					image = this.options.hu + image,
					caption = obj.caption ? obj.caption.trim() : '',
					href = obj.href ? obj.href.trim() : (this.options.linked ? image : this.options.href),
					target = obj.target ? obj.target.trim() : '_self',
					thumbnail = obj.thumbnail ? this.options.hu + obj.thumbnail.trim() : image.replace(this.options.replace[0], this.options.replace[1]),
					title = caption.replace(/<.+?>/gm, '').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, "'");
				this.data.images.push(image);
				this.data.captions.push(caption);
				this.data.hrefs.push(href);
				this.data.targets.push(target);
				this.data.thumbnails.push(thumbnail);
				this.data.titles.push(title);
			}
			if (this.options.random)
				this.slide = this._slide = Number.random(0, this.data.images.length - 1);

			// only run when data is loaded dynamically into an existing slideshow instance

			if (this.options.thumbnails && this.el.retrieve('thumbnails'))
				this._thumbnails();
			if (this.el.retrieve('images')){
				[this.a, this.b].each(function(img){
					['morph', 'tween'].each(function(p){
						if (this.retrieve(p)) this.get(p).cancel();
					}, img);
				});
				this.slide = this._slide = this.duration = 0;
				this.go(0);
			}
			return this.data.images.length;
		},

	/**
	Public method: destroy
		Destroys a Slideshow instance.

	Arguments:
		p - (string) The images and optional thumbnails, captions and links for the show.

	Syntax:
		myShow.destroy(p);
	*/

		destroy: function(p){
			Object.each(this.events, function(array, e){
				array.each(function(fn){ document.removeEvent(e, fn); });
			});
			this.pause(1);
			if (this.options.loader)
				clearTimeout(this.el.retrieve('loader').retrieve('timer'));
			if (this.options.thumbnails)
				clearTimeout(this.el.retrieve('thumbnails').retrieve('timer'));
			this.el.uid = Native.UID++;
			if (p)
				this.el[p]();
		},

	/**
	Private method: preload
		Preloads the next slide in the show, once loaded triggers the show, updates captions, thumbnails, etc.
	*/

		_preload: function(fast){
			var src = this.data.images[this._slide].replace(/([^?]+).*/, '$1'),
				cached = loaded = !!this.cache[src];
			if (!cached){
				if (!this.preloader)
				 	this.preloader = new Asset.image(src, {'onload': function(){
						this.store('loaded', true);
					}});
				loaded = this.preloader.retrieve('loaded') && this.preloader.get('width');
			}
			if (loaded && Date.now() > this.delay && Date.now() > this.duration){
				var src = this.data.images[this._slide].replace(/([^?]+).*/, '$1');
				if (this.preloader){
					this.cache[src] = {
						'height': this.preloader.get('height'),
						'src': src,
						'width': this.preloader.get('width')
					}
				}
				if (this.stopped){
					if (this.options.captions)
						this.caption.get('morph').cancel().start(this.classes.get('captions', 'hidden'));
					this.pause(1);
					if (this.end)
						this.fireEvent('end');
					this.stopped = this.end = false;
					return;
				}
				this.image = this.counter % 2 ? this.b : this.a;
				this.image.set('styles', {'display': 'block', 'height': 'auto', 'visibility': 'hidden', 'width': 'auto', 'zIndex': this.counter});
				this.image.set(this.cache[src]);
				if (this.options.resize)
					this._resize(this.image);
				if (this.options.center)
					this._center(this.image);
				var anchor = this.image.getParent();
				if (this.data.hrefs[this._slide]){
					anchor.set('href', this.data.hrefs[this._slide]);
					anchor.set('target', this.data.targets[this._slide]);
				}
				else {
					anchor.erase('href');
					anchor.erase('target');
				}
				var title = this.data.titles[this._slide];
				this.image.set('alt', title);
				if (this.options.titles)
					anchor.set('title', title);
				if (this.options.loader)
					this.loader.fireEvent('hide');
				if (this.options.captions)
					this.caption.fireEvent('update', fast);
				if (this.options.thumbnails)
					this.thumbnails.fireEvent('update', fast);
				this._show(fast);
				this._loaded();
			}
			else {
				if (Date.now() > this.delay && this.options.loader)
					this.loader.fireEvent('show');
				this.timer = this._preload.delay(50, this, fast);
			}
		},

	/**
	Private method: show
		Does the slideshow effect.
	*/

		_show: function(fast){
			if (!this.image.retrieve('morph')){
				var options = this.options.overlap ? {'duration': this.options.duration, 'link': 'cancel'} : {'duration': this.options.duration / 2, 'link': 'chain'};
				$$(this.a, this.b).set('morph', Object.merge(options, {'onStart': this._start.bind(this), 'onComplete': this._complete.bind(this), 'transition': this.options.transition}));
			}
			var hidden = this.classes.get('images', (this.direction == 'left' ? 'next' : 'prev')),
				visible = this.classes.get('images', 'visible'),
				img = this.counter % 2 ? this.a : this.b;
			if (fast){
				img.get('morph').cancel().set(hidden);
				this.image.get('morph').cancel().set(visible);
			}
			else {
				if (this.options.overlap){
					img.get('morph').set(visible);
					this.image.get('morph').set(hidden).start(visible);
				}
				else {
					var fn = function(hidden, visible){
						this.image.get('morph').start(visible);
					}.pass([hidden, visible], this);
					hidden = this.classes.get('images', (this.direction == 'left' ? 'prev' : 'next'));
					if (this.firstrun)
						return fn();
					this.image.get('morph').set(hidden);
					img.get('morph').set(visible).start(hidden).chain(fn);
				}
			}
		},

	/**
	Private method: loaded
		Run after the current image has been loaded, sets up the next image to be shown.
	*/

		_loaded: function(){
			this.counter++;
			this.delay = Date.now() + this.options.duration + this.options.delay;
			this.direction = 'left';
			this.duration = this.options.fast == 2 || (this.options.fast == 1 && this.paused) ? 0 : Date.now() + this.options.duration;
			if (this._slide == (this.data.images.length - 1) && !this.options.loop && !this.options.random)
				this.stopped = this.end = true;
			if (this.options.random){
				this.showed.i++;
				if (this.showed.i >= this.showed.array.length){
					var n = this._slide;
					if (this.showed.array.getLast() != n) this.showed.array.push(n);
					while (this._slide == n)
						this.slide = this._slide = Number.random(0, this.data.images.length - 1);
				}
				else
					this.slide = this._slide = this.showed.array[this.showed.i];
			}
			else {
				this.slide = this._slide;
				this._slide = (this.slide + 1) % this.data.images.length;
			}
			if (this.image.getStyle('visibility') != 'visible')
				(function(){ this.image.setStyle('visibility', 'visible'); }).delay(1, this);
			if (this.preloader)
				this.preloader = this.preloader.destroy();
			this._preload();
		},

	/**
	Private method: center
		Center an image.
	*/

		_center: function(img){
			var size = img.getSize(),
				h = size.y, w = size.x;
			img.set('styles', {'left': (w - this.width) / -2, 'top': (h - this.height) / -2});
		},

	/**
	Private method: resize
		Resizes an image.
	*/

		_resize: function(img){
			var size = img.getSize(),
				h = size.y, w = size.x,
				dh = this.height / h, dw = this.width / w;
			if (this.options.resize == 'fit')
				dh = dw = dh > dw ? dw : dh;
			if (this.options.resize == 'fill')
				dh = dw = dh > dw ? dh : dw;
			img.set('styles', {'height': Math.ceil(h * dh), 'width': Math.ceil(w * dw)});
		},

	/**
	Private method: start
		Callback on start of slide change.
	*/

		_start: function(){
			this.fireEvent('start');
		},

	/**
	Private method: complete
		Callback on start of slide change.
	*/

		_complete: function(){
			if ((this.firstrun && this.options.paused) || this.paused){
				this.pause(1);
			}
			this.firstrun = false;
			this.fireEvent('complete');
		}
	});

	/**
	Private method: captions
		Builds the optional caption element, adds interactivity.
		This method can safely be removed if the captions option is not enabled.
	*/

	var Caption = new Class({
		Implements: [Chain, Events, Options],

		options: {/*
			duration: 500,
			fps: 50,
			transition: 'sine:in:out',
			unit: false, */
			link: 'cancel'
		},

		initialize: function(slideshow){
			if (!slideshow)
				return;
			var options = slideshow.options.captions;
			if (options === true)
				options = {};
			this.setOptions(options);
			var el = slideshow.el.getElement(slideshow.classes.get('captions')),
				caption = el ? el.dispose().empty()
					: new Element('div', {'class': slideshow.classes.get('captions').substr(1)});
			slideshow.caption = caption;
			caption.set({
		    	'aria-busy': false,
		    	'aria-hidden': false,
				'events': { 'update': this.update.bind(slideshow) },
				'morph': this.options,
				'role': 'description'
			});
		    if (!caption.get('id'))
		    	caption.set('id', 'Slideshow-' + Date.now());
		    slideshow.el.retrieve('images').set('aria-labelledby', caption.get('id'));
			caption.inject(slideshow.el);
		},

		update: function(fast){
		    var empty = (this.data.captions[this._slide] === '');
		    if (fast){
		      var p = empty ? 'hidden' : 'visible';
		      this.caption.set({'aria-hidden': empty, 'html': this.data.captions[this._slide]}).get('morph').cancel().set(this.classes.get('captions', p));
		    }
		    else {
		      var fn1 = empty ? function(){} : function(n){
		        this.caption.set('html', this.data.captions[n]).morph(this.classes.get('captions', 'visible'));
		      }.pass(this._slide, this);
		      var fn2 = function(){
		        this.caption.set('aria-busy', false);
		      }.bind(this);
		      this.caption.set('aria-busy', true).get('morph').cancel().start(this.classes.get('captions', 'hidden')).chain(fn1, fn2);
		    }
		}
	});

	/**
	Private method: controller
	  Builds the optional controller element, adds interactivity.
	  This method can safely be removed if the controller option is not enabled.
	*/

	var Controller = new Class({
		Implements: [Chain, Events, Options],

		options: {/*
			duration: 500,
			fps: 50,
			transition: 'sine:in:out',
			unit: false, */
			link: 'cancel'
		},

		initialize: function(slideshow){
			if (!slideshow)
				return;
			var options = slideshow.options.captions;
			if (options === true)
				options = {};
			this.setOptions(options);
			var el = slideshow.el.getElement(slideshow.classes.get('controller')),
				controller = el ? el.dispose().empty()
					: new Element('div', {'class': slideshow.classes.get('controller').substr(1)});
			slideshow.controller = controller;
			controller.set({
				'aria-hidden': false,
				'role': 'menubar'
			});
			var ul = new Element('ul', {'role': 'menu'}).inject(controller),
				i = 0;
			Object.each(slideshow.accesskeys, function(accesskey, action){
				var li = new Element('li', {
					'class': (action == 'pause' && this.options.paused) ? this.classes.play + ' ' + this.classes[action] : this.classes[action]
				}).inject(ul);
				var a = this.el.retrieve(action, new Element('a', {
					'role': 'menuitem', 'tabindex': i++, 'title': accesskey.label
				}).inject(li));
				a.set('events', {
					'click': function(action){
						this[action]()
					}.pass(action, this),
					'mouseenter': function(active){
						this.addClass(active)
					}.pass(this.classes.active, a),
					'mouseleave': function(active){
						this.removeClass(active)
					}.pass(this.classes.active, a)
				});
			}, slideshow);
			controller.set({
				'events': {
					'hide': this.hide.pass(slideshow.classes.get('controller', 'hidden'), controller),
					'show': this.show.pass(slideshow.classes.get('controller', 'visible'), controller)
				},
				'morph': this.options
			}).store('hidden', false);
			slideshow.events
				.push('keydown', this.keydown.bind(slideshow))
				.push('keyup',	this.keyup.bind(slideshow))
				.push('mousemove',	this.mousemove.bind(slideshow));
			controller.inject(slideshow.el).fireEvent('hide');
		},

		hide: function(hidden){
			if (this.get('aria-hidden') == 'false')
				this.set('aria-hidden', true).morph(hidden);
		},

		keydown: function(e){
			Object.each(this.accesskeys, function(accesskey, action){
				if (e.key == accesskey.key && e.shift == accesskey.shift && e.control == accesskey.control && e.alt == accesskey.alt && e.meta == accesskey.meta){
					if (this.controller.get('aria-hidden') == 'true')
						this.controller.get('morph').set(this.classes.get('controller', 'visible'));
					this.el.retrieve(action).fireEvent('mouseenter');
				}
			}, this);
		},

		keyup: function(e){
			Object.each(this.accesskeys, function(accesskey, action){
				if (e.key == accesskey.key && e.shift == accesskey.shift && e.control == accesskey.control && e.alt == accesskey.alt && e.meta == accesskey.meta){
					if (this.controller.get('aria-hidden') == 'true')
						this.controller.set('aria-hidden', false).fireEvent('hide');
					this.el.retrieve(action).fireEvent('mouseleave');
				}
			}, this);
		},

		mousemove: function(e){
			var images = this.el.retrieve('images').getCoordinates(),
				action = (e.page.x > images.left && e.page.x < images.right && e.page.y > images.top && e.page.y < images.bottom) ? 'show' : 'hide';
			this.controller.fireEvent(action);
		},

		show: function(visible){
			if (this.get('aria-hidden') == 'true')
				this.set('aria-hidden', false).morph(visible);
		}
	});

	/**
	Private method: loader
		Builds the optional loader element, adds interactivity.
		This method can safely be removed if the loader option is not enabled.
	*/

	var Loader = new Class({
		Implements: [Chain, Events, Options],

		options: {/*
			duration: 500,
			transition: 'sine:in:out',
			unit: false, */
			fps: 20,
			link: 'cancel'
		},

		initialize: function(slideshow){
			if (!slideshow)
				return;
			var options = slideshow.options.loader;
			if (options === true)
				options = {};
			this.setOptions(options);
			var loader = new Element('div', {
				'aria-hidden': false,
				'class': slideshow.classes.get('loader').substr(1),
				'morph': this.options,
				'role': 'progressbar'
			}).store('animate', false).store('i', 0).store('delay', 1000 / this.options.fps).inject(slideshow.el);
			slideshow.loader = loader;
			var url = loader.getStyle('backgroundImage').replace(/url\(['"]?(.*?)['"]?\)/, '$1').trim();
			if (url){
				if (url.test(/\.png$/) && Browser.ie && Browser.version < 7)
					loader.setStyles({'backgroundImage': 'none', 'filter': 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + url + '", sizingMethod="crop")'});
				new Asset.image(url, {'onload': function(){
					var size = loader.getSize(),
						width = this.get('width'),
						height = this.get('height');
					if (width > size.x)
						loader.store('x', size.x).store('animate', 'x').store('frames', (width / size.x).toInt());
					if (height > size.y)
						loader.store('y', size.y).store('animate', 'y').store('frames', (height / size.y).toInt());
				}});
			}
			loader.set('events', {
				'animate': this.animate.bind(loader),
				'hide': this.hide.pass(slideshow.classes.get('loader', 'hidden'), loader),
				'show': this.show.pass(slideshow.classes.get('loader', 'visible'), loader)
			});
			loader.fireEvent('hide');
		},

		animate: function(){
			var animate = this.retrieve('animate');
			if (!animate)
				return;
			var i = (this.retrieve('i').toInt() + 1) % this.retrieve('frames');
			this.store('i', i);
			var n = (i * this.retrieve(animate)) + 'px';
			if (animate == 'x')
				this.setStyle('backgroundPosition', n + ' 0px');
			if (animate == 'y')
				this.setStyle('backgroundPosition', '0px ' + n);
		},

		hide: function(hidden){
			if (this.get('aria-hidden') == 'false'){
				this.set('aria-hidden', true).morph(hidden);
				if (this.retrieve('animate'))
					clearTimeout(this.retrieve('timer'));
			}
		},

		show: function(visible){
			if (this.get('aria-hidden') == 'true'){
				this.set('aria-hidden', false).morph(visible);
				if (this.retrieve('animate')){
					this.store('timer', function(){
						this.fireEvent('animate')
					}.periodical(this.retrieve('delay'), this));
				}
			}
		}
	});

	/**
	Private method: thumbnails
		Builds the optional thumbnails element, adds interactivity.
		This method can safely be removed if the thumbnails option is not enabled.
	*/

	var Thumbnails = new Class({
		Implements: [Chain, Events, Options],

		options: {/*
			duration: 500,
			transition: 'sine:in:out',
			unit: false, */
			columns: null,
			fps: 50,
			link: 'cancel',
			position: null,
			rows: null,
			scroll: null
		},

		initialize: function(slideshow){
			var options = (slideshow.options.thumbnails === true) ? {}
				: slideshow.options.thumbnails;
			this.setOptions(options);
			var el = slideshow.el.getElement(slideshow.classes.get('thumbnails')),
				thumbnails = el ? el.empty()
					: new Element('div', {'class': slideshow.classes.get('thumbnails').substr(1)});
			slideshow.thumbnails = thumbnails;
			thumbnails.set({'role': 'menubar', 'styles': {'overflow': 'hidden'}});
			var uid = thumbnails.retrieve('uid', 'Slideshow-' + Date.now()),
				ul = new Element('ul', {'role': 'menu', 'styles': {'left': 0, 'position': 'absolute', 'top': 0}, 'tween': {'link': 'cancel'}}).inject(thumbnails);
			slideshow.data.thumbnails.each(function(thumbnail, i){
				var li = new Element('li', {'id': uid + i}).inject(ul),
					a = new Element('a', {
						'class': slideshow.classes.get('thumbnails', 'hidden').substr(1),
						'events': {
							'click': this.click.pass(i, slideshow)
						},
						'href': slideshow.data.images[i],
						'morph': this.options,
						'role': 'menuitem',
						'tabindex': i
					}).store('uid', i).inject(li);
				if (slideshow.options.titles)
					a.set('title', slideshow.data.titles[i]);
				new Asset.image(thumbnail, {
					'onload': this.onload.pass(i, slideshow)
				}).inject(a);
			}, this);
			thumbnails.set('events', {
				'scroll': this.scroll.bind(thumbnails),
				'update': this.update.bind(slideshow)
			});
			var coords = thumbnails.getCoordinates();
			if (!options.scroll)
				options.scroll = (coords.height > coords.width) ? 'y' : 'x';
			var props = (options.scroll == 'y') ? ['top', 'bottom', 'height', 'y', 'width']
				: ['left', 'right', 'width', 'x', 'height'];
			thumbnails.store('props', props).store('delay', 1000 / this.options.fps);
			slideshow.events.push('mousemove', this.mousemove.bind(thumbnails));
			thumbnails.inject(slideshow.el);
		},

		click: function(i){
			this.go(i);
			return false;
		},

		mousemove: function(e){
			var coords = this.getCoordinates();
			if (e.page.x > coords.left && e.page.x < coords.right && e.page.y > coords.top && e.page.y < coords.bottom){
				this.store('page', e.page);
				if (!this.retrieve('mouseover')){
					this.store('mouseover', true);
					this.store('timer', function(){this.fireEvent('scroll');}.periodical(this.retrieve('delay'), this));
				}
			}
			else {
				if (this.retrieve('mouseover')){
					this.store('mouseover', false);
					clearTimeout(this.retrieve('timer'));
				}
			}
		},

		onload: function(i){
			var thumbnails = this.thumbnails,
				a = thumbnails.getElements('a')[i];
			if (a){
				(function(a){
					var visible = i == this.slide ? 'active' : 'inactive';
					a.store('loaded', true).get('morph').set(this.classes.get('thumbnails', 'hidden')).start(this.classes.get('thumbnails', visible));
				}).delay(Math.max(1000 / this.data.thumbnails.length, 100), this, a);
			}
			if (thumbnails.retrieve('limit'))
				return;
			var props = thumbnails.retrieve('props'),
				options = this.options.thumbnails,
				pos = props[1],
				length = props[2],
				width = props[4],
				li = thumbnails.getElement('li:nth-child(' + (i + 1) + ')').getCoordinates();
			if (options.columns || options.rows){
				thumbnails.setStyles({'height': this.height, 'width': this.width});
				if (options.columns.toInt())
					thumbnails.setStyle('width', li.width * options.columns.toInt());
				if (options.rows.toInt())
					thumbnails.setStyle('height', li.height * options.rows.toInt());
			}
			var div = thumbnails.getCoordinates();
			if (options.position){
				if (options.position.test(/bottom|top/))
					thumbnails.setStyles({'bottom': 'auto', 'top': 'auto'}).setStyle(options.position, -div.height);
				if (options.position.test(/left|right/))
					thumbnails.setStyles({'left': 'auto', 'right': 'auto'}).setStyle(options.position, -div.width);
			}
			var units = Math.floor(div[width] / li[width]),
				x = Math.ceil(this.data.images.length / units),
				r = this.data.images.length % units,
				len = x * li[length],
				ul = thumbnails.getElement('ul').setStyle(length, len);
			ul.getElements('li').setStyles({'height': li.height, 'width': li.width});
			thumbnails.store('limit', div[length] - len);
		},

		scroll: function(n, fast){
			var div = this.getCoordinates(),
				ul = this.getElement('ul').getPosition(),
				props = this.retrieve('props'),
				axis = props[3], delta, pos = props[0], size = props[2], value,
				tween = this.getElement('ul').set('tween', {'property': pos}).get('tween');
			if (n != undefined){
				var uid = this.retrieve('uid'),
					li = document.id(uid + n).getCoordinates();
				delta = div[pos] + (div[size] / 2) - (li[size] / 2) - li[pos];
				value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
				if (fast)
					tween.set(value);
				else
					tween.start(value);
			}
			else{
				var area = div[props[2]] / 3,
					page = this.retrieve('page'),
					velocity = -(this.retrieve('delay') * 0.01);
				if (page[axis] < (div[pos] + area))
					delta = (page[axis] - div[pos] - area) * velocity;
				else if (page[axis] > (div[pos] + div[size] - area))
					delta = (page[axis] - div[pos] - div[size] + area) * velocity;
				if (delta){
					value = (ul[axis] - div[pos] + delta).limit(this.retrieve('limit'), 0);
					tween.set(value);
				}
			}
		},

		update: function(fast){
			var thumbnails = this.thumbnails,
				uid = thumbnails.retrieve('uid');
			thumbnails.getElements('a').each(function(a, i){
				if (a.retrieve('loaded')){
					if (a.retrieve('uid') == this._slide){
						if (!a.retrieve('active', false)){
							a.store('active', true);
							var active = this.classes.get('thumbnails', 'active');
							if (fast) a.get('morph').set(active);
							else a.morph(active);
						}
					}
					else {
						if (a.retrieve('active', true)){
							a.store('active', false);
							var inactive = this.classes.get('thumbnails', 'inactive');
							if (fast) a.get('morph').set(inactive);
							else a.morph(inactive);
						}
					}
				}
			}, this);
			if (!thumbnails.retrieve('mouseover'))
				thumbnails.fireEvent('scroll', [this._slide, fast]);
		}
	});
})();


