
/**
 * AviationSlider - A jQuery image slider with Ken Burns effect
 * (c) Copyright Christian "Kriesi" Budschedl
 * http://www.kriesi.at
 * http://www.twitter.com/kriesi/
 */



(function($)
{
	var pluginNameSpace = 'aviationSlider',
				
		//methods used to create the slideshow
		methods = {
		
			/************************************************************************
			methods.init:
			
			initialize the slider by activating the image preloader if available and 
			then wait until images are loaded
			*************************************************************************/
			init: function()
			{
				var current = this;
				this.aviaImagePreloader({fadeInSpeed:0},function(){ methods.preloadingDone.apply( current ); });
			},
			
			/************************************************************************
			methods.preloadingDone:
			
			once images are pre loaded execute all necessary functions for the slider
			like applying controlls and starting autorotation
			*************************************************************************/
			preloadingDone: function()
			{
				//fetch slider data
				var data = this.data( pluginNameSpace );
				
				//calculate the time of the ken burns effect.
				data.burnsTime = (parseInt(data.options.autorotationSpeed) * 1400 + parseInt(data.options.animationSpeed));
				
				//prepare slides
				methods.prepareSlides.apply( this );
				
				//allow animation of slides:
				data.animatingNow = false;
				
				//append controlls and start autsolider if we got more than one slide and these options are set
				if(data.slideCount > 1)
				{
					//append normal and arrow controlls
					if(data.options.appendControlls) methods.appendControlls.apply( this );
					if(data.options.autorotation) methods.autorotation.apply( this );
					
					//check for external controlls
					if(data.options.externalControlls) methods.useExternalControlls.apply( this );
				}
				
				methods.bindEvents.apply( this );
				
				//show caption if available
				if(data.options.appendCaption) methods.appendCaption.apply( this );
				data.allcaptions = this.find('.'+data.options.captionClass).css({display:'none'});

				methods.showCaption.apply( this );
								
				//calculate ken burns data and apply the effect
				methods.calculatePosition.apply( this );				
				
			},			
			
			
			/************************************************************************
			methods.prepareSlides:
			
			addds classnames slides so we know if they are image slides, image slides
			with video beneath or embeded videos 
			*************************************************************************/
			prepareSlides :function()
			{
				var data = this.data( pluginNameSpace ), currentslide, imageslide, videoslide, classname;
				
				data.slides.each(function(i)
				{
					//first check for videos within the slider
					currentslide 	= $(this);
					imageslide 		= currentslide.find('img');
					videoslide		= currentslide.find('video, embed, object, iframe, .avia_video');
					
					if(imageslide.length && videoslide.length)
					{
						classname = 'comboslide';
					}
					else if(videoslide.length)
					{
						classname = 'videoslide';
					}
					else if(imageslide.length)
					{
						classname = 'imageslide';
					}
					
					currentslide.addClass(classname).append('<span class="slideshow_overlay"></span>');
					
					//if we are using canvas and an image was encountered create the canvas element
					if(data.useCanvas && imageslide.length)
					{
						//create canvas element and set height and width while creating, since setting it in CSS results in distortion of image
						var canvas = $('<canvas height="'+data.size.height+'" width="'+data.size.width+'"></canvas>').insertAfter(imageslide);						
						imageslide.css({display:'none'});
					}					
					
				});
			},
			
			/************************************************************************
			methods.autorotation:
			
			start the slider autorotation
			*************************************************************************/
			autorotation: function()
			{ 
				var current = this,
					data = this.data( pluginNameSpace ),
					time = (parseInt(data.options.autorotationSpeed) * 1000);
					
					data.interval = setTimeout(function()
					{ 
						//switch slides
						methods.transition.apply( current, ['next'] );							
						
						//call this function again	
						methods.autorotation.apply( current );
					},
					time);
					
					if(data.options.appendControlls && data.arrowControlls) data.arrowControlls.play.addClass('ctrl_active').text('Pause');
			},
			
			
			/************************************************************************
			methods.autorotationStop:
			
			stop the slider autorotation
			*************************************************************************/
			autorotationStop: function()
			{ 
				var data = this.data( pluginNameSpace );
				clearTimeout(data.interval);
				data.interval = false;
				
				if(data.options.appendControlls && data.arrowControlls) data.arrowControlls.play.removeClass('ctrl_active').text('Play');
			},
			
			/************************************************************************
			methods.switchAutorotation:
			
			switch between active and inactive autorotation state
			*************************************************************************/
			switchAutorotation: function()
			{
				var data = this.data( pluginNameSpace );
				
				if(data.interval)
				{
					methods.autorotationStop.apply( this );
				}
				else
				{
					methods.transition.apply( this, ['next'] );
					methods.autorotation.apply( this );
				}
			},
			
			/************************************************************************
			methods.appendControlls:
			
			append direct controlls as well as arrow controlls to the slider
			*************************************************************************/
			appendControlls: function()
			{
				var data = this.data( pluginNameSpace ),
					first = 'class="active_item" ',
					singlecontroll = '',
					i,
					arrowcontroll  = '<a href="#" class="ctrl_back ctrl_arrow">Previous</a>';
					arrowcontroll += '<a href="#" class="ctrl_play ctrl_arrow">Play</a>';
					arrowcontroll += '<a href="#" class="ctrl_fwd  ctrl_arrow">Next</a>';
				
				for(i = 0; i < data.slideCount; i++)
				{
					singlecontroll += '<a '+first+'href="#'+i+'">'+(i+1)+'</a>';
					first = '';
				}
				
				data.controllContainer = $('<div class="slidecontrolls">'+singlecontroll+'</div>').insertAfter(this);
				data.arrowControllContainer = $('<div class="arrowslidecontrolls">'+arrowcontroll+'</div>').insertAfter(this);
				data.controlls = data.controllContainer.find('a');
				data.arrowControlls = { 
										 prev: data.arrowControllContainer.find('.ctrl_back'), 
										 next: data.arrowControllContainer.find('.ctrl_fwd'), 
										 play: data.arrowControllContainer.find('.ctrl_play') 
									  }; 
			},
			
			/************************************************************************
			methods.setSlides:
			
			checks which slide should be displayed next and stores that information to
			the this.data.nextSlide var
			*************************************************************************/
			setSlides: function(selector)
			{
				//get slider data and set the current slide by selecting the one that is visible
				var data = this.data( pluginNameSpace ), newIndex;
				
				if(!data.animatingNow)
				{
					data.currentSlide 		= this.find(data.options.slides + ':visible');
					data.prevSlideIndex 	= data.slides.index(data.currentSlide);
					
					//based on the passed selector value (next/prev/integer value) get the number of the next slide
					switch (selector)
					{
						case 'next': newIndex = data.prevSlideIndex + 1 < data.slideCount  ? data.prevSlideIndex + 1 : 0;  break;
						case 'prev': newIndex = data.prevSlideIndex - 1 >= 0 ? data.prevSlideIndex - 1 : data.slideCount - 1; break;
						default: newIndex = selector;
					}
					
					//select the next slide and store it to data.nextSlide
					data.nextSlide = this.find( data.options.slides + ':eq('+newIndex+')');
					data.currentSlideIndex = newIndex;
					
					//check if the current slide is the same as the next one. if so skip the transition
					if(data.nextSlide[0] == data.currentSlide[0]) data.skipTransition = true;
				}
			},
			
			/************************************************************************
			methods.appendCaption:
			
			append a caption based on the image alt attribute
			*************************************************************************/
			appendCaption: function()
			{
				var data = this.data( pluginNameSpace ), description = false, splitdesc = [], caption;
				
				data.slides.each(function()
				{
					var currentSlide = $(this);
					description 	 = currentSlide.find('img').attr('alt');
					splitdesc 	 	 = description.split('::');
								
					if(splitdesc[0] != "" )
					{
						if(splitdesc[1] != undefined )
						{
							description = "<strong>"+splitdesc[0] +"</strong>"+splitdesc[1]; 
						}
						else
						{
							description = splitdesc[0];
						}
					}

					if(description)
					{
						caption = $('<span></span>').addClass(data.options.captionClass)
												    .html('<span class="inner_caption">'+description+"</span>")
												    .css({display:'none'})
												    .appendTo(currentSlide); 
					}
				});
				
			},
			
			/************************************************************************
			methods.showCaption:
			
			show the caption for the current slide once the slide has been revealed
			*************************************************************************/
			showCaption: function()
			{
				var data 	= this.data( pluginNameSpace ),
					width 	= this.width();	
				
				//hide all other captions, ned to reselect them here in case we removed and cloned one for videos
				data.allcaptions = this.find('.'+data.options.captionClass).css({display:'none'});
							
				
				//select current caption
				var caption 		= data.currentSlide.find('.'+data.options.captionClass),
					innerCaption 	= caption.find('.inner_caption'),
					captionWidth 	= caption.width(),
					centerPoint 	= width/2 - caption.outerWidth()/2;
				
				innerCaption.css(
				{
					width:captionWidth + 1,
					opacity:0
				});
				
				innerCaption.delay(1000).animate({opacity:1}, 500);
					
				caption.css(
				{
					display:'block', 
					opacity:0,
					left: width/2,
					width:0,
					overflow:'hidden'
				});
					
				caption.animate(
				{
					opacity: data.options.captionOpacity,
					left: centerPoint,
					width: captionWidth
				
				}, 1500, 'easeInOutCubic');
			},
			
			/************************************************************************
			methods.switchSlides:
			
			visual slide transition via jQuerys animate function
			*************************************************************************/
			switchSlides: function()
			{
				var current = $(this), data = this.data( pluginNameSpace );
				
				if(!data.animatingNow && !data.skipTransition)
				{
					methods.beforeSwitch.apply( current );
					data.currentSlide.animate({opacity:0}, data.options.animationSpeed, function(){ methods.switchComplete.apply( current ); });
					
					//check the controlls and apply the active class to the correct controll
					if(data.controlls.length) data.controlls.removeClass('active_item').filter(':eq('+data.currentSlideIndex+')').addClass('active_item');
					if(data.externalControlls.length) data.externalControlls.removeClass('active_item').filter(':eq('+data.currentSlideIndex+')').addClass('active_item');
				}
				
				if(data.skipTransition) data.skipTransition = false;
			},
			
			/************************************************************************
			methods.beforeSwitch:
			
			execute this before the slide switching starts
			*************************************************************************/
			beforeSwitch: function()
			{
				var data = this.data( pluginNameSpace );
				
				data.animatingNow = true;
				data.currentSlide.css({zIndex:3});
				data.nextSlide.css({zIndex:2, display:'block'});
				methods.kenBurns.apply( this , [data.nextSlide] );
			},
			
			/************************************************************************
			methods.switchComplete:
			
			execute this once the slides have been switched
			*************************************************************************/
			switchComplete: function()
			{
				var data = this.data( pluginNameSpace ), image = data.currentSlide.find('img'), video = data.currentSlide.find('.slideshow_video');
				
				data.animatingNow = false;
				
				data.nextSlide.css({zIndex:3});
				data.currentSlide.css({zIndex:2, display:'none', opacity:1});
				
				if(data.currentSlide.is('.comboslide') && !image.is(':visible'))
				{	
					
					image.css({display:'block'});
					video.css({display:'none' });
					data.currentSlide.wrapInner('<div class="videowrap_temp" />');
					
					var videwrap = $('.videowrap_temp', data.currentSlide), clone = videwrap.clone(true);
					videwrap.remove();
					data.currentSlide.append(clone);
					clone.find('.slideshow_overlay').css({display:'block'}).unwrap();
				}
				
				
				//set the current slide
				data.currentSlide = data.nextSlide;
				
				//show image caption
				methods.showCaption.apply( this );
				
				//clear all ken burns timeouts
				var index = data.slides.index(data.currentSlide ),
					counter = 0;
					
				for (x in data.timeout)
				{
					if(counter != index) clearTimeout(data.timeout[x]);
					counter++;
				}
	
			},
			
			/************************************************************************
			methods.transition:
			
			switch the slides
			*************************************************************************/
			transition: function(selector, autorotation)
			{
				methods.setSlides.apply( this, [selector] );	
				methods.switchSlides.apply( this );
				
				if('stop_autorotation' == autorotation)
				{
					methods.autorotationStop.apply(this);
				}
			},
			
			/************************************************************************
			methods.showvideo:
			
			hide image and show video instead
			*************************************************************************/
			showvideo: function(clicked_item)
			{
				var data = this.data( pluginNameSpace );
				
				clicked_item.find('img, canvas, .slideshow_overlay, .'+data.options.captionClass).stop().fadeOut();
				clicked_item.find('.slideshow_video').stop().fadeIn();
				
			},
			
			/************************************************************************
			methods.bindEvents:
			
			bind all events for the slider
			*************************************************************************/
			bindEvents: function()
			{ 
				var current = this, data = this.data( pluginNameSpace );
				
				//when any link within the slideshow is clicked stop the autorotation
				this.find('a').bind('click.'+pluginNameSpace, function(){ methods.autorotationStop.apply(current); });
				
				//show videos
				data.slides.bind('click.'+pluginNameSpace, function()
				{ 
					var clicked_item = $(this);

					if(clicked_item.is('.comboslide'))
					{
						methods.showvideo.apply(current, [clicked_item]); 
						methods.autorotationStop.apply(current);
						return false; 
					}
				});
				
				//bind controll clicks
				if(data.controlls && data.controlls.length)
				{
					data.controlls.bind('click.'+pluginNameSpace, function()
					{ 
						var selector = this.hash.substr(1); 
						methods.transition.apply(current, [selector, 'stop_autorotation']);
						return false;
					});
				}
				
				//bind external controlls if available
				if(data.externalControlls && data.externalControlls.length)
				{
					data.externalControlls.each(function(i)
					{
						$(this).bind('click.'+pluginNameSpace, function()
						{ 
							methods.transition.apply(current, [i, 'stop_autorotation']);
							return false;
						});	
					});
				}
				
				
				//bind arrowControll clicks
				if(data.arrowControlls && data.arrowControlls.next.length)
				{
					data.arrowControlls.next.bind('click.'+pluginNameSpace, function(){ methods.transition.apply(current, ['next','stop_autorotation']); return false; });
					data.arrowControlls.prev.bind('click.'+pluginNameSpace, function(){ methods.transition.apply(current, ['prev','stop_autorotation']); return false; });
					data.arrowControlls.play.bind('click.'+pluginNameSpace, function(){ methods.switchAutorotation.apply(current); return false; });
				}
				
				if($.fn.avia_hide_slide_controlls)
				current.parents(".slideshow_container:eq(0)").avia_hide_slide_controlls();
			},
			
			/************************************************************************
			methods.calculatePosition:
			
			calculate the transition positions for the images
			*************************************************************************/
			
			calculatePosition: function()
			{
				var data = this.data( pluginNameSpace ),
					containerHeight = this.height(),
					containerWidth = this.width(),
					imageObj, img, height, width, posLeft, posTop, movement = [], size = [], height_new_percent, width_new_percent;
					
				//check if starting and ending points are set via classnames
				var starting  = /kb_start__(\w+)/, ending = /kb_end__(\w+)/, match_start = "", match_end = "";
					
				//check if starting and ending size are set via clasnames
				var startingSize  = /kb_starting_size__(\d+)/, endingSize = /kb_ending_size__(\d+)/, match_startSize = "", match_endSize = "";
					
					
				data.movement = [];	
				
				//show the css slides for a split second so all browser get the correct image size values, doesnt work if set to display none			
				data.slides.css({display:'block'}).each(function(i)
				{
					data.movement[i] = [];
					
					//extract the classname values for starting and end point as well as size %
					match_start 	=  starting.exec(this.className);
					match_end   	=  ending.exec(this.className);
					match_startSize =  startingSize.exec(this.className);
					match_endSize   =  endingSize.exec(this.className);
					
					movement['start'] 	= match_start != null ? match_start[1] : 'topleft';
					movement['end']   	= match_end   != null ? match_end[1] : 'topleft';
					size['start']   	= match_end   != null ? parseInt(match_startSize[1]) / 100 : 1;
					size['end']   		= match_end   != null ? parseInt(match_endSize[1]) / 100 : 1;
				
					imageObj 	= $(this).find('img');
					imgHeight 	= imageObj.height();
					imgWidth 	= imageObj.width();
					
					//for start and end in movement
					for(pos in movement)
					{	
						//calculate the new height and width
						height_new_percent = width_new_percent = false;									
						height = imgHeight * size[pos];
						width  = imgWidth  * size[pos];
						
						//check if this new height and width are big enough to fit into the image container, if not adjust it so it fits
						if(height < containerHeight)
						{
							height_new_percent = Math.round((containerHeight / (imgHeight/100)) )/ 100;
						}
						
						if(width < containerWidth)
						{
							width_new_percent = Math.round((containerWidth / (imgWidth/100)) )/ 100;
						}
						
						if(height_new_percent || width_new_percent)
						{
							size[pos] = height_new_percent > width_new_percent ? height_new_percent : width_new_percent;
							height = imgHeight * size[pos];
							width  = imgWidth  * size[pos];
						}
											
						posLeft = (width  - containerWidth) * -1;
						posTop 	= (height  - containerHeight) * -1;
						
						//check the value that was extracted in the classname for image movement
						switch(movement[pos])
						{
							case 'topleft'		: data.movement[i][pos] = { top:0, 			left:0, 		scaleing: size[pos]}; 	break;
							case 'topright'		: data.movement[i][pos] = { top:0, 			left:posLeft, 	scaleing: size[pos]}; 	break;
							case 'topcenter'	: data.movement[i][pos] = { top:0, 			left:posLeft/2, scaleing: size[pos]};	break;
							case 'bottomleft'	: data.movement[i][pos] = { top:posTop, 	left:0 , 		scaleing: size[pos]}; 	break;
							case 'bottomright'	: data.movement[i][pos] = { top:posTop, 	left:posLeft , 	scaleing: size[pos]}; 	break;
							case 'bottomcenter'	: data.movement[i][pos] = { top:posTop, 	left:posLeft/2, scaleing: size[pos]}; 	break;
							case 'centerleft'	: data.movement[i][pos] = { top:posTop/2, 	left:0 , 		scaleing: size[pos]}; 	break;
							case 'centerright'	: data.movement[i][pos] = { top:posTop/2, 	left:posLeft, 	scaleing: size[pos]};	break;
							case 'centered'		: data.movement[i][pos] = { top:posTop/2, 	left:posLeft/2, scaleing: size[pos]};	break;
						}
					}
					
				
				//now we got start and end position, lets calculate the difference
				data.movement[i]['dif'] = {};
				for(x in  data.movement[i]['start'])
				{
					data.movement[i]['dif'][x] = data.movement[i]['start'][x] - data.movement[i]['end'][x];
				}
					
				//hide the slides again, but show the first one
				}).css({display:'none'});
				
				data.currentSlide.css({display:'block'});
				
				//apply the effect onto the first slide and show that slide
				methods.kenBurns.apply( this , [data.currentSlide, true] );
			},
			
			/************************************************************************
			methods.kenBurns:
			
			apply the ken burns effect on an image
			*************************************************************************/
			kenBurns: function(slide, firstrun)
			{
				var data = this.data( pluginNameSpace ),
					currentImage = slide.find('img'),
					index = data.slides.index(slide);

				//before the first run the slides are moved out of the viewport. change that and set the opacity of the first element to zero so it will fade in smoothly
				if(firstrun == true)
				{
					data.slides.css({left:0});
					data.currentSlide.css({opacity:0}).animate({opacity:1},700);
				}
				
				if(data.useCanvas)
				{
					methods.startKenBurnsCanvasLoop.apply( this, [slide, currentImage, index] );	
				}
				else
				{
					//set starting value for the image
					currentImage.transform(
					{
						origin: ['0%', '0%'],
						scaleX: data.movement[index]['start']['scaleing'],
	  					scaleY: data.movement[index]['start']['scaleing'],
	  					translateX: (data.movement[index]['start']['left'] / data.movement[index]['start']['scaleing'])+'px',
	  					translateY: (data.movement[index]['start']['top']  / data.movement[index]['start']['scaleing'])+'px'
					});
										
					//animate the image
					currentImage.stop().animate(
					{
						scaleX: data.movement[index]['end']['scaleing'],
	  					scaleY: data.movement[index]['end']['scaleing'],
	  					translateX: (data.movement[index]['end']['left'] / data.movement[index]['end']['scaleing'])+'px',
	  					translateY: (data.movement[index]['end']['top']  / data.movement[index]['end']['scaleing'])+'px'
					}, data.burnsTime );
				}
				
			},
			
			/************************************************************************
			methods.startKenBurnsCanvasLoop:
			
			starts the function that applies the Ken burns effect
			*************************************************************************/
			startKenBurnsCanvasLoop: function(slide, currentImage, index)
			{
				var data = this.data( pluginNameSpace ),
					size 		= { height: currentImage.height(), width:currentImage.width() },
					image		= currentImage.get(0),
					context 	= slide.find('canvas').get(0).getContext('2d'),
					stepCount 	= 1,
					fr 			= 15,
					iterations 	= data.burnsTime / (1000 / fr ) ,
					movement 	= data.movement[index];
					
				methods.drawImage(context, image, movement, iterations, stepCount, size, fr, {}, {}, data.timeout, index);
				
				
			/*
				console.log(iterations);
				console.log(movement['dif']['scaleing'] / iterations);
				console.log(movement['start']['scaleing']);
			*/

			},
			
			/************************************************************************
			methods.drawImage:
			
			calculates the canvas movement/size
			*************************************************************************/
			drawImage: function(context, image, movement, iterations, stepCount, size, fr, position, newSize, timeout, index)
			{
				for(x in movement['dif']) 
				{ 
					position[x] = movement['start'][x] + (-movement['dif'][x] / iterations * stepCount);
				}
				
				newSize = {  height: size.height * position['scaleing'],  width: size.width  * position['scaleing']  };
				
				context.drawImage(image, position['left'], position['top'], newSize.width, newSize.height );
				
				stepCount++;
				
				if(stepCount < iterations)
				{
					timeout[index] = setTimeout(function(){ methods.drawImage(context, image, movement, iterations, stepCount, size, fr, {}, {}, timeout, index); }, fr);
				}
			},

			
			/************************************************************************
			methods.overwrite_defaults:
			
			lets you overwrite options for multiple sliders on one page with different 
			settings, without the need to call the slider function multiple times
			*************************************************************************/
			overwrite_options: function()
			{
				var data 	= this.data( pluginNameSpace ),
					optionsWrapper = this.parents('.slideshow_container:eq(0)');
					
					if(optionsWrapper.length)
					{
						var autoInterval = /autoslidedelay__(\d+)/;
						var matchInterval = autoInterval.exec(optionsWrapper[0].className);

						if(matchInterval != null) { data.options.autorotationSpeed = matchInterval[1]; }
						if(optionsWrapper.is('.autoslide_false')) 	data.options.autorotation = false;
						if(optionsWrapper.is('.autoslide_true')) 	data.options.autorotation = true;
						
					}
			},
			
			/************************************************************************
			methods.useExternalControlls:
			
			check for external controlls
			*************************************************************************/
			useExternalControlls: function()
			{
				var data 	= this.data( pluginNameSpace ), 
					optionsWrapper = this.parents('.slideshow_container:eq(0)'),
					externalContainer;
				
				if(optionsWrapper.length)
				{
					externalContainer = optionsWrapper.next(data.options.externalControlls[0]+':eq(0)');
				}
				else
				{
					externalContainer = this.nextAll(data.options.externalControlls[0]+':eq(0)');
				}
				
				if(externalContainer)
				{
					data.externalControlls = externalContainer.find(data.options.externalControlls[1]);
				}
			}
			
		};



	$.fn.aviationSlider = function(options) 
	{
		return this.each(function()
		{
			var slider =  $(this), data = {}, 
			
			//default slideshow settings. can be overwritten by passing different values when calling the function 
			defaults = 
			{
				autorotation: 		false,				// autorotation true or false?
				autorotationSpeed:	6,					// duration between autorotation switch in Seconds
				slides: 			'li',				// wich element inside the container should serve as slide
				animationSpeed: 	2000,				// animation duration
				appendControlls: 	true,				// should slidecontrolls be appended or should we use none/predefined,
				externalControlls:	['.thumbnails_container','li'], //check for external controlls and apply click binding
				appendCaption: 		false,				// should a caption be created by using the slideshow images alt tag?,
				captionOpacity:		0.7,				// caption opacity
				captionClass:		'slideshow_caption'	// caption class
			};
			
			//merge default options and options passed by the user, then collect some slider data
			data.options 		= $.extend(defaults, options);
			data.size 			= { height: slider.height(), width: slider.width()};
			data.slides  		= slider.find(data.options.slides).css({display:'none'});
			data.slideCount 	= data.slides.length;
			data.currentSlide 	= slider.find(data.options.slides + ':eq(0)').css({display:'block'}) ;
			data.nextSlide	 	= slider.find(data.options.slides + ':eq(1)');
			data.interval 		= false;
			data.timeout 		= {};
			data.animatingNow 	= true;
			data.useCanvas      = false;
			
			//check if browser supports canvas
			if (document.createElement('canvas').getContext) { data.useCanvas = true; }

			//apply data to the slider to keep track of variables and states
			slider.data( pluginNameSpace, data );
			
			//overwrite options with slider specific options if necessary
			methods.overwrite_options.apply( slider );
			
			//initialize the slideshow
			methods.init.apply( slider );
			
			
		});
	};
})(jQuery);











