/*
 *  Sudo Slider ver 1.0.11 - jQuery plugin 
 *  Written by Erik Kristensen info@webbies.dk. 
 *  Based on Easy Slider 1.7 by Alen Grakalic http://cssglobe.com/post/5780/easy-slider-17-numeric-navigation-jquery-slider
 *	
 *	 Dual licensed under the MIT
 *	 and GPL licenses.
 * 
 *	 Built for jQuery library
 *	 http://jquery.com
 *
 */
 /* 
 TODO:
 Finding and fixing bugs. (No known bugs atm.) 

 TODO for next major version: (i've had 10 minor versions now, don't think i'm ever going to do a major). 
 joining firstshow & firsthtml etc.
 */
(function($)
{
	$.fn.sudoSlider = function(options)
	{
		if (typeof(options) != 'object' && options != '' && options) 
		{ 
			// Here, i just trigger it to do something, it's way down the actual action happens. 
			this.each(function(){
				$(this).trigger("sudoSliderEvent", [options]);
			});
		}
		else
		{
			// default configuration properties
			var defaults = {
				prevNext:          true,
				prevHtml:          '<a href="#" class="prevBtn"> previous </a>',
				nextHtml:          '<a href="#" class="nextBtn"> next </a>',
				controlsShow:      true,
				controlsAttr:      'id="controls"',
				controlsFadeSpeed: '400',
				controlsFade:      true,
				insertAfter:       true,
				firstShow:         false,
				firstHtml:         '<a href="#" class="firstBtn"> first </a>',
				lastShow:          false,
				lastHtml:          '<a href="#" class="lastBtn"> last </a>',
				numericAttr:       'class="controls"',
				numericText:       ['1'],
				vertical:          false,
				speed:             '400',
				ease:              'swing',
				auto:              false,
				pause:             '6000',
				continuous:        false,
				clickableAni:      false,
				numeric:           false,
				updateBefore:      false,
				history:           false,
				speedhistory:      '400',
				autoheight:        true,
				customLink:        false,
				fade:              false,
				crossFade:         true,
				fadespeed:         '500',
				ajax:              false,
				loadingText:       false,
				preloadAjax:       false,
				startSlide:        false,
				imgAjaxFunction:   false,
				docAjaxFunction:   false,
				beforeAniFunc:     false,
				afterAniFunc:      false,
				uncurrentFunc:     false,
				currentFunc:       false
			};
			var options = $.extend(defaults, options);
			
			// To make it smaller when minimized.
			// Not including the variables only used once in the code. 
			// I just found out that this (as in now, not the same as final release) makes the script 572 bytes smaller. (That's about 6%)
			//var optionscontrolsShow = options.controlsShow; // Only used once.
			var optionscontrolsFadeSpeed = options.controlsFadeSpeed;
			//var optionscontrolsBefore = options.controlsBefore; // Only used once.
			//var optionscontrolsAfter = options.controlsAfter; // Only used once.
			var optionscontrolsFade = options.controlsFade;
			//var optionsinsertAfter = options.insertAfter;// Only used once.
			var optionsfirstShow = options.firstShow;
			var optionslastShow = options.lastShow;
			var optionsvertical = options.vertical;
			var optionsspeed = options.speed;
			var optionsease = options.ease;
			var optionsauto = options.auto;
			var optionspause = options.pause;
			var optionscontinuous = options.continuous;
			var optionsprevNext = options.prevNext;
			var optionsnumeric = options.numeric;
			var optionsnumericAttr = options.numericAttr;
			var optionsnumericText = options.numericText;
			//var optionsclickableAni = options.clickableAni; // Only used once.
			var optionshistory = options.history;
			var optionsspeedhistory = options.speedhistory;
			var optionsautoheight = options.autoheight;
			var optionscustomLink = options.customLink;
			var optionsfade = options.fade;
			var optionscrossFade = options.crossFade;
			var optionsfadespeed = options.fadespeed;
			var optionsupdateBefore = options.updateBefore;
			var optionsajax = options.ajax;
			//var optionspreloadAjax= options.preloadAjax; // Only used once.
			var optionsstartSlide = options.startSlide;
			var optionsimgAjaxFunction = options.imgAjaxFunction;
			var optionsdocAjaxFunction = options.docAjaxFunction;
			var optionsbeforeAniFunc = options.beforeAniFunc;
			var optionsafterAniFunc = options.afterAniFunc;
			var optionsuncurrentFunc = options.uncurrentFunc;
			var optionscurrentFunc = options.currentFunc;
			
			return this.each(function()
			{	
				// There are some things we don't do at init. 
				var init = true; // I know it's an ugly workaround, but it works. 
				// If auto is on, so is continuous. (People tend to forget things they don't think about :p)
				if (optionsauto) optionscontinuous = true;
				
				// Setting up some variables. 
				var obj = $(this);
				
				// Fix for nested list items
				var ul = obj.children("ul");
				var li = ul.children("li");
				
				// Some variables i'm gonna use alot. 
				var s = li.length;
				var w = li.eq(0).width(); // All slides must be same width, so this shouldn't be a problem. 
				var h = obj.height();
				
				// Now we are going to fix the document, if it's 'broken'. (No <ul> or no <li>). 
				// I assume that it's can only be broken, if ajax is enabled. If it's broken without Ajax being enabled, the script doesn't have anything to fill the holes. 
				if (optionsajax)
				{
					// Is the ul element there?
					if (ul.length == 0)
					{
						// No it's not, lets create it. 
						obj.append('<ul></ul>');
						ul = obj.children("ul");
					}
				
					// Do we have enough list elements to fill out all the ajax documents. 
					if (optionsajax.length > s)
					{
						// No we dont. 
						for (var i = 1; i <= optionsajax.length - s; i++) ul.append('<li><p>' + returnFunnyLoadingText() + '</p></li>');
						li = ul.children("li");
						s = li.length;
						w = li.eq(0).width();
					}
				}				
				// i just love stackoverflow (http://stackoverflow.com/questions/182112/what-are-some-funny-loading-statements-to-keep-users-amused-closed)
				// i know this is just an easter egg, because you really should never see it. 
				// But what the heck, i want it. 
				function returnFunnyLoadingText()
				{
					var funnyLoadingTexts = [
						//"Locating the required gigapixels to render",
						"Spinning up the hamster",
						//"&pi; &times; 1337% == 42",
						//"&pi; &times; 1337% != 42!",
						//"Shovelling coal into the server",
						"Programming the flux capacitor",
						//"The last time I tried this the monkey didn't survive",
						"Testing data on Timmy... ... ... We need another Timmy",
						//"I should have had a V8 this morning",
						//"My other load screen is much faster. You should try that one instead",
						//"The version I have of this in testing has much funnier load screens",
						"Warming up Large Hadron Collider",
						"It looks like you're waiting for something to load"
					];
					return options.loadingText ? options.loadingText : (funnyLoadingTexts[Math.round(Math.random()*(funnyLoadingTexts.length-1))] + '...');
				};
				
				
				// Continuing with the variables. 
				var t = 0;
				var ot = t;
				var nt = t;
				var ts = s-1;
				
				var clickable = true;
				var buttonclicked = false;
				var fading = false;
				var ajaxloading = false;
				var autoheightdocument = 0;
				var numericControls = new Array();
				var numericContainer = false;
				var destroyed = false;
				
				// Set obj overflow to hidden (and position to relative <strike>, if fade is enabled. </strike>)
				obj.css("overflow","hidden");
				if (obj.css("position") == "static") obj.css("position","relative"); // Fixed a lot of IE6 + IE7 bugs. 
	
				// Float items to the left
				li.css('float', 'left');
				
				// They doens't always put a text in the numericText. 
				// With this, if the user dont, the code will. 
				for(var i=0;i<s;i++)
				{
					if (optionsnumericText[i] == undefined) optionsnumericText[i] = (i+1);
					// Same thing for ajax thingy. 
					if (optionsajax && optionsajax[i] == undefined) optionsajax[i] = false;
				}
				
				// Clone elements for continuous scrolling
				if(optionscontinuous)
				{
					if(optionsvertical)
					{
						// First we create the elements, pretending AJAX is a city in Russia. 
						ul.prepend(li.filter(":last-child").clone().css("margin-top","-"+ h +"px"));
						ul.append(li.filter(":nth-child(2)").clone());
						ul.height((s+1)*h);
					} else {
						// First we create the elements, pretending AJAX is a city in Russia. 
						ul.prepend(li.filter(":last-child").clone().css("margin-left","-"+ w +"px"));
						ul.append(li.filter(":nth-child(2)").clone());
						ul.width((s+1)*w);
					}
					// Now, lets check if AJAX really is a city in Russia.
					if (optionsajax)
					{
						// Now we move from Russia back to reallity (nothing bad about the Russians, it's just a saying in Denmark.)
						// Starting with putting the first document after the last. 
						if (optionsajax[0]) {
							ajaxLoad('last', 0, false, 0);
							// ajaxLoad(0, 0, false, 0); //And this would just be a waste of brandwith. 
						}
						// And putting the last document before the first. 
						if (optionsajax[s-1])
						{
							ajaxLoad('first', (s-1), false, 0);
							// And then preloading the last document (the same document, but into it's entended position). No need to preload the first slide, it gets loaded elsewhere. 
							ajaxLoad(ts, ts, false, 0);
							optionsajax[s-1] = false;
						}
					}
				}
				else // <strike>Bug fix</strike> feature.
				{
					if(optionsvertical)	ul.height(s*h);
					else ul.width(s*w);
				};
				
				// Display the controls.
				if(options.controlsShow)
				{
					var controls = $('<span ' + options.controlsAttr + '></span>');
					if (options.insertAfter) $(obj).after(controls);
					else $(obj).before(controls);
					
					var html = options.controlsBefore;
					if(optionsnumeric) {
						numericContainer = controls.prepend('<ol '+ optionsnumericAttr +'></ol>').children();
						for(var i=0;i<s;i++)
						{
							numericControls[i] = $(document.createElement("li"))
							.attr({'rel' : (i+1)})
							.html('<a href="#"><span>'+ optionsnumericText[i] +'</span></a>') 
							.appendTo(numericContainer)
							.click(function(){
								goToSlide($(this).attr('rel') - 1, true);
								return false;
							});
						};
					}
					if(optionsfirstShow) {
						var firstbutton = makecontrol(options.firstHtml, "first");
					}
					if(optionslastShow) {
						var lastbutton = makecontrol(options.lastHtml, "last");
					}
					if(optionsprevNext){
						var nextbutton = makecontrol(options.nextHtml, "next");
						var prevbutton = makecontrol(options.prevHtml, "prev");
					}
				};
				
				// Preload elements. 
				if (options.preloadAjax)
				{
					for (var i=0;i<=ts;i++) // Preload everything.
					{
						
						if (optionsajax[i])
						{
							// If somethings is to be loaded, lets load it. 
							ajaxLoad(i, i, false, 0);
							// Making sure it aint loaded again. 
							optionsajax[i] = false;
						}
					}
				}
				
				function goToSlide(i, clicked)
				{
					if (!destroyed)
					{
						if (optionsfade)
						{
							fadeto(i, clicked);
						} else {
							animate(i,clicked,true);
						}
					}
				};
				// I go a long way to save lines of code. 
				function makecontrol(html, action)
				{
					var button = $(html);
					controls.prepend(button);
					button.click(function(){
						goToSlide(action, true);
						return false;
					});
					return button;
				}
				
				// Lets make those fast/normal/fast into some numbers we can make calculations with.
				optionscontrolsFadeSpeed = textSpeedToNumber(optionscontrolsFadeSpeed);
				optionsspeed = textSpeedToNumber(optionsspeed);
				optionspause = textSpeedToNumber(optionspause);
				optionsspeedhistory = textSpeedToNumber(optionsspeedhistory);
				optionsfadespeed = textSpeedToNumber(optionsfadespeed);
				// The functions do the magic.
				function textSpeedToNumber(speed)
				{
					if (parseInt(speed)) var returnspeed = parseInt(speed);
					else 
					{
						switch(speed)
						{
						case 'fast':
							var returnspeed = 200;
							break;
						case 'normal':
							var returnspeed = 400;
							break;
						case 'medium':
							var returnspeed = 400;
							break;
						case 'slow':
							var returnspeed = 600;
							break;
						default:
							var returnspeed = 400;
						}
					}
					return returnspeed;
				};
				function runOnImagesLoaded(e,_cb)
				{
					// This function is based on the onImagesLoaded plugin by soundphed, that was in a comment on this page "http://engineeredweb.com/blog/09/12/preloading-images-jquery-and-javascript#comment-92". 
					e.each(function() {
						var $imgs = (this.tagName.toLowerCase()==='img')?$(this):$('img',this),
						_cont = this,
						i = 0,
						_done=function() {
							if( typeof _cb === 'function' ) _cb(_cont);
						};
						
						if( $imgs.length ) {
							$imgs.each(function() {
								var _img = this,
								_checki=function(e) {
									if((_img.complete) || (_img.readyState=='complete'&&e.type=='readystatechange') )
									{
										if( ++i===$imgs.length ) _done();
									}
									else if( _img.readyState === undefined ) // dont for IE
									{
										$(_img).attr('src',$(_img).attr('src')); // re-fire load event
									}
								}; // _checki \\
								$(_img).bind('load readystatechange', function(e){_checki(e);});
								_checki({type:'readystatechange'}); // bind to 'load' event...
							});
						} else _done();
					});
				};
				
				// Is the file a image? (This function is not only used in the Ajaxload function)
				function imageCheck(file)
				{
					var image = false;
					
					var len = file.length;
					var ext = file.substr(len-4, 4);
					
					if (ext == '.jpg' || ext == '.png' || ext == '.bmp' || ext == '.gif') 
					{
						image = true;
					}
					var ext = file.substr(len-5, 5);
					if (ext == '.jpeg')
					{
						image = true;
					}
					
					return image;
				}
				function fadeControl (fadeOpacity,fadetime,nextcontrol)
				{
					if (nextcontrol)
					{
						var eA = nextbutton;
						var eB = lastbutton;
						var directionA = 'next';
						var directionB = 'last';
						var firstlastshow = optionslastShow;
					}
					else
					{
						var eA = prevbutton;
						var eB = firstbutton;
						var directionA = 'prev';
						var directionB = 'first';
						var firstlastshow = optionsfirstShow;
					}
					if (!optionscontinuous)
					{
						if (optionsprevNext) eA.fadeTo(fadetime, fadeOpacity, function() { if (fadeOpacity == 0) $(this).hide();});
						if (firstlastshow) eB.fadeTo(fadetime, fadeOpacity, function() { if (fadeOpacity == 0) $(this).hide();});
						if(optionscustomLink)
						{
							$(optionscustomLink)
							.filter(function(index) { 
								return ($(this).attr("rel") == directionA || $(this).attr("rel") == directionB);
							})
							.fadeTo(fadetime, fadeOpacity, function() { if (fadeOpacity == 0) $(this).hide();});
						} 
					}
				};
				// Fade the controls, if we are at the end of the slide. 
				// It's all the different kind of controls. 
				function fadeControls (a,fadetime)
				{
					if(a==0) fadeControl (0,fadetime,false);
					else fadeControl (1,fadetime,false);
					
					if(a==ts) fadeControl (0,fadetime,true);
					else fadeControl (1,fadetime,true);
				};
				
				
				
				// Updating the 'current' class
				function setCurrent(i)
				{
					i = parseInt((i>ts) ? i=0 : ((i<0)? i=ts: i)) + 1;
					for(var a=0;a<numericControls.length;a++) setCurrentElement(numericControls[a], i);
					if(optionscustomLink) setCurrentElement(optionscustomLink, i);
				};
				function setCurrentElement(element,i)
				{
					$(element)
						.filter(".current")
						.removeClass("current")
						.each(function() {
							if ($.isFunction(optionsuncurrentFunc)){ optionsuncurrentFunc.call(this, $(this).attr("rel")); }
						});
					$(element)
						.filter(function() { 
							return $(this).attr("rel") == i; 
						})
						.addClass("current")
						.each(function(index) {
							if ($.isFunction(optionscurrentFunc)){ optionscurrentFunc.call(this, i); }
						});
				};
				// Find out wich numericText fits the current url. 
				function filterUrlHash(t)
				{
					var te = 0;
					for (var i=0;i<=s;i=i+1) if (optionsnumericText[i] == t) te = i;
					return te;
				};
				// Automaticly adjust the height, i love this function. 
				function autoheight(i, speed)
				{
					if (i == s) i = 0;
					// First i run it. In case there are no images. 
					var target = li.eq(i);
					var nheight = target.height();
					if (nheight != 0) setHeight(nheight, speed);
					// Then i run it again after the images has been loaded. (If any)
					runOnImagesLoaded(target,function(imgtarget){
						nheight = $(imgtarget).height();
						if (nheight != 0) setHeight(nheight, speed);
					});
				};
				function setHeight(nheight, speed)
				{
					obj.animate(
						{ height:nheight},
						{
							queue:false,
							duration:speed,
							easing:optionsease
						}
					);
				};
				// When the animation finishes (fade or sliding), we need to adjust the slider. 
				function adjust()
				{
					if(t>ts) t=0;
					if(t<0) t=ts;
					if (!optionsupdateBefore) setCurrent(t);
					if(optionsvertical) ul.css("margin-top",(t*h*-1)); 
	 				else ul.css("margin-left",(t*w*-1)); 
					clickable = true;
					if(optionshistory && buttonclicked) window.location.hash = optionsnumericText[t];
					if (!fading)
					{
						// Lets run the after animation function.
						if ($.isFunction(optionsafterAniFunc)){optionsafterAniFunc.call(li.eq(t) , t + 1);}
					}
				};
				// Convert the direction into a usefull number.
				function filterDir(dir, ot)
				{
					var nt = t; // i dont want to mess with the 't' variable.
					switch(dir)
					{
						case "next":
							nt = (ot>=ts) ? (optionscontinuous ? nt+1 : ts) : nt+1;
							break;
						case "prev":
							nt = (t<=0) ? (optionscontinuous ? nt-1 : 0) : nt-1;
							break;
						case "first":
							nt = 0;
							break;
						case "last":
							nt = ts;
							break;
						default:
							nt = parseInt(dir);
						break;
					};
					return nt;
				};
				// Load a ajax document (or i image) into a list element. 
				// If testing this locally (loading everything from a harddisk instead of the internet), it may not work. 
				// But then try to upload it to a server, and see it shine. 
				function ajaxLoad(i, l, adjust, speed)
				{
					var targetslide = false;
					if (parseInt(i) || i == 0) targetslide = li.eq(i);
					else
					{
						if (i == 'last') targetslide = $('li:last', obj);
						else targetslide = $('li:first', obj);
					}
					// What speed should the autoheight function animate with?
					var ajaxspeed = (fading) ? (!optionscrossFade ? parseInt(optionsfadespeed * (2/5)) : optionsfadespeed) : speed;
					// The script itself is not using the 'tt' variable. But a custom function can use it. 
					var tt = l + 1;
					if (imageCheck(optionsajax[l])) 
					{
						// Load the image.
						targetslide.html(' ').append($(new Image()).attr('src', optionsajax[l]));
						// When the document is ready again, we launch a autoheight event. 
						runOnImagesLoaded(targetslide,function(img){
							var target = $(img).children();
							// If the image is to wide, shrink it. 
							var width = target.width();
							var height = target.height();
							target.attr({'oldheight' : height, 'oldwidth' : width});
							if (width > w) target.animate({ width: w, height: (height/width)*w}, 0);
							// If we want, we can launch a function here. 
							if ($.isFunction(optionsimgAjaxFunction)){optionsimgAjaxFunction.call($(img), tt);}
							// Then do the autoheight.
							if (optionsautoheight && adjust) autoheight(t, ajaxspeed);
						});
					}
					else
					{
						
						// Load the document into the list element. 
						targetslide.load(optionsajax[l], function(response, status, xhr) {
							if (status == "error" || !$(this).html()) $(this).html("Sorry but there was an error: " + (xhr.status ? xhr.status: 'no content') + " " + xhr.statusText);
							// If we want, we can launch a function here. 
							if (status != "error" && $.isFunction(optionsdocAjaxFunction)){optionsdocAjaxFunction.call($(this), tt);}
							// Lets adjust the height, i don't care if there's an error or not. 
							var nheight = $(this).height();
							if (optionsautoheight && adjust) autoheight(l, ajaxspeed);
						});
					}
				};
				// It's not only a slider, it can also fade from slide to slide. 
				function fadeto(i, clicked)
				{
					if (i != t && !destroyed) // We doesn't want something to happen all the time. The URL can change a lot, and cause som "flickering". 
					{
						if (clickable)
						{
							ajaxloading = false;
							// Stop auto if cliked.
							if(clicked) clearTimeout(timeout);
							// Update the current class of the buttons. 
							if (optionsupdateBefore) setCurrent(filterDir(i, ot));
							// Only clickable if not clicked.
							clickable = !clicked;
							// Setting the speed. 
							var speed = (!clicked && !optionsauto && optionshistory) ? optionsfadespeed * (optionsspeedhistory / optionsspeed) : optionsfadespeed;
							var ll = filterDir(i, ot);
							// Lets make sure that the target actually exists. 
							if(ll>ts) ll=0; 
							if(ll<0) ll=ts;
							// Lets make sure the prev/next buttons also fade. 
							if(optionscontrolsFade) fadeControls (ll,optionscontrolsFadeSpeed);
							// Lets adjust the height, but not if the ajax document isn't loaded. 
							if (optionsautoheight) 
							{
								if (optionsajax)
								{
									// If Ajax is enabled
									if (!optionsajax[ll]) autoheight(ll,optionsfadespeed); // we only want to change the height, if the document we are fading to, is allready loaded.
								}
								else autoheight(ll,optionsfadespeed); // The height animation takes the full lenght of the fade animation (fadein + fadeout if it's not crossfading).  
							}
							// Define the target. 
							var target = li.eq(ll);
							// So lets run the function.
							if ($.isFunction(optionsbeforeAniFunc)){optionsbeforeAniFunc.call(target, ll + 1);}
							// Crossfading?
							if (optionscrossFade)
							{
								// I clone the target, and fade it in, then hide the cloned element while adjusting the slider to show the real target.
								// I dont hide it right away, because that breaks the autoheight function, and the function that auto-resizes ajax-loaded images.
								var fadeIntarget = target.clone().prependTo(obj).css({'z-index' : '100000', 'position' : 'absolute', 'list-style' : 'none', 'top' : '0', 'left' : '0'});
								// Maybe we need to load some content into it first?
								if (optionsajax[ll])
								{
									// I have to load the Ajax-content into the target clone, and the target itself. 
									// First the target clone.
									ajaxLoad(0, ll, false, speed);
									// Then the target.
									if (imageCheck(optionsajax[ll])) // Weird bugs, weird fixes. But this works. 
									{
										ajaxLoad(ll+1, ll, false, speed);
										runOnImagesLoaded(li.eq(ll+1),function(){
											if (optionsautoheight) autoheight(ll, optionsfadespeed);
										});
									}
									else
									{
										ajaxLoad(ll+1, ll, true, speed);
									}
									optionsajax[ll] = false;
								}
								// Lets fade it in. 
								fadeIntarget.hide().fadeIn(optionsfadespeed, function() {
									// So the animate function knows what to do. 
									clickable = true;
									fading = true;
									animate(i,false,false); // Moving to the correct place.
									// Removing it again, if i dont, it will just be a pain in the ....
									$(this).remove();
									if(optionshistory && clicked) window.location.hash = optionsnumericText[t]; // It's just one line of code, no need to make a function of it. 
									// Lets put that variable back to the default (and not during animation) value. 
									fading = false;
									// Now run that after animation function.
									// We already got the target and the slider number from earlier.
									// So lets run the function.
									if ($.isFunction(optionsafterAniFunc)){optionsafterAniFunc.call(target, ll + 1);}
								});
							}
							else
							{
								// fadeOut and fadeIn.
								var fadeinspeed = parseInt((speed)*(3/5));
								var fadeoutspeed = speed - fadeinspeed;
								// I set the opacity to something higher than 0, because if it's 0, the content that i try to read (to make the autoheight work etc.) aint there.
								obj.children().fadeTo(fadeoutspeed, 0.00001, function(){
									// So the animation function knows what to do. 
									clickable = true;
									fading = true;
									animate(i,false,false); // Moving to the correct place.
									// Only clickable if not clicked.
									clickable = !clicked; 
									// Now, lets fade the slider back in. 
									obj.children().fadeTo(fadeinspeed, 1, function(){
										if(optionshistory && clicked) window.location.hash = optionsnumericText[t]; // It's just one line of code, no need to make a function of it. 
										clickable = true;
										fading = false;
										// Now run that after animation function.
										// We already got the target and the slider number from earlier.
										// So lets run the function.
										if ($.isFunction(optionsafterAniFunc)){optionsafterAniFunc.call(target, ll + 1);}
									});
								});
							}
						}
					}
				};
				function animate(dir,clicked,time) // (Direction, did the user click something, is this to be done in >1ms?) 
				{
					if (clickable && !destroyed)
					{
						ajaxloading = false;
						clickable = (!clicked && !optionsauto) ? true : options.clickableAni;
						// to the adjust function. 
						buttonclicked = clicked;
						ot = t;
						t = filterDir(dir, ot);
						if (optionsupdateBefore) setCurrent(t);
						// Calculating the speed to do the animation with. 
						var diff = Math.sqrt(Math.abs(ot-t));
						var speed = parseInt(diff*optionsspeed);
						if (!clicked && !optionsauto) speed = parseInt(diff*optionsspeedhistory); // Auto:true and history:true doens't work well together, and they ain't supposed to. 
						if (!time) speed = 0;
						
						// Ajax begins here 
						// I also these variables in the below code (running custom function).
						var i = t;
						if(t>ts) i=0;
						if(t<0) i=ts;
						if (optionsajax)
						{
							// Loading the target slide, if not already loaded. 
							if (optionsajax[i]) 
							{
								ajaxLoad(i, i, true, speed);
								optionsajax[i] = false; 
								ajaxloading = true;
							}
							// It can look stupid the script scroll over some not-loaded slides. Therefore, they are loaded. 
							// It can produce some heavy load, so the script wont do it, it it's more than 10 slides.
							if (!fading)
							{
								// I dont like copypasting the same code, but this is the most efficient way i can think of atm. 
								var countajax = 0;
								if (ot > t)
								{
									for (a = t; a <= ot; a++)
									{
										if (a<=ts && a>=0)
										{
											if (optionsajax[a]) 
											{
												ajaxLoad(a, a, false, speed);
												optionsajax[a] = false; 
												countajax++;
											}
										}
										if (countajax == 10) a = ot;
									}
								}
								else
								{
									for (a = ot; a <= t; a++)
									{
										if (a<=ts && a>=0)
										{
											if (optionsajax[a]) 
											{
												ajaxLoad(a, a, false, speed);
												optionsajax[a] = false; 
												countajax++;
											}
										}
										if (countajax == 10) a = t;
									}
								}
							}
							// Then we have to preload the next one. 
						 	if ((i + 1 <= ts) && !init)
							{
								if (optionsajax[i + 1]) 
								{
									ajaxLoad(i + 1, i + 1, false, 0);
									optionsajax[i + 1] = false;
								}
							}
							// And the previous one. 
							if (i - 1 >= 0 && !init)
							{
								if (optionsajax[i - 1]) 
								{
									ajaxLoad(i - 1, i - 1, false, 0);
									optionsajax[i - 1] = false;
								}
							}
						}
						// Ajax ends here
						if (!fading)
						{
							// Lets run the before animation function.
							if ($.isFunction(optionsbeforeAniFunc)){
								optionsbeforeAniFunc.call(li.eq(i), i + 1);
								if (t == -1 || t == s) optionsbeforeAniFunc.call(ul.children("li").eq((t == -1) ? 0 : -1), i + 1);
							}
							
						}
						// Start animation. 
						if(!optionsvertical) {
							if (optionsautoheight && !fading && !ajaxloading) autoheight(t, speed);
							p = (t*w*-1);
							ul.animate(
								{ marginLeft: p},
								{
									queue:false,
									duration:speed,
									easing:optionsease,
									complete:adjust
								}
							);
						} else {
							p = (t*h*-1);
							ul.animate(
								{ marginTop: p },
								{
									queue:false,
									duration:speed,
									easing:optionsease,
									complete:adjust
								}
							);
						};
						// End animation. 
						
						// Fading the next/prev/last/first controls in/out if needed. 
						if(optionscontrolsFade)
						{
							var fadetime = optionscontrolsFadeSpeed;
							if (!clicked && !optionsauto) fadetime = (optionsspeedhistory / optionsspeed) * optionscontrolsFadeSpeed;					
							if (!time) fadetime = 0;
							if (fading) fadetime = parseInt((optionsfadespeed)*(3/5));
							fadeControls (t,fadetime);
						}
						
						// Stopping auto if clicked. 
						if(clicked) clearTimeout(timeout);
						// Continuing if not clicked.
						if(optionsauto && dir=="next" && !clicked){
							timeout = startAuto(optionspause + optionsspeed);
						};
					};
				};
				// init
				var timeout;
				
				// Starting auto. 
				if(optionsauto){
					timeout = startAuto(optionspause);
				};
				function startAuto(pause)
				{
					return setTimeout(function(){
						goToSlide("next", false);
					},pause);
				}
				if (optionscustomLink) // customLinks. Easy to make, great to use. 
				{
					// Using live, that way javascript ajax-loaded buttons and javascript generated content will work.
					$(optionscustomLink).live('click', function() { //høns
						var a = $(this).attr('rel');
						if (a) doExternalInput(a);
						return false;
					}); 
				}
				obj.bind('sudoSliderEvent', function(e, a) { 
					doExternalInput(a);
				});
				function doExternalInput(a)
				{
					// Check for special events
					if (a == 'stop') clearTimeout(timeout)
					else if (a == 'start')
					{
						timeout = startAuto(optionspause);
						optionsauto = true;
					}
					else if (a == 'block') clickable = false;
					else if (a == 'unblock') clickable = true;
					else if (a == 'action') alert('The slider just performed an action');
					else if (a == 'destroy') 
					{
						// First, i remove the controls. 
						controls.remove(); // that's it.
						// Now to set a variable, so nothing is run. 
						destroyed = true; // No animation, no fading, no clicking from now. 
						// Then remove the customLink bindings:
						$(optionscustomLink).die("click");
						// Now remove the "continuous clones". 
						if (optionscontinuous)
						{
							ul.children("li").eq(0).remove();
							ul.children("li").eq(-1).remove();
						}
					}
					// The general case. 
					// That means, typeof(a) == numbers and first,last,next,prev
					// I dont make any kind of input validation, meaning that it's quite easy to break the script with non-valid input. 
					else if (clickable) goToSlide((a == parseInt(a)) ? a - 1 : a, true);
				};
				// Done.
				init = false; //nasty workaround, but it works. 
				
				
				// Lets make those bookmarks and back/forward buttons work. 
				if (optionshistory) {
					// Going to the correct slide at load. 
					$.address.init(function(e) {
						var i = filterUrlHash(e.value);
				 	 	animate(i,false,false);
					})
					// Sliding/fading to the correct slide, on url change. 
					.change(function(e) {
						var i = filterUrlHash(e.value);
						if (i != t) goToSlide(i, false);
					});
				}
				// The startSlide setting only require one line of code. And here it is:
	 			else if (optionsstartSlide) animate(optionsstartSlide - 1,false,false); 
				// doing it anyway. good way to fix bugs. 
				// And i only preload the next and previous slide after init (which this is). So i'm doing it. 
				// + if i didn't do this, a lot of things wouldn't happen on page load. By always animating, i ensure that everthing that's supposed to happen, do happen. 
				else animate(0,false,false); 
			});
		}
	};
})(jQuery);