// -------------------------------------------------------------------------------------------
// Slideshow helper, arrows
// -------------------------------------------------------------------------------------------
(function($)
{
	$.fn.avia_hide_slide_controlls = function(variables) 
	{
		return this.each(function()
		{
			var container  = $(this), 
				slideshow = container.find('.slideshow'),
				arrowItems = container.find('.arrowslidecontrolls a');
				arrowItems.css({opacity:0});	
				
				container.hover(
				
					function()
					{
						arrowItems.stop().animate({'opacity':1});
					},
					function(event)
					{
/* 						if(!$(event.relatedTarget).is('.ctrl_arrow')) */
						arrowItems.stop().animate({'opacity':0});
					}
				
				);
			});
	};
})(jQuery);	







/*
 * jQuery 2d Transform v0.9.3
 * http://wiki.github.com/heygrady/transform/
 *
 * Copyright 2010, Grady Kuhnline
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 * 
 * Date: Sat Dec 4 15:46:09 2010 -0800
 */
(function(f,g,j,b){var h=/progid:DXImageTransform\.Microsoft\.Matrix\(.*?\)/,c=/^([\+\-]=)?([\d+.\-]+)(.*)$/,q=/%/;var d=j.createElement("modernizr"),e=d.style;function n(s){return parseFloat(s)}function l(){var s={transformProperty:"",MozTransform:"-moz-",WebkitTransform:"-webkit-",OTransform:"-o-",msTransform:"-ms-"};for(var t in s){if(typeof e[t]!="undefined"){return s[t]}}return null}function r(){if(typeof(g.Modernizr)!=="undefined"){return Modernizr.csstransforms}var t=["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"];for(var s in t){if(e[t[s]]!==b){return true}}}var a=l(),i=a!==null?a+"transform":false,k=a!==null?a+"transform-origin":false;f.support.csstransforms=r();if(a=="-ms-"){i="msTransform";k="msTransformOrigin"}f.extend({transform:function(s){s.transform=this;this.$elem=f(s);this.applyingMatrix=false;this.matrix=null;this.height=null;this.width=null;this.outerHeight=null;this.outerWidth=null;this.boxSizingValue=null;this.boxSizingProperty=null;this.attr=null;this.transformProperty=i;this.transformOriginProperty=k}});f.extend(f.transform,{funcs:["matrix","origin","reflect","reflectX","reflectXY","reflectY","rotate","scale","scaleX","scaleY","skew","skewX","skewY","translate","translateX","translateY"]});f.fn.transform=function(s,t){return this.each(function(){var u=this.transform||new f.transform(this);if(s){u.exec(s,t)}})};f.transform.prototype={exec:function(s,t){t=f.extend(true,{forceMatrix:false,preserve:false},t);this.attr=null;if(t.preserve){s=f.extend(true,this.getAttrs(true,true),s)}else{s=f.extend(true,{},s)}this.setAttrs(s);if(f.support.csstransforms&&!t.forceMatrix){return this.execFuncs(s)}else{if(f.browser.msie||(f.support.csstransforms&&t.forceMatrix)){return this.execMatrix(s)}}return false},execFuncs:function(t){var s=[];for(var u in t){if(u=="origin"){this[u].apply(this,f.isArray(t[u])?t[u]:[t[u]])}else{if(f.inArray(u,f.transform.funcs)!==-1){s.push(this.createTransformFunc(u,t[u]))}}}this.$elem.css(i,s.join(" "));return true},execMatrix:function(z){var C,x,t;var F=this.$elem[0],B=this;function A(N,M){if(q.test(N)){return parseFloat(N)/100*B["safeOuter"+(M?"Height":"Width")]()}return o(F,N)}var s=/translate[X|Y]?/,u=[];for(var v in z){switch(f.type(z[v])){case"array":t=z[v];break;case"string":t=f.map(z[v].split(","),f.trim);break;default:t=[z[v]]}if(f.matrix[v]){if(f.cssAngle[v]){t=f.map(t,f.angle.toDegree)}else{if(!f.cssNumber[v]){t=f.map(t,A)}else{t=f.map(t,n)}}x=f.matrix[v].apply(this,t);if(s.test(v)){u.push(x)}else{C=C?C.x(x):x}}else{if(v=="origin"){this[v].apply(this,t)}}}C=C||f.matrix.identity();f.each(u,function(M,N){C=C.x(N)});var K=parseFloat(C.e(1,1).toFixed(6)),I=parseFloat(C.e(2,1).toFixed(6)),H=parseFloat(C.e(1,2).toFixed(6)),G=parseFloat(C.e(2,2).toFixed(6)),L=C.rows===3?parseFloat(C.e(1,3).toFixed(6)):0,J=C.rows===3?parseFloat(C.e(2,3).toFixed(6)):0;if(f.support.csstransforms&&a==="-moz-"){this.$elem.css(i,"matrix("+K+", "+I+", "+H+", "+G+", "+L+"px, "+J+"px)")}else{if(f.support.csstransforms){this.$elem.css(i,"matrix("+K+", "+I+", "+H+", "+G+", "+L+", "+J+")")}else{if(f.browser.msie){var w=", FilterType='nearest neighbor'";var D=this.$elem[0].style;var E="progid:DXImageTransform.Microsoft.Matrix(M11="+K+", M12="+H+", M21="+I+", M22="+G+", sizingMethod='auto expand'"+w+")";var y=D.filter||f.curCSS(this.$elem[0],"filter")||"";D.filter=h.test(y)?y.replace(h,E):y?y+" "+E:E;this.applyingMatrix=true;this.matrix=C;this.fixPosition(C,L,J);this.applyingMatrix=false;this.matrix=null}}}return true},origin:function(s,t){if(f.support.csstransforms){if(typeof t==="undefined"){this.$elem.css(k,s)}else{this.$elem.css(k,s+" "+t)}return true}switch(s){case"left":s="0";break;case"right":s="100%";break;case"center":case b:s="50%"}switch(t){case"top":t="0";break;case"bottom":t="100%";break;case"center":case b:t="50%"}this.setAttr("origin",[q.test(s)?s:o(this.$elem[0],s)+"px",q.test(t)?t:o(this.$elem[0],t)+"px"]);return true},createTransformFunc:function(t,u){if(t.substr(0,7)==="reflect"){var s=u?f.matrix[t]():f.matrix.identity();return"matrix("+s.e(1,1)+", "+s.e(2,1)+", "+s.e(1,2)+", "+s.e(2,2)+", 0, 0)"}if(t=="matrix"){if(a==="-moz-"){u[4]=u[4]?u[4]+"px":0;u[5]=u[5]?u[5]+"px":0}}return t+"("+(f.isArray(u)?u.join(", "):u)+")"},fixPosition:function(B,y,x,D,s){var w=new f.matrix.calc(B,this.safeOuterHeight(),this.safeOuterWidth()),C=this.getAttr("origin");var v=w.originOffset(new f.matrix.V2(q.test(C[0])?parseFloat(C[0])/100*w.outerWidth:parseFloat(C[0]),q.test(C[1])?parseFloat(C[1])/100*w.outerHeight:parseFloat(C[1])));var t=w.sides();var u=this.$elem.css("position");if(u=="static"){u="relative"}var A={top:0,left:0};var z={position:u,top:(v.top+x+t.top+A.top)+"px",left:(v.left+y+t.left+A.left)+"px",zoom:1};this.$elem.css(z)}};function o(s,u){var t=c.exec(f.trim(u));if(t[3]&&t[3]!=="px"){var w="paddingBottom",v=f.style(s,w);f.style(s,w,u);u=p(s,w);f.style(s,w,v);return u}return parseFloat(u)}function p(t,u){if(t[u]!=null&&(!t.style||t.style[u]==null)){return t[u]}var s=parseFloat(f.css(t,u));return s&&s>-10000?s:0}})(jQuery,this,this.document);(function(d,c,a,f){d.extend(d.transform.prototype,{safeOuterHeight:function(){return this.safeOuterLength("height")},safeOuterWidth:function(){return this.safeOuterLength("width")},safeOuterLength:function(l){var p="outer"+(l=="width"?"Width":"Height");if(!d.support.csstransforms&&d.browser.msie){l=l=="width"?"width":"height";if(this.applyingMatrix&&!this[p]&&this.matrix){var k=new d.matrix.calc(this.matrix,1,1),n=k.offset(),g=this.$elem[p]()/n[l];this[p]=g;return g}else{if(this.applyingMatrix&&this[p]){return this[p]}}var o={height:["top","bottom"],width:["left","right"]};var h=this.$elem[0],j=parseFloat(d.curCSS(h,l,true)),q=this.boxSizingProperty,i=this.boxSizingValue;if(!this.boxSizingProperty){q=this.boxSizingProperty=e()||"box-sizing";i=this.boxSizingValue=this.$elem.css(q)||"content-box"}if(this[p]&&this[l]==j){return this[p]}else{this[l]=j}if(q&&(i=="padding-box"||i=="content-box")){j+=parseFloat(d.curCSS(h,"padding-"+o[l][0],true))||0+parseFloat(d.curCSS(h,"padding-"+o[l][1],true))||0}if(q&&i=="content-box"){j+=parseFloat(d.curCSS(h,"border-"+o[l][0]+"-width",true))||0+parseFloat(d.curCSS(h,"border-"+o[l][1]+"-width",true))||0}this[p]=j;return j}return this.$elem[p]()}});var b=null;function e(){if(b){return b}var h={boxSizing:"box-sizing",MozBoxSizing:"-moz-box-sizing",WebkitBoxSizing:"-webkit-box-sizing",OBoxSizing:"-o-box-sizing"},g=a.body;for(var i in h){if(typeof g.style[i]!="undefined"){b=h[i];return b}}return null}})(jQuery,this,this.document);(function(g,f,b,h){var d=/([\w\-]*?)\((.*?)\)/g,a="data-transform",e=/\s/,c=/,\s?/;g.extend(g.transform.prototype,{setAttrs:function(i){var j="",l;for(var k in i){l=i[k];if(g.isArray(l)){l=l.join(", ")}j+=" "+k+"("+l+")"}this.attr=g.trim(j);this.$elem.attr(a,this.attr)},setAttr:function(k,l){if(g.isArray(l)){l=l.join(", ")}var j=this.attr||this.$elem.attr(a);if(!j||j.indexOf(k)==-1){this.attr=g.trim(j+" "+k+"("+l+")");this.$elem.attr(a,this.attr)}else{var i=[],n;d.lastIndex=0;while(n=d.exec(j)){if(k==n[1]){i.push(k+"("+l+")")}else{i.push(n[0])}}this.attr=i.join(" ");this.$elem.attr(a,this.attr)}},getAttrs:function(){var j=this.attr||this.$elem.attr(a);if(!j){return{}}var i={},l,k;d.lastIndex=0;while((l=d.exec(j))!==null){if(l){k=l[2].split(c);i[l[1]]=k.length==1?k[0]:k}}return i},getAttr:function(j){var i=this.getAttrs();if(typeof i[j]!=="undefined"){return i[j]}if(j==="origin"&&g.support.csstransforms){return this.$elem.css(this.transformOriginProperty).split(e)}else{if(j==="origin"){return["50%","50%"]}}return g.cssDefault[j]||0}});if(typeof(g.cssAngle)=="undefined"){g.cssAngle={}}g.extend(g.cssAngle,{rotate:true,skew:true,skewX:true,skewY:true});if(typeof(g.cssDefault)=="undefined"){g.cssDefault={}}g.extend(g.cssDefault,{scale:[1,1],scaleX:1,scaleY:1,matrix:[1,0,0,1,0,0],origin:["50%","50%"],reflect:[1,0,0,1,0,0],reflectX:[1,0,0,1,0,0],reflectXY:[1,0,0,1,0,0],reflectY:[1,0,0,1,0,0]});if(typeof(g.cssMultipleValues)=="undefined"){g.cssMultipleValues={}}g.extend(g.cssMultipleValues,{matrix:6,origin:{length:2,duplicate:true},reflect:6,reflectX:6,reflectXY:6,reflectY:6,scale:{length:2,duplicate:true},skew:2,translate:2});g.extend(g.cssNumber,{matrix:true,reflect:true,reflectX:true,reflectXY:true,reflectY:true,scale:true,scaleX:true,scaleY:true});g.each(g.transform.funcs,function(j,k){g.cssHooks[k]={set:function(n,o){var l=n.transform||new g.transform(n),i={};i[k]=o;l.exec(i,{preserve:true})},get:function(n,l){var i=n.transform||new g.transform(n);return i.getAttr(k)}}});g.each(["reflect","reflectX","reflectXY","reflectY"],function(j,k){g.cssHooks[k].get=function(n,l){var i=n.transform||new g.transform(n);return i.getAttr("matrix")||g.cssDefault[k]}})})(jQuery,this,this.document);(function(e,g,h,c){var d=/^([+\-]=)?([\d+.\-]+)(.*)$/;var a=e.fn.animate;e.fn.animate=function(p,l,o,n){var k=e.speed(l,o,n),j=e.cssMultipleValues;k.complete=k.old;if(!e.isEmptyObject(p)){if(typeof k.original==="undefined"){k.original={}}e.each(p,function(s,u){if(j[s]||e.cssAngle[s]||(!e.cssNumber[s]&&e.inArray(s,e.transform.funcs)!==-1)){var t=null;if(jQuery.isArray(p[s])){var r=1,q=u.length;if(j[s]){r=(typeof j[s].length==="undefined"?j[s]:j[s].length)}if(q>r||(q<r&&q==2)||(q==2&&r==2&&isNaN(parseFloat(u[q-1])))){t=u[q-1];u.splice(q-1,1)}}k.original[s]=u.toString();p[s]=parseFloat(u)}})}return a.apply(this,[arguments[0],k])};var b="paddingBottom";function i(k,l){if(k[l]!=null&&(!k.style||k.style[l]==null)){}var j=parseFloat(e.css(k,l));return j&&j>-10000?j:0}var f=e.fx.prototype.custom;e.fx.prototype.custom=function(u,v,w){var y=e.cssMultipleValues[this.prop],p=e.cssAngle[this.prop];if(y||(!e.cssNumber[this.prop]&&e.inArray(this.prop,e.transform.funcs)!==-1)){this.values=[];if(!y){y=1}var x=this.options.original[this.prop],t=e(this.elem).css(this.prop),j=e.cssDefault[this.prop]||0;if(!e.isArray(t)){t=[t]}if(!e.isArray(x)){if(e.type(x)==="string"){x=x.split(",")}else{x=[x]}}var l=y.length||y,s=0;while(x.length<l){x.push(y.duplicate?x[0]:j[s]||0);s++}var k,r,q,o=this,n=o.elem.transform;orig=e.style(o.elem,b);e.each(x,function(z,A){if(t[z]){k=t[z]}else{if(j[z]&&!y.duplicate){k=j[z]}else{if(y.duplicate){k=t[0]}else{k=0}}}if(p){k=e.angle.toDegree(k)}else{if(!e.cssNumber[o.prop]){r=d.exec(e.trim(k));if(r[3]&&r[3]!=="px"){if(r[3]==="%"){k=parseFloat(r[2])/100*n["safeOuter"+(z?"Height":"Width")]()}else{e.style(o.elem,b,k);k=i(o.elem,b);e.style(o.elem,b,orig)}}}}k=parseFloat(k);r=d.exec(e.trim(A));if(r){q=parseFloat(r[2]);w=r[3]||"px";if(p){q=e.angle.toDegree(q+w);w="deg"}else{if(!e.cssNumber[o.prop]&&w==="%"){k=(k/n["safeOuter"+(z?"Height":"Width")]())*100}else{if(!e.cssNumber[o.prop]&&w!=="px"){e.style(o.elem,b,(q||1)+w);k=((q||1)/i(o.elem,b))*k;e.style(o.elem,b,orig)}}}if(r[1]){q=((r[1]==="-="?-1:1)*q)+k}}else{q=A;w=""}o.values.push({start:k,end:q,unit:w})})}return f.apply(this,arguments)};e.fx.multipleValueStep={_default:function(j){e.each(j.values,function(k,l){j.values[k].now=l.start+((l.end-l.start)*j.pos)})}};e.each(["matrix","reflect","reflectX","reflectXY","reflectY"],function(j,k){e.fx.multipleValueStep[k]=function(n){var p=n.decomposed,l=e.matrix;m=l.identity();p.now={};e.each(p.start,function(q){p.now[q]=parseFloat(p.start[q])+((parseFloat(p.end[q])-parseFloat(p.start[q]))*n.pos);if(((q==="scaleX"||q==="scaleY")&&p.now[q]===1)||(q!=="scaleX"&&q!=="scaleY"&&p.now[q]===0)){return true}m=m.x(l[q](p.now[q]))});var o;e.each(n.values,function(q){switch(q){case 0:o=parseFloat(m.e(1,1).toFixed(6));break;case 1:o=parseFloat(m.e(2,1).toFixed(6));break;case 2:o=parseFloat(m.e(1,2).toFixed(6));break;case 3:o=parseFloat(m.e(2,2).toFixed(6));break;case 4:o=parseFloat(m.e(1,3).toFixed(6));break;case 5:o=parseFloat(m.e(2,3).toFixed(6));break}n.values[q].now=o})}});e.each(e.transform.funcs,function(j,k){e.fx.step[k]=function(o){var n=o.elem.transform||new e.transform(o.elem),l={};if(e.cssMultipleValues[k]||(!e.cssNumber[k]&&e.inArray(k,e.transform.funcs)!==-1)){(e.fx.multipleValueStep[o.prop]||e.fx.multipleValueStep._default)(o);l[o.prop]=[];e.each(o.values,function(p,q){l[o.prop].push(q.now+(e.cssNumber[o.prop]?"":q.unit))})}else{l[o.prop]=o.now+(e.cssNumber[o.prop]?"":o.unit)}n.exec(l,{preserve:true})}});e.each(["matrix","reflect","reflectX","reflectXY","reflectY"],function(j,k){e.fx.step[k]=function(q){var p=q.elem.transform||new e.transform(q.elem),o={};if(!q.initialized){q.initialized=true;if(k!=="matrix"){var n=e.matrix[k]().elements;var r;e.each(q.values,function(s){switch(s){case 0:r=n[0];break;case 1:r=n[2];break;case 2:r=n[1];break;case 3:r=n[3];break;default:r=0}q.values[s].end=r})}q.decomposed={};var l=q.values;q.decomposed.start=e.matrix.matrix(l[0].start,l[1].start,l[2].start,l[3].start,l[4].start,l[5].start).decompose();q.decomposed.end=e.matrix.matrix(l[0].end,l[1].end,l[2].end,l[3].end,l[4].end,l[5].end).decompose()}(e.fx.multipleValueStep[q.prop]||e.fx.multipleValueStep._default)(q);o.matrix=[];e.each(q.values,function(s,t){o.matrix.push(t.now)});p.exec(o,{preserve:true})}})})(jQuery,this,this.document);(function(g,h,j,c){var d=180/Math.PI;var k=200/Math.PI;var f=Math.PI/180;var e=2/1.8;var i=0.9;var a=Math.PI/200;var b=/^([+\-]=)?([\d+.\-]+)(.*)$/;g.extend({angle:{runit:/(deg|g?rad)/,radianToDegree:function(l){return l*d},radianToGrad:function(l){return l*k},degreeToRadian:function(l){return l*f},degreeToGrad:function(l){return l*e},gradToDegree:function(l){return l*i},gradToRadian:function(l){return l*a},toDegree:function(n){var l=b.exec(n);if(l){n=parseFloat(l[2]);switch(l[3]||"deg"){case"grad":n=g.angle.gradToDegree(n);break;case"rad":n=g.angle.radianToDegree(n);break}return n}return 0}}})})(jQuery,this,this.document);(function(f,e,b,g){if(typeof(f.matrix)=="undefined"){f.extend({matrix:{}})}var d=f.matrix;f.extend(d,{V2:function(h,i){if(f.isArray(arguments[0])){this.elements=arguments[0].slice(0,2)}else{this.elements=[h,i]}this.length=2},V3:function(h,j,i){if(f.isArray(arguments[0])){this.elements=arguments[0].slice(0,3)}else{this.elements=[h,j,i]}this.length=3},M2x2:function(i,h,k,j){if(f.isArray(arguments[0])){this.elements=arguments[0].slice(0,4)}else{this.elements=Array.prototype.slice.call(arguments).slice(0,4)}this.rows=2;this.cols=2},M3x3:function(n,l,k,j,i,h,q,p,o){if(f.isArray(arguments[0])){this.elements=arguments[0].slice(0,9)}else{this.elements=Array.prototype.slice.call(arguments).slice(0,9)}this.rows=3;this.cols=3}});var c={e:function(k,h){var i=this.rows,j=this.cols;if(k>i||h>i||k<1||h<1){return 0}return this.elements[(k-1)*j+h-1]},decompose:function(){var v=this.e(1,1),t=this.e(2,1),q=this.e(1,2),p=this.e(2,2),o=this.e(1,3),n=this.e(2,3);if(Math.abs(v*p-t*q)<0.01){return{rotate:0+"deg",skewX:0+"deg",scaleX:1,scaleY:1,translateX:0+"px",translateY:0+"px"}}var l=o,j=n;var u=Math.sqrt(v*v+t*t);v=v/u;t=t/u;var i=v*q+t*p;q-=v*i;p-=t*i;var s=Math.sqrt(q*q+p*p);q=q/s;p=p/s;i=i/s;if((v*p-t*q)<0){v=-v;t=-t;u=-u}var w=f.angle.radianToDegree;var h=w(Math.atan2(t,v));i=w(Math.atan(i));return{rotate:h+"deg",skewX:i+"deg",scaleX:u,scaleY:s,translateX:l+"px",translateY:j+"px"}}};f.extend(d.M2x2.prototype,c,{toM3x3:function(){var h=this.elements;return new d.M3x3(h[0],h[1],0,h[2],h[3],0,0,0,1)},x:function(j){var k=typeof(j.rows)==="undefined";if(!k&&j.rows==3){return this.toM3x3().x(j)}var i=this.elements,h=j.elements;if(k&&h.length==2){return new d.V2(i[0]*h[0]+i[1]*h[1],i[2]*h[0]+i[3]*h[1])}else{if(h.length==i.length){return new d.M2x2(i[0]*h[0]+i[1]*h[2],i[0]*h[1]+i[1]*h[3],i[2]*h[0]+i[3]*h[2],i[2]*h[1]+i[3]*h[3])}}return false},inverse:function(){var i=1/this.determinant(),h=this.elements;return new d.M2x2(i*h[3],i*-h[1],i*-h[2],i*h[0])},determinant:function(){var h=this.elements;return h[0]*h[3]-h[1]*h[2]}});f.extend(d.M3x3.prototype,c,{x:function(j){var k=typeof(j.rows)==="undefined";if(!k&&j.rows<3){j=j.toM3x3()}var i=this.elements,h=j.elements;if(k&&h.length==3){return new d.V3(i[0]*h[0]+i[1]*h[1]+i[2]*h[2],i[3]*h[0]+i[4]*h[1]+i[5]*h[2],i[6]*h[0]+i[7]*h[1]+i[8]*h[2])}else{if(h.length==i.length){return new d.M3x3(i[0]*h[0]+i[1]*h[3]+i[2]*h[6],i[0]*h[1]+i[1]*h[4]+i[2]*h[7],i[0]*h[2]+i[1]*h[5]+i[2]*h[8],i[3]*h[0]+i[4]*h[3]+i[5]*h[6],i[3]*h[1]+i[4]*h[4]+i[5]*h[7],i[3]*h[2]+i[4]*h[5]+i[5]*h[8],i[6]*h[0]+i[7]*h[3]+i[8]*h[6],i[6]*h[1]+i[7]*h[4]+i[8]*h[7],i[6]*h[2]+i[7]*h[5]+i[8]*h[8])}}return false},inverse:function(){var i=1/this.determinant(),h=this.elements;return new d.M3x3(i*(h[8]*h[4]-h[7]*h[5]),i*(-(h[8]*h[1]-h[7]*h[2])),i*(h[5]*h[1]-h[4]*h[2]),i*(-(h[8]*h[3]-h[6]*h[5])),i*(h[8]*h[0]-h[6]*h[2]),i*(-(h[5]*h[0]-h[3]*h[2])),i*(h[7]*h[3]-h[6]*h[4]),i*(-(h[7]*h[0]-h[6]*h[1])),i*(h[4]*h[0]-h[3]*h[1]))},determinant:function(){var h=this.elements;return h[0]*(h[8]*h[4]-h[7]*h[5])-h[3]*(h[8]*h[1]-h[7]*h[2])+h[6]*(h[5]*h[1]-h[4]*h[2])}});var a={e:function(h){return this.elements[h-1]}};f.extend(d.V2.prototype,a);f.extend(d.V3.prototype,a)})(jQuery,this,this.document);(function(c,b,a,d){if(typeof(c.matrix)=="undefined"){c.extend({matrix:{}})}c.extend(c.matrix,{calc:function(e,f,g){this.matrix=e;this.outerHeight=f;this.outerWidth=g}});c.matrix.calc.prototype={coord:function(e,i,h){h=typeof(h)!=="undefined"?h:0;var g=this.matrix,f;switch(g.rows){case 2:f=g.x(new c.matrix.V2(e,i));break;case 3:f=g.x(new c.matrix.V3(e,i,h));break}return f},corners:function(e,h){var f=!(typeof(e)!=="undefined"||typeof(h)!=="undefined"),g;if(!this.c||!f){h=h||this.outerHeight;e=e||this.outerWidth;g={tl:this.coord(0,0),bl:this.coord(0,h),tr:this.coord(e,0),br:this.coord(e,h)}}else{g=this.c}if(f){this.c=g}return g},sides:function(e){var f=e||this.corners();return{top:Math.min(f.tl.e(2),f.tr.e(2),f.br.e(2),f.bl.e(2)),bottom:Math.max(f.tl.e(2),f.tr.e(2),f.br.e(2),f.bl.e(2)),left:Math.min(f.tl.e(1),f.tr.e(1),f.br.e(1),f.bl.e(1)),right:Math.max(f.tl.e(1),f.tr.e(1),f.br.e(1),f.bl.e(1))}},offset:function(e){var f=this.sides(e);return{height:Math.abs(f.bottom-f.top),width:Math.abs(f.right-f.left)}},area:function(e){var h=e||this.corners();var g={x:h.tr.e(1)-h.tl.e(1)+h.br.e(1)-h.bl.e(1),y:h.tr.e(2)-h.tl.e(2)+h.br.e(2)-h.bl.e(2)},f={x:h.bl.e(1)-h.tl.e(1)+h.br.e(1)-h.tr.e(1),y:h.bl.e(2)-h.tl.e(2)+h.br.e(2)-h.tr.e(2)};return 0.25*Math.abs(g.e(1)*f.e(2)-g.e(2)*f.e(1))},nonAffinity:function(){var f=this.sides(),g=f.top-f.bottom,e=f.left-f.right;return parseFloat(parseFloat(Math.abs((Math.pow(g,2)+Math.pow(e,2))/(f.top*f.bottom+f.left*f.right))).toFixed(8))},originOffset:function(h,g){h=h?h:new c.matrix.V2(this.outerWidth*0.5,this.outerHeight*0.5);g=g?g:new c.matrix.V2(0,0);var e=this.coord(h.e(1),h.e(2));var f=this.coord(g.e(1),g.e(2));return{top:(f.e(2)-g.e(2))-(e.e(2)-h.e(2)),left:(f.e(1)-g.e(1))-(e.e(1)-h.e(1))}}}})(jQuery,this,this.document);(function(e,d,a,f){if(typeof(e.matrix)=="undefined"){e.extend({matrix:{}})}var c=e.matrix,g=c.M2x2,b=c.M3x3;e.extend(c,{identity:function(k){k=k||2;var l=k*k,n=new Array(l),j=k+1;for(var h=0;h<l;h++){n[h]=(h%j)===0?1:0}return new c["M"+k+"x"+k](n)},matrix:function(){var h=Array.prototype.slice.call(arguments);switch(arguments.length){case 4:return new g(h[0],h[2],h[1],h[3]);case 6:return new b(h[0],h[2],h[4],h[1],h[3],h[5],0,0,1)}},reflect:function(){return new g(-1,0,0,-1)},reflectX:function(){return new g(1,0,0,-1)},reflectXY:function(){return new g(0,1,1,0)},reflectY:function(){return new g(-1,0,0,1)},rotate:function(l){var i=e.angle.degreeToRadian(l),k=Math.cos(i),n=Math.sin(i);var j=k,h=n,p=-n,o=k;return new g(j,p,h,o)},scale:function(i,h){i=i||i===0?i:1;h=h||h===0?h:i;return new g(i,0,0,h)},scaleX:function(h){return c.scale(h,1)},scaleY:function(h){return c.scale(1,h)},skew:function(k,i){k=k||0;i=i||0;var l=e.angle.degreeToRadian(k),j=e.angle.degreeToRadian(i),h=Math.tan(l),n=Math.tan(j);return new g(1,h,n,1)},skewX:function(h){return c.skew(h)},skewY:function(h){return c.skew(0,h)},translate:function(i,h){i=i||0;h=h||0;return new b(1,0,i,0,1,h,0,0,1)},translateX:function(h){return c.translate(h)},translateY:function(h){return c.translate(0,h)}})})(jQuery,this,this.document);

