// JavaScript Document
Number.implement({

	/*
	Property: numberFormat
		Format a number with grouped thousands.

	Arguments:
		decimals, optional - integer, number of decimal percision; default, 2
		dec_point, optional - string, decimal point notation; default, '.'
		thousands_sep, optional - string, grouped thousands notation; default, ','

	Returns:
		a formatted version of number.

	Example:
		>(36432.556).()  // returns 36,432.56
		>(36432.556).numberFormat(2, '.', ',')  // returns 36,432.56
	*/

	numberFormat : function(decimals, dec_point, thousands_sep) {
		decimals = Math.abs(decimals) + 1 ? decimals : 2;
		dec_point = dec_point || '.';
		thousands_sep = thousands_sep || ',';
	
		var matches = /(-)?(\d+)(\.\d+)?/.exec((isNaN(this) ? 0 : this) + ''); // returns matches[1] as sign, matches[2] as numbers and matches[3] as decimals
		var remainder = matches[2].length > 3 ? matches[2].length % 3 : 0;
		return (matches[1] ? matches[1] : '') + (remainder ? matches[2].substr(0, remainder) + thousands_sep : '') + matches[2].substr(remainder).replace(/(\d{3})(?=\d)/g, "$1" + thousands_sep) + 
				(decimals ? dec_point + (+matches[3] || 0).toFixed(decimals).substr(2) : '');
	}


});


/////////////////////////////////////////////////////domready/////////////////////////////////////////////////////
window.addEvent('domready', function(){
/////////////////////////////////////////////////////options////////////////////////////////////////////
var options = {
'vat': 20,
'delivery': 6.50,
'delVar': 120,
'imgW': 70,
'imgH': 70,
'alt': 'cartImage',
'currency': '\u00A3',
'cartHeight': 76,
'popHeight': 60,
'popTransition': 'sine:in:out',
'duration': 300,
'background': '#F60',
'popOpacity': 0.7,
'tipOpacity': 'in',
'menuWidth': '202px'
};
options['cartMessages'] = [
'We accept Paypal',
'All prices excl. VAT',
'You can drag products to cart',
'Free delivery on orders over '+ options['currency']+'120',
'Delivery '+options['currency']+'6.50'+' otherwise'
];
//new UvumiDropdown('login');
if($('searchInput')){
var t = $('searchInput');
  t.addEvents({
    'focus': function() { t.value = (t.value == 'Search Site...' ? '' : t.value); },
    'blur': function()  { t.value = (t.value == '' ? 'Search Site...' : t.value); }
  });
}
if($('more')){
		moreClick();
		}
$$('input.quantity').each(function(el){
	var def = el.get('value');
	el.addEvents({
		'focus': function() { el.select(); },
    	'blur': function()  { 
		 if(isNaN(el.get('value')) || el.value == ''){
		 	el.value = def;
			Sexy.error('<h1>PS Glass Fittings</h1><br/><p>The quantity you typed does not appear to be a number, please type numeric values only.</p>'); 
		 }
		 }
		});
	});
/////////////////////////////slide it moo/////////////////////////////

if($('SlideItMoo_info_outer')){
$$('.SlideItMoo_back', '.SlideItMoo_forward').fade('hide');
			/*  Create SlideItMoo instance  */	
			var sMoo = new SlideItMoo({
				overallContainer: 'SlideItMoo_info_outer',
				elementScrolled: 'SlideItMoo_info_inner',
				thumbsContainer: 'SlideItMoo_info_items',		
				itemsSelector: '.info_item',
				itemsVisible:1,				
				itemWidth:600,
				showControls:1,
				autoSlide: 5000,
				transition: Fx.Transitions.Back.easeIn,
				duration: 800,
				direction:1,
				/* the onChange event fires when the current slide changes. We'll use it to display the next/previous article title ( in #announce ) */
				onChange: function( index ){					
				}
			});	
			if($$('.slide_item').length > 3){
			$('SlideItMoo_info_outer').addEvents({
												 'mouseenter': function(){
													 $$('.SlideItMoo_back', '.SlideItMoo_forward').fade(.7);
													 },
												  'mouseleave': function(){
													 $$('.SlideItMoo_back', '.SlideItMoo_forward').fade('out');
													 }	 
												 });	
			}
}

/////////////////////////////submit link select text/////////////////////////////

if($('linkInformation')){
$('linkInformation').getElements('dd.selectMe').each(function(el) {
		//add double-click and blur events
		el.addEvent('click',function() {					 
			//store "before" message
			var before = el.get('html').trim();
			//erase current
			el.set('html','');
			//replace current text/content with input or textarea element
			if(el.hasClass('textarea'))
			{
				var input = new Element('textarea', { 'class':'box', 'html':before, 'readonly': 'readonly'});
			}
			else
			{
				var input = new Element('input', { 'class':'box', 'value':before, 'readonly': 'readonly' });
				//blur input when they press "Enter"
				input.addEvent('keydown', function(e) { if(e.key == 'enter') { this.fireEvent('blur'); } });
			}
			input.inject(el).select();
			//add blur event to input
			input.addEvents({
							'blur': function(){
									el.set('html',before).addClass(before != '' ? '' : 'editable-empty');
								},
							 'click': function(e){
								 e.stop()
								 return;
								 }
							});
		});
	});
}

/////////////////////////////////////////////////////hide email image////////////////////////////

$$('.productContainer', '.leftContainer').each(function(el){
								   var email = el.getElement('.productEmail');
								   if(email){
								   email.fade('hide');
								   }
								   el.addEvents({
												'mouseenter': function(ev){
													if(email){
													email.fade('in')
													}
													},
												'mouseleave': function(ev){
													if(email){
													email.fade('out');
													}
													}	
												});
								   });

/////////////////////////////////////////////////////open modal////////////////////////////

$$('.modal').each(function(el){
						   el.addEvent('click', function(ev){
										ev.stop();
										overlay.open();
										openModal(el.get('rel'), el.get('href'));
										})
						   
						   });

/////////////////////////////////////////////////////overlay////////////////////////////

var overlay = new Overlay(document.body,{
	id: 'overlay',
	color: '#000',
	duration: 300,
	opacity: 0.7,
	onClick: function() {
		this.close();
		$('modal').fade('out').destroy();

	},
	onShow: function() {
		//make ajax call while the overlay is happening...?
		//var Request = new Request()....
	}
});

/////////////////////////////admin edittable content/////////////////////////////

$$('.setting').each(function(el) {
		//add double-click and blur events
		el.addEvent('click',function() {
			var parent = el.getParent('div.acContentContainer');
			var sel = $('admin').getElement('select.settingChoice');
			var selected = sel.getSelected();
			selected = selected[0].value.replace(/http:\/\//g,'');
			var splitted = selected.split('/');
			selected = splitted[splitted.length -1].replace(/~/g, '/');
			if(selected == 'administration')selected = 'default';
			parent.setStyle('height', 'auto');						 
			//store "before" message
			var before = el.get('html').trim();
			//erase current
			el.set('html','');
			//replace current text/content with input or textarea element
			if(el.hasClass('textarea'))
			{
				var input = new Element('textarea', { 'class':'box', 'html':before });
			}
			else
			{
				var input = new Element('input', { 'class':'box', 'value':before });
				//blur input when they press "Enter"
				input.addEvent('keydown', function(e) { if(e.key == 'enter') { this.fireEvent('blur'); } });
			}
			input.inject(el).select();
			//add blur event to input
			input.addEvents({
							'blur': function(){
									
									//get value, place it in original element
									val = input.get('value').trim();
									el.set('html',val).addClass(val != '' ? '' : 'editable-empty');
									var content = el.get('html');
									if(content != before){
									if(content == '--')content = '';
									//save respective record
									var url = 'administration';
									var request = new Request({
										url:url,
										method:'post',
										data: {
											'adminPage': selected,
											'content': content,
											'id': el.get('rel')
											},
										onRequest: function() {
										},
										onSuccess: function(){
										var height = parent.getHeight();
										parent.setStyle('height', height);
										}
									}).send();
									}
									else{
										var height = parent.getHeight();
										parent.setStyle('height', height);
										}
								},
							 'click': function(e){
								 e.stop()
								 return;
								 }
							});
		});
	});

/////////////////////////////admin settings drop down/////////////////////////////////

if($('admin')){
var sel = $('admin').getElement('select.settingChoice');
if(sel){
sel.addEvent('change',function(ev){
							   var selected = sel.getSelected();
							   selected = selected[0].value;
							   window.location = selected;
							   });
}
}

/////////////////////////////hide info boxes on click/////////////////////////////////

var boxes = $$('div.errorBox', 'div.alertBox', 'div.infoBox');
boxes.each(function(el){
					el.getElement('img.error').setStyle('cursor', 'pointer');
					el.getElement('img.error').addEvent('click', function(){
												  el.nix(true);
												  })
					})

/////////////////////////////////////////////accordion tween open span/////////////////////////////////

var toggles = $$('.toggler');
var content = $$('.acContentContainer');
toggles.each(function(el){
					  el.addEvents({
					  'mouseenter': function(){
						  var t = el.getParent().getElement('span.acStatus');
						  t.set('tween', {
								'duration': 'short'
								})
						  t.tween('color', '#F60');
						  },
					  'mouseleave':  function(){
						  var t = el.getParent().getElement('span.acStatus');
						  t.tween('color', '#666');
						  }
				  })
});

/////////////////////////////////////////////cart opacity on focue/////////////////////////////////

if($('cartContent')){
cartOpacity();
}

/////////////////////////////////////////////cart messages marquee/////////////////////////////////

if($('cartScroll')){
fxmq = new Fx.Marquee($('cartScroll'), {
	duration: 500,
	showEffect: {
		top: [0,0], //reset the top every time to zero
		left: [-100, 0],
		opacity: [0,1]
	},
	hideEffect: {
		top: 20
	},
	revertEffect: {
		top: [-30, 0],
		left: [0,0] //reset the left back to zero on revert
	}
});

cartMessages(fxmq,options);
}

/////////////////////////////////////////////////////fade alerts///////////////////////////////////

$$('div.fade').each(function(el){
							 el.set('fade');
							 el.nix.delay(3000, el);
							 });

/////////////////////////////////////////////////////add Drawing///////////////////////////////////

if($('addProduct')){
	var add = $('addProduct');
	add.addEvent('click', function(ev){
								  if(add.hasClass('slideSelect')){
									  addSlideSelect(add);
									  }
									  else{
								  		addSelect(add);
									  }
								   })
	}

/////////////////////////////////////////////////////delete product///////////////////////////////////

$$('a.deleteProductRow').each(function(el){
					 el.addEvent('click',function(ev){
							ev.stop();
							Sexy.confirm('<h1>PS Glass Fittings</h1><br/><p>Are you sure you want to delete this product. Deleting products can mess up peoples history, invoices and future orders</p>', {	  
							  textBoxBtnOk: 'Yes',
	  						  textBoxBtnCancel: 'No',
							  onComplete:
								function(returnvalue) {
								  if (returnvalue) {
								  window.location=el.href;
								  }
								}
							  });					  
						})
					 });

/////////////////////////////////////////////////////delete link///////////////////////////////////

$$('a.deleteLinkRow').each(function(el){
					 el.addEvent('click',function(ev){
							ev.stop();
							Sexy.confirm('<h1>PS Glass Fittings</h1><br/><p>Are you sure you want to delete this link?</p>', {	  
							  textBoxBtnOk: 'Yes',
	  						  textBoxBtnCancel: 'No',
							  onComplete:
								function(returnvalue) {
								  if (returnvalue) {
								  window.location=el.href;
								  }
								}
							  });					  
						})
					 });

/////////////////////////////////////////////////////formcheck//////////////////////////////////////////

if($('loginForm')){
$('loginForm').addEvent('submit',function(){
									  $each($$('input[type=submit]'),function(el) {
									  el.disabled = 1,
									  el.setStyles({
												   'border-color': '#999',
												   'background': '#F4F4F4',
												   'color': '#999',
												   'cursor': 'text'
												   })
									  });
										  })
}
var addCheck = new FormCheck('addProductForm', {
							 submit: false,
							 onValidateSuccess: function(form){
								 	$('addProductForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
							 });

var editUser = new FormCheck('editUserForm', {
							 submit: false,
							 onValidateSuccess: function(form){
								 	$('editUserForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
							 });

var linkCheck = new FormCheck('linkForm', {
							  submit: false,
							 onValidateSuccess: function(form){
								 	$('linkForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });
var marketCheck = new FormCheck('marketForm', {
								submit: false,
							 onValidateSuccess: function(form){
								 	$('marketForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });
var editCheck = new FormCheck('editProductForm', {
							  submit: false,
							 onValidateSuccess: function(form){
								 	$('editProductForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });
var newOrderCheck = new FormCheck('newOrderForm', {
								  submit: false,
							 onValidateSuccess: function(form){
								 	$('newOrderForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });
var regCheck = new FormCheck('regForm', {
							 submit: false,
							 onValidateSuccess: function(form){
								 	$('regForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });
var reviewCheck = new FormCheck('reviewForm', {
								submit: false,
							 onValidateSuccess: function(form){
								 	$('reviewForm').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });
var loginCheck = new FormCheck('login-form', {
							   submit: false,
							 onValidateSuccess: function(form){
								 	$('login-form').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });

var forgotPass = new FormCheck('forgotPass', {
							   submit: false,
							 onValidateSuccess: function(form){
								 	$('forgotPass').submit();
									$each($$('input[type=submit]'),function(el) {
									el.disabled = 1,
									el.setStyles({
												 'border-color': '#999',
												 'background': '#F4F4F4',
												 'color': '#999',
												 'cursor': 'text'
												 })
									});
								 }
								 });

/////////////////////////////changePassword/////////////////////////////////

if($('changePassword')){
	$('changePassword').addEvent('click',function(ev){
							ev.stop();
							var li = new Element('li');
							var label = new Element('label');
							var input = new Element('input', {type: 'password'});
							var span = new Element('span',{'class': 'orange','text': '*'});
							var oldPassLabel = label.clone().set('html','<span class="orange">*</span> Old Password');
							var oldPass = input.clone().setProperties({'name': 'oldPass','class': "validate['required']", 'id': 'oldPass'});
							var passLabel = label.clone().set('html','<span class="orange">*</span> New Password');
							var pass = input.clone().setProperties({'name': 'password', 'class': "validate['required']", 'id': 'password'});
							var conLabel = label.clone().set('html','<span class="orange">*</span> Confirm Password');
							var con = input.clone().setProperties({'name': 'confirm', 'class': "validate['confirm[password]']", 'id': 'confirm'});
							var one = li.clone().adopt(oldPassLabel, oldPass);
							var two = li.clone().adopt(passLabel, pass);
							var three = li.clone().adopt(conLabel, con);
							var par = $('changePassword').getParent('li');
							one.replaces(par);
							two.inject(one, 'after');
							three.inject(two, 'after');
							editUser.register($('oldPass'));
							editUser.register($('password'));
							editUser.register($('confirm'));
							})
	}
	
/////////////////////////////////////////////////////top products/////////////////////////////////////							

if($('topProducts')){
new viewer($$('#productBox img)'),{
			mode: ['top','right','bottom','left'],
			fxOptions: {duration:1200}
			}).play(true);
}

/////////////////////////////////////////////////////login panel////////////////////////////////////						

if($('loginToggle')){
$('loginToggle').addEvent('click', function(e){
											openPanel();
											e.stop();										
											})

$('closePanel').addEvent('click', function(ev){
										   ev.stop();
										   closePanel();
										   })
}

/////////////////////////////////////////////////////tooltips/////////////////////////////////////////////////////	

var toTip = $$('a.removeCart', 'a.info', '.tipMe');
toTip.each(function(element,index) {
	var content = element.get('title').split('::');
	element.store('tip:title', content[0]);
	var con = content[1].replace(/~/g,'<br />');
	con = con.replace(/<<Click To Remove->/g,'<span class="padded grey italic">Click To Remove</span>');
	element.store('tip:text',con);
});
var tipz = new Tips(toTip,{
	className: 'tipz',
	fixed: false,
	onShow: function(el){
		el.fade(options['tipOpacity']);
		},
	onHide: function(el){
		el.fade('out');
		}	
});

/////////////////////////////////////////////////////imageTips/////////////////////////////////////////////////////	

var imgTips = $$('img.imgz');
imgTips.each(function(element,index) {
	var content = element.get('src').replace('uploads/', 'uploads/LARGE-');
	var nImg = new Element('img',{
						   'alt': 'Large Drawing',
						   'src': content
						   })
	element.store('tip:title', '');
	element.store('tip:text',nImg);
});
var imgTipz = new Tips(imgTips,{
	className: 'imgTipz',
	onShow: function(el){
		el.fade(options['tipOpacity']);
		},
	onHide: function(el){
		el.fade('out');
		}	
});

/////////////////////////////////////////////////////menu/////////////////////////////////////////////////////	

/*if($('trigger')){
var menu = $('hiddenMenu');
var height = menu.getHeight();
menu.setStyle('height', '0px');
menu.set('morph');
$('trigger').addEvents({
					   'mouseenter': function(){
						   menu.morph({
									  'height': height - 2,
									  'width': options['menuWidth'],
									  'opacity': 1
									  })
						   },
						 'mouseleave': function(){
							menu.morph({
									  'height': 0,
									  'width': 0,
									  'opacity': 0
									  })
						   }  
					   });
}*/

/////////////////////////////////////////////////////noStock/////////////////////////////////////////////////////	

var noStock = $$('div.noStock');
if(noStock.length > 0){
	noStock.each(function(el){
						  el.fade('hide');
						  el.getParent('form').addEvents({
													   'mouseenter':function(){
														   el.fade(0.8);
														   },
														'mouseleave': function(){
															el.fade('out'); 
														   },
														'click': function(){
															 Sexy.error('<h1>PS Glass Fittings</h1><br/><p>Were sorry but this product is currently out of stock. Please <a href="http://www.psglassfittings.com/contact" class="contact">Contact Us</a> for details on when we can expect this product back in stock</p>'); 
															} 
													   })
						  })
	
	}

/////////////////////////////////////////////////////checkout/////////////////////////////////////////////////////

if($('checkoutForm')){
$('updateCart').destroy();	
var checkForm = $('checkoutForm');
$$('#checkoutForm select', '#checkoutForm input.quantity').each(function(el){
				   el.addEvent('change',function(ev){
									 $each($$('select', 'input'),function(e) {
													e.disabled=1;						 
														})		 
									  checkForm.set('send',{
													onSuccess:function(){
														 $each($$('select', 'input'),function(e) {
														 e.disabled=0;						 
															})	
														}
													})
									  checkForm.send();
									  updateCart(el, options)
									   })
						   })
}

/////////////////////////////////////////////////////clear cart//////////////////////////////////////////

if($('clearCart')){
$('clearCart').addEvent('click', function(ev){
										  ev.stop();
										  var href = $('clearCart').get('href');
										  clearCart(href,options);
										  })
}

/////////////////////////////////////////////////////click To Cart//////////////////////////////////

$$('form.productsForm').each(function(form){
							if(form.getElement('input.hidePrice')){		  
							var price = form.getElement('input.hidePrice').value;
							form.addEvent('submit', function(ev){
													   ev.stop();
													   if(price.length > 0){		 
														 $('cart').set('tween',{
																			 onComplete: function(){
																				 $('cart').tween('background-color','#FFF');
																				 }
																			 })
														 $('cart').tween('background-color', options['background']);
														 var add = addToCart(form, options);
														 if(add != false){
														 tipz.attach(add);
														 }
														 form.send();
														 }
														  else{
															  Sexy.error('<h1>PS Glass Fittings</h1><br/><p>Were sorry but this product does not have a set price. Please <a href="http://www.psglassfittings.com/contact" class="contact">Contact Us</a> for prices</p>');
															  }
														 })
							}
							})

/////////////////////////////////////////////////////click To remove//////////////////////////////////////////

$$('a.removeCart').each(function(a){
								 a.addEvent('click', function(ev){
											  ev.stop();
											  removeCartItem(a, options);
											  })
								 });

/////////////////////////////////////////////////////drag to cart and popup////////////////////////////

$$('div.popUp').setStyle('opacity', options['popOpacity']);
$$('div.imageContainer').addEvents({
				  'mousedown':function(ev){
					  if(!this.getElement('div.noStock')){
					  var form = this.getParent('form.productsForm');
					  var price = form.getElement('input.hidePrice').value;
					  if(price.length > 0){
					  var clone = this.getElement('img.productImage').clone();
					  var origin = this.getPosition();
					  clone.setStyles({opacity:0.7,position:'absolute',left:origin.x,top:origin.y}).inject(document.body).makeDraggable({
					  preventDefault: true,
					  droppables:[$('cartContent')],
					  onEnter:function(){
					  $('cart').tween('background-color', options['background']);	
					  },
					  onLeave:function(){
					  $('cart').tween('background-color', '#FFF');	
					  },
					  onDrop:function(el,drop){
						  if(drop){
							  el.destroy();
							  $('cart').tween('background-color', '#FFF');
							  form.send();
							  var add = addToCart(form, options);
							  if(add != false){
								   tipz.attach(add);
								 }
						  }else{
							  el.get('morph').start({
								  opacity:0,
								  left:origin.x,
								  top:origin.y
							  }).chain(el.destroy.bind(el));
						  }
						  $('cartContent').removeEvents();
					  },
					  onCancel:function(el){
						  el.destroy();
						  }
				  }).start(ev);
				  }
				  else{
					  Sexy.error('<h1>PS Glass Fittings</h1><br/><p>Were sorry but this product does not have a set price. Please <a href="http://www.psglassfittings.com/contact" class="contact">Contact Us</a> for prices</p>');
					  }
					  }
		  },
		  'mouseenter': function(){
			  var popUp = this.getElement('div.popUp');
			  if(popUp){
			  popUp.set('tween',{
					   transition: options['popTransition'],
					   duration: options['duration']
					   })
			  popUp.tween('margin-bottom', '0');
			  }
			  },
		  'mouseleave': function(){
			  var popUp = this.getElement('div.popUp');
			  if(popUp){
			  popUp.tween('margin-bottom', '-'+options['popHeight']);
			  }
			  }
	  });

});

/////////////////////////////////////////////////////functions//////////////////////////////////////////
/////////////////////////////////////////////////////addSelect//////////////////////////////////////////

var addSelect = function(el){
	var num = 1;
	$$('input.browse').each(function(e){
									 var id = e.get('name').split('_');
									 if(id[1] && id[1] >= num){
										 num = parseInt(id[1]) + 1;
										 }
									 })
	var sel = el.getPrevious('input.browse').clone().set('name', 'draw_' + num);
	var img = new Element('img',{'class': 'info','src': 'images/delete.png', 'width': '20', 'height':'7','alt':'remove', 'style': 'margin-top:4px;'});
	var remove = new Element('a',{'class': 'info', 'href': 'javascript:void(0);'}).grab(img);
	remove.addEvent('click', function(){
									  removeSelect(this);
									  });
	var par = el.getParent('li');
	var li = new Element('li').adopt(sel, remove).inject(par, 'after');
	}

/////////////////////////////////////////////////////addSlideSelect//////////////////////////////////////////

var addSlideSelect = function(el){
	var num = 1;
	$$('input.browse').each(function(e){
									 var id = e.get('name').split('_');
									 if(id[1] && id[1] >= num){
										 num = parseInt(id[1]) + 1;
										 }
									 })
	var sel = el.getPrevious('input.browse').clone().set('name', 'slideImage_' + num);
	var caption = el.getParent('ul').getElement('input[name=slideCaption]').clone().set('name', 'slideCaption_' + num);
	var img = new Element('img',{'class': 'info','src': 'images/delete.png', 'width': '20', 'height':'7','alt':'remove', 'style': 'margin-top:4px;'});
	var remove = new Element('a',{'class': 'info', 'href': 'javascript:void(0);'}).grab(img);
	remove.addEvent('click', function(){
									  removeSlideSelect(this);
									  });
	var par = el.getParent('li').getNext('li');
	var label = new Element('label').set('text', 'Image:');
	var li = new Element('li').adopt(label, sel, remove).inject(par, 'after');
	var labelTwo = new Element('label').set('text', 'Image Caption');
	var liTwo = new Element('li').adopt(labelTwo, caption).inject(li, 'after');
	}

/////////////////////////////////////////////////////createModal///////////////////////////////////////	

var createModal = function(){
	var modalTable = new HtmlTable({});
	var scroller = new Element('div', {'id': 'loadScroll'});
	var loader = new Element('div', {'id': 'loadContainer'}).grab(scroller);
	var modalContent = new Element('div', {'id': 'modalContent'}).grab(loader);
	modalTable.push([{content: '&nbsp;',properties: {'class': 'topLeft'}},{content: '&nbsp;',properties: {'class': 'top'}},{content: '&nbsp;',properties: {'class': 'topRight'}}], {'class': 'modalRow'});
	modalTable.push([{content: '&nbsp;',properties: {'class': 'midLeft'}},{content: modalContent,properties: {'class': 'mid'}},{content: '&nbsp;',properties: {'class': 'midRight'}}], {'class': 'modalRow'});
	modalTable.push([{content: '&nbsp;',properties: {'class': 'bottomLeft'}},{content: '&nbsp;',properties: {'class': 'bottom'}},{content: '&nbsp;',properties: {'class': 'bottomRight'}}], {'class': 'modalRow'});
	var closeLink = new Element('div', {'id': 'mClose'});
	closeLink.addEvent('click',function(ev){
										if($('modal')){
										$('modal').fade('out').destroy();
										$('overlay').fade('out');
										}
										})
	var modalClose = new Element('div', {'id': 'modalClose'}).grab(closeLink);
	var mContainer = new Element('div',{'id': 'modalContainer'}).adopt(modalClose, modalTable);
	var modal = new Element('div',{
							'id': 'modal'
							}).grab(mContainer);
	modal.inject(document.body, 'bottom');
	modal.setStyles({'visibility': 'visible'});
	}

/////////////////////////////////////////////////////resizeModal///////////////////////////////////////

var resizeModal = function(trans, dur){
	 var size = window.getSize();
	 var scrolled = window.getScroll();
	 var over = window.getScrollSize();
	 $('overlay').setStyles({'height': over.y, 'width': over.x});
	 var nSize = $('modal').getSize();
	 var halfW = (nSize.x + 20) / 2;
	 var halfH = (nSize.y + 20) / 2;
	 var halfWinW = size.x / 2;
	 var halfWinH = size.y / 2;
	 var nLeft = Math.round(halfWinW - halfW);
	 var nTop = Math.round(halfWinH - halfH);
	 if(nTop < 10){
		 nTop = 10;
		 }
	 if(nLeft < 10){
		 nLeft = 10;
		 }	 
	 nTop = Math.round(nTop + scrolled.y);
	 $('modal').set('morph',{
			  transition: trans,
			  duration: dur
			  });
	 $('modal').morph({
					  'top': nTop,
					  'left': nLeft
					  });
	}

/////////////////////////////////////////////////////openModal///////////////////////////////////////	
	
var openModal = function(rel, href){
	if(!$('modal')){createModal();}
	var trans = 'back:out';
	var dur = 700;
	var formWidth = 500;
	var timer;
	window.addEvent('resize', function(){
	 if($('modal')){							   
	  $clear(timer);
	  timer = (function(){
		resizeModal(trans, dur);
	  }).delay(50);
	 }
	});
	var size = window.getSize();
	var scrolled = window.getScroll();
	var modal = $('modal');
	var content = $('modalContent');
	var mSize = modal.getSize();
	var cSize = content.getSize();
	var left = (size.x / 2);
	left = Math.round(left - (mSize.x /2));
	var top = Math.round(mSize.y + 100) * -1;
	var scroller = $('loadScroll');
	var splitted = rel.split('||');
	var subject = splitted[0];
	var file = splitted[1];
	if(modal){
	modal.setStyles({
					'top': top,
					'left': left,
					'visibility': 'visible',
					'opacity': 1
					});
	content.setStyles({
					  'height': cSize.y,
					  'width': cSize.x
					  })
	var top = (size.y / 2);
	top = Math.round(top - mSize.y / 2);
	top = Math.round(top + scrolled.y);
	if(top < 10){
		 top = 10;
		 }
	 if(left < 10){
		 left = 10;
		 }	
	modal.set('morph',{
			  transition: trans,
			  duration: dur,
			  onComplete: function(){
				   scroller.setStyle('left', '0');
				   scroller.set('tween',{
								 duration: 6000,
								 onStart: function(){
									 var request = new Request({
											url: href,
											link: 'chain',
											method: 'get',
											data: {
												'subject': subject,
												'file': file,
												'modal': '1'
											},
											onRequest: function() {
											},
											onSuccess: function(response) {
												 if($('modalContent')){
												 var newContent = new Element('div',{
																		'id': 'contentForm',	  
																		'html': response
																		});
												 newContent.fade('hide').inject($('modalContent'),'bottom');
												 var nSize = newContent.getSize();
												 var size = window.getSize();
												 var halfMW = (formWidth + 20) / 2;
												 var halfMH = (nSize.y + 20) / 2;
												 var halfWinW = size.x / 2;
												 var halfWinH = size.y / 2;
												 var scrolled = window.getScroll();
												 var nLeft = Math.round(halfWinW - halfMW);
												 var nTop = Math.round(halfWinH - halfMH);
												 nTop = Math.round(nTop + scrolled.y);
												 if(nTop < 10){
													 nTop = 10;
													 }
												 if(nLeft < 10){
													 nLeft = 10;
													 }	
												 if(modal){
												 modal.set('morph',{
														   transition: trans,
			 											   duration: dur,
														   onStart: function(){
															   if($('loadContainer')){
															   $('loadContainer').fade('out').nix(true);
															   }
															   },
														   onComplete: function(){
															   newContent.fade('in');
															   var myFormValidator = new Form.Validator($('modalForm'), {
																			  stopOnFailure: true,
																			  evaluateOnSubmit: true,
																			  evaluateFieldsOnBlur: false,
																			  evaluateFieldsOnChange: false,
																			  onElementFail: function(el){
																				  var bc  = el.getStyle('border-color');
																				  var c  = el.getStyle('color');
																				  el.flash('#F00',bc,5,'border-color',100);
																				  },
																			  onFormValidate: function(valid, el, ev){
																				  if(valid){
																					   ev.stop();
																					   $each($$('input[type=submit]'),function(el) {
																					   el.disabled = 1,
																					   el.setStyles({
																									   'border-color': '#999',
																									   'background': '#F4F4F4',
																									   'color': '#999',
																									   'cursor': 'text'
																									   })
																						  });
																					    $('modalForm').set('send',{
																						   onRequest: function(){
																							   var dotW = 230;
																							   var dotH = 75;
																							   var sending = new Element('div',{'id': 'dotter','styles':{'height': dotH, 'width': dotW, 'padding':'10px'}});
																							   sending.fade('hide').inject(content, 'bottom');
																							   var myDotter = new Dotter('dotter');
																							   var size = window.getSize();
																							   var scrolled = window.getScroll();
																							   var halfNW = (dotW + 20) / 2;
																							   var halfNH = (dotH + 20) / 2;
																							   var halfWinNW = size.x / 2;
																							   var halfWinNH = size.y / 2;
																							   var neLeft = Math.round(halfWinNW - halfNW);
																							   var neTop = Math.round(halfWinNH - halfNH);
																							   neTop = Math.round(neTop + scrolled.y);
																							    if(neTop < 10){
																									 neTop = 10;
																									 }
																								 if(neLeft < 10){
																									 neLeft = 10;
																									 }	
																							   modal.set('morph',{
																										 transition: trans,
																										 duration: dur,
																										 onStart: function(){
																											 $('contentForm').set('tween',{
																																  onComplete: function(){
																																	  $('contentForm').destroy();
																																	  $('dotter').fade('in');
																																	  myDotter.start();
																																	  }
																																  })
																											 $('contentForm').tween('opacity', 0);
																											 }
																											 });
																							   modal.morph({
																										   'left': neLeft,
																										   'top': neTop
																										   });
																							   content.set('morph',{
																										 duration: dur,
																										 transition: trans
																										 });
																							   content.morph({
																											 'height': dotH,
																											 'width': dotW
																											 });
																							   },
																						   onSuccess: function(){
																							   $('dotter').set('tween',{
																											   onComplete: function(){
																												   var sent = new Element('div',{'id': 'sent', 'text': 'Sent!'}).fade('hide').replaces($('dotter'));
																													   $('sent').set('tween',{
																																 onComplete: function(){
																																	 $('modal').set('tween',{
																																			  transition: 'back:in',
																																			  duration: dur,
																																			  onComplete: function(){
																																				  $('overlay').fade('out');
																																				  $('modal').nix(true);
																																				  }
																																			  });
																															   top = top * -1;
																															   $('modal').tween('top', top);
																																	 }.delay(2000)
																																 })
																														  $('sent').tween('opacity', 1);
																												   }.delay(800)
																												   });
																							  $('dotter').tween('opacity', 0);
																							   }.delay(3000)	 
																						   });
																		$('modalForm').send();
																					  }
																				  } 		  
																			  });
															   }
														   })
												 content.set('morph',{
															 transition: trans,
			 											   	 duration: dur
															 });
												 modal.morph({
															 'top': nTop,
															 'left': nLeft
															 });
												 
												 content.morph({
																	'height': nSize.y,
																	'width': formWidth
																	});
												 }
											}
												}
										}).send();
									 }.delay(3500)
								 });
					scroller.tween('left', '510px');
				  }
			  });
	modal.morph({
				'top': top
				});
	}
	}	
	
/////////////////////////////////////////////////////removeSelect///////////////////////////////////////

var removeSelect = function(el){
	el.getParent('li').destroy();
	}
	
/////////////////////////////////////////////////////removeSlideSelect///////////////////////////////////////

var removeSlideSelect = function(el){
	var par = el.getParent('li');
	par.getNext('li').destroy();
	par.destroy();
	}	
	
/////////////////////////////////////////////////////updateCart////////////////////////////

var updateCart = function(el,options){
	  /*var selected = el.getSelected();
	  selected = selected[0].value*/
	  var name = el.get('name').split('_');
	  var selected = el.get('value');
	  if(name[0] == 'qty'){
		  var price = $('itemPrice_'+name[1]).get('text');
		  price = parseFloat(price) * parseInt(selected);
		  $('itemTotal_'+name[1]).set('text',parseFloat(price).numberFormat(2, '.', ','));
		  var total = 0.00;
		  $$('span.itemTotal').each(function(el){
											 total += parseFloat(el.get('text').replace(',',''));
											 })
		  $('subTotal').set('text', parseFloat(total).numberFormat(2, '.', ','));
		  var delivery = options['delivery'];
		  if(total >= options['delVar']){
			  delivery = 0.00;
			  }
		  $('delivery').set('text', parseFloat(delivery).numberFormat(2, '.', ','));
		  var vat = (parseFloat(total) + parseFloat(delivery))*(options['vat']/100);
		  $('vat').set('text', parseFloat(vat).numberFormat(2, '.', ','));
		  var full = parseFloat(total)+parseFloat(delivery)+parseFloat(vat);
		  $('total').set('text', full.numberFormat(2, '.', ','));
		 }
	}

/////////////////////////////////////////////////////clearCart/////////////////////////////////////////////////////

var clearCart = function(href, options){
	var cart = $('cartContent');
	if(cart.getElements('a.removeCart').length > 0){
	Sexy.confirm('<h1>PS Glass Fittings</h1><br/><p>Are you sure you want to empty your cart?</p>', {
	  textBoxBtnOk: 'Yes',
	  textBoxBtnCancel: 'No',		 
	  onComplete:
		function(returnvalue) {
		  if (returnvalue) {
			var height = cart.getHeight();
			var req = new Request({url: href}).send();
			if(height > options['cartHeight']){
			cart.setStyle('height', height);
			cart.set('tween',{
					 onComplete: function(){
						 cart.setStyle('height', 'auto');
						 }
					 })
			cart.tween('height', options['cartHeight'])
			
			}
			$('cart').set('tween',{
						  onComplete: function(){
								$('cart').tween('background-color','#fff');
							}	  
						  })
			$('cart').tween('background-color', options['background']);
			cart.getElements('a.removeCart').each(function(el){
														 el.fade('out').destroy();
														 })
			var spacer = new Element('div',{
										'id': 'cartSpacer'
										}).inject(cart)
			$('items').set('text', '0');
			$('total').set('text', (0.00).numberFormat(2, '.', ','));
		  }
		}
	  });
	}
	else{
		Sexy.error('<h1>PS Glass Fittings</h1><br/><p>Your cart is already empty</p>');
		}
	
}	
	
/////////////////////////////////////////////////////removeCartItem/////////////////////////////////////////////////////

var removeCartItem = function(a, options){
	Sexy.confirm('<h1>PS Glass Fittings</h1><br/><p>Are you sure you want to remove this item?</p>', {
	  textBoxBtnOk: 'Yes',
	  textBoxBtnCancel: 'No',
	  onComplete:
		function(returnvalue) {
		  if (returnvalue) {
			var req = new Request({url: a.get('href')});
			req.send();
			var title = new Array();
			title[0] = a.retrieve('tip:title');
			title[1] = a.retrieve('tip:text');
			var v = itemDetails(a,title,options);
			var cartItems =  $('items').get('text');
			var total =  $('total').get('text').replace(',','');
			var items = $('cartContent').getElements('a.removeCart');
			a.removeEvents();
			if(items.length == 1){
				var spacer = new Element('div',{
										 'id': 'cartSpacer'
										 }).replaces(a);
				}
				else{
					a.destroy();
					}
			$$('div.tipz').fade('out');		
			var count = Math.round(parseInt(cartItems) - parseInt(v['qty']));
			if(count <= 0){
				count = 0;
				}
			var full = (parseFloat(total) - parseFloat(v['price'] * v['qty']));
			if(full <= 0.00){
				full = 0.00;
				}
			$('items').set('text', count);
			$('total').set('text', full.numberFormat(2, '.', ','));	
		  } else {
		  }
		}
	  });
		
	}

/////////////////////////////////////////////////////itemDetails/////////////////////////////////////////////////////

var itemDetails = function(el,t,options){
	 var title = t[1].split('<br />');
	 var quantity = title[0].split(' : ');
	 var quantity = quantity[1];
	 var variable = title[1].split(' : ');
	 var varName = variable[0];
	 variable = variable[1];
	 var price = title[2].split(' : '+options['currency']);
	 var price = price[1];
	 var tid = el.getElement('img').get('id').split('_');
	 id = tid[2];
	 var v = {
		 'name'		: 	t[0],
		 'qty'		: 	quantity,
		 'var'		: 	variable,
		 'price'	: 	price,
		 'id'		: 	id,
		 'sess'		:	tid[1],
		 'varName'	: 	varName
		 }
	return v;	 
	}

/////////////////////////////////////////////////////createTitle/////////////////////////////////////////////////////

var createTitle = function(v, i, options){
	var title = i['name']+'::';
	if(v != false){
	var qty = Math.round(parseInt(v['qty'])+parseInt(i['qty']));
	var total = (parseFloat(v['price'])*(parseInt(v['qty'])+parseInt(i['qty']))).numberFormat(2, '.', ',');
	}
	else{
		var qty = Math.round(parseInt(i['qty']));
	 	var total = (parseFloat(i['price'] * i['qty'])).numberFormat(2, '.', ',');
		}
	title += 'Quantity : '+qty+'<br />';
	title += i['varName']+' : '+i['var']+'<br />';
	var price = parseFloat(i['price']).numberFormat(2, '.', ',');
	title += 'Price : '+options['currency']+price+'<br />';
	title += 'TOTAL : '+options['currency']+total+'<br />';
	title += '<span class="padded grey italic">Click To Remove</span>';
	return title;
	}

/////////////////////////////////////////////////////addToCart/////////////////////////////////////////////////////

var addToCart = function(form, options){
	var cart = $('cartContent');
	var i = {
		'name'		:	form.getElement('input.hideName').value,
		'var' 		:  	form.getElement('select.variable').value,
		'qty' 		: 	form.getElement('input.quantity').value,
		'price' 	: 	form.getElement('input.hidePrice').value,
		'id'		:	form.getElement('input.hideId').value,
		'varName'	:	form.getElement('input.hideVar').value
		};
	var href = form.get('action');
	var image = form.getElement('img.productImage').clone();
	var cartItems =  $('items').get('text');
	var total =  $('total').get('text').replace(',','');
	var inCart = cart.getElements('img.cartImage').getParent('a');
	var sess = 0;
	if(inCart.length > 0){
		var sess = inCart.length;
		var check = inCart.some(function(el){
										 var title = new Array();
										 title[0] = el.retrieve('tip:title');
										 title[1] = el.retrieve('tip:text');
										 var v = itemDetails(el,title,options);
										 if(v['var'] == i['var'] && v['id'] == i['id']){
											 var nt = createTitle(v,i,options).split('::');
											 el.store('tip:title', nt[0]);
											 el.store('tip:text', nt[1]);
											 return true;
											 }
										 })
		}	
	if(inCart.length == 0 || !check){
			var clone = image.removeProperty('class');
			clone.addClass('cartImage').setProperties({'id': 'img_'+sess+'_'+i['id'], 'width': options['imgW'], 'height': options['imgH'], 'alt': options['alt']});
			var a = new Element('a', {
								'href': href+'/remove/'+i['var']+'~'+i['id'],
								'class': 'removeCart'
								});
			var nt = createTitle(false,i,options).split('::');
			a.store('tip:title', nt[0]);
			a.store('tip:text', nt[1]);
			a.addEvent('click', function(ev){
										 ev.stop();
										 removeCartItem(a, options);
										 })
			if($('cartSpacer')){
				a.grab(clone).replaces($('cartSpacer'));
			}
			else{		
				a.grab(clone).inject(cart, 'top');
				}
				var tip = true;
			}
		$('items').set('text', Math.round(parseInt(cartItems) + parseInt(i['qty'])));
		$('total').set('text', (parseFloat(total) + parseFloat(i['price'] * i['qty'])).numberFormat(2, '.', ','));
		cartOpacity();
		if(tip){
			return a;
		}
		else{
			return false;
			}
	}

/////////////////////////////////////////checkafter////////////////////////////////////////
var checkAfter = function(){
	var leng = $('afterPrice').value;
	if(leng.length > 6){
		Sexy.alert('<h1>PS Glass Fittings</h1><br/><p>The after price is too long please try to keep it under 6 characters</p>');
		}
	}
	
/////////////////////////////////////////cartMessages////////////////////////////////////////	
var cartMessages = function(fxmq, options){
	fxmq.announce({
		message: options['cartMessages'][0],
		delay: 3000, revert: false
}).chain(function(){
	fxmq.announce({
		message: options['cartMessages'][1],
		delay: 3000, revert: false
	});
}).chain(function(){
	fxmq.announce({
		message: options['cartMessages'][2],
		delay: 3000, revert: false
	});
}).chain(function(){
	fxmq.announce({
		message: options['cartMessages'][3],
		delay: 3000, revert: true,
		showEffect: {
			top: [0,0],
			left: [500, 0],
			opacity: [0,1]
		},
		hideEffect: {
			top: [0,0],
			left: [0, 500]
		}
	}).chain(function(){
		cartMessages(fxmq,options);
		});
});
	}	

/////////////////////////////////////////cartOpacity////////////////////////////////////////	

var cartOpacity = function(){
var cart = $('cartContent');
cart.getElements('img').each(function(el){
				 var imgs = el.getParent('div').getElements('img').erase(el);
				 el.addEvents({
							  'mouseenter':function(){
								  imgs.tween('opacity', 0.5);
								  },
							   'mouseleave': function(){
								  imgs.tween('opacity', 1);
									}  
							  })
				 })
}

/////////////////////////////////////////open and close panel////////////////////////////////////////	
var openPanel = function(){
	var panel = $('panel');
	var toggle = $('loginToggle');
	panel.set('morph',{
			  onComplete: function(){
				  toggle.removeEvents();
				  toggle.addEvent('click',function(ev){
												   ev.stop()
												   closePanel();
												   })
				  }
			  });
	panel.morph({
				'margin-top': '0px'
				})
	}

var closePanel = function(){
	var panel = $('panel');
	var toggle = $('loginToggle');
	panel.set('morph',{
			  onComplete: function(){
				  toggle.removeEvents();
				  toggle.addEvent('click',function(ev){
												   ev.stop()
												   openPanel();
												   })
				  }
			  });
	panel.morph({
				'margin-top': '-100px'
				})
	}

var moreClick = function(){
	var more = $('more');
	var par = more.getParent('ul');
	more.addEvent('click', function(ev){
		ev.stop();
		var request = new Request({
				url:more.get('href'),
				method:'get',
				onRequest: function() {
				var loader = new Element('img', {'src': 'images/ajax.gif', 'width': '24', 'height': '24', 'alt': 'Loading Comments...', 'class': 'loader'});
				loader.replaces(more);	
				},
				onSuccess: function(response){
				$('more-comments').destroy();	
				par.set('html', par.get('html') + response);
				if($('more'))moreClick();
				}
			}).send();
		});
	}	
/////////////////////////////////////////////////////classes/////////////////////////////////////////////////////
/////////////////////////////////////////////////////viewer/////////////////////////////////////////////////////
/*
Author:
	luistar15, <leo020588 [at] gmail.com>
License:
	MIT License

Class
	viewer v0.9 (rev.08-12-08)

Arguments:
	items: dom collection | required
	parameters - see Parameters below

Parameters:
	sizes: obj | item sizes (px) | default: {w:480,h:240}
	mode: string OR array | 'rand','top','right','bottom','left','alpha' | default: 'rand'
	modes: array | default: ['top','right','bottom','left','alpha']
	fxOptions: object | Fx.Tween options | default: {duration:500}
	interval: int | for periodical | default: 5000

Methods:
	previous(manual): walk to previous item
		manual: bolean | default:false
	next(manual): walk to next item
		manual: bolean | default:false
	play(wait): auto walk items
		wait: boolean | required
	stop(): stop auto walk
	walk(item,manual): walk to item
		item: int | required
		manual: bolean | default:false

Requires:
	mootools 1.2 core
*/

var viewer = new Class({

	mode: 'rand',
	modes: ['top','right','bottom','left','alpha'],
	sizes: {w:480,h:240},
	fxOptions: {duration:500},
	interval: 5000,

	initialize: function(items,options){
		if(options) for(var o in options) this[o]=options[o];
		//
		if(this.buttons){
			this.buttons.previous.addEvent('click',this.previous.bind(this,[true]));
			this.buttons.next.addEvent('click',this.next.bind(this,[true]));
		}
		this.__current = 0;
		this.__previous = null;
		this.items = items.setStyle('display','none');
		this.items[this.__current].setStyle('display','block');
		this.disabled = false;
		this.attrs = {
			left: ['left',-this.sizes.w,0,'px'],
			top: ['top',-this.sizes.h,0,'px'],
			right: ['left',this.sizes.w,0,'px'],
			bottom: ['top',this.sizes.h,0,'px'],
			alpha: ['opacity',0,1,'']
		};
		this.rand = this.mode=='rand';
		this.sequence = typeof(this.mode)=='object' ? this.mode : false;
		this.curseq = 0;
		this.timer = null;
	},

	walk: function(n,manual){
		if(this.__current!==n && !this.disabled){
			this.disabled = true;
			if(manual){
				this.stop();
			}
			if(this.rand){
				this.mode = this.modes.getRandom();
			}else if(this.sequence){
				this.mode = this.sequence[this.curseq];
				this.curseq += this.curseq+1<this.sequence.length ? 1 : -this.curseq;
			}
			this.__previous = this.__current;
			this.__current = n;
			var a = this.attrs[this.mode].associate(['p','f','t','u']);
			for(var i=0;i<this.items.length;i++){
				if(this.__current===i){
					this.items[i].setStyles($extend({'display':'block','z-index':'2'},JSON.decode('{"'+a.p+'":"'+a.f+a.u+'"}')));
				}else if(this.__previous===i){
					this.items[i].setStyles({'z-index':'1'});
				}else{
					this.items[i].setStyles({'display':'none','z-index':'0'});
				}
			}
			this.items[n].set('tween',$merge(this.fxOptions,{onComplete:this.onComplete.bind(this)})).tween(a.p,a.f,a.t);
		}
	},

	play: function(wait){
		this.stop();
		if(!wait){
			this.next();
		}
		this.timer = this.next.periodical(this.interval,this,[false]);
	},

	stop: function(){
		$clear(this.timer);
	},

	next: function(manual){
		this.walk(this.__current+1<this.items.length ? this.__current+1 : 0,manual);
	},

	previous: function(manual){
		this.walk(this.__current>0 ? this.__current-1 : this.items.length-1,manual);
	},

	onComplete: function(){
		this.disabled = false;
		this.items[this.__previous].setStyle('display','none');
		if(this.onWalk) this.onWalk(this.__current);
	}
});

/**
 * Observer - Observe formelements for changes
 *
 * - Additional code from clientside.cnet.com
 *
 * @version		1.1
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */
var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.element = $(el) || $$(el);
		this.addEvent('onFired', onFired);
		this.setOptions(options);
		this.bound = this.changed.bind(this);
		this.resume();
	},

	changed: function() {
		var value = this.element.get('value');
		if ($equals(this.value, value)) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	},

	pause: function(){
		if (this.timer) $clear(this.timer);
		else this.element.removeEvent('keyup', this.bound);
		return this.clear();
	},

	resume: function(){
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.bound);
		return this;
	}

});

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
};

/**
 * Autocompleter
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

var Autocompleter = new Class({

	Implements: [Options, Events],

	options: {/*
		onOver: $empty,
		onSelect: $empty,
		onSelection: $empty,
		onShow: $empty,
		onHide: $empty,
		onBlur: $empty,
		onFocus: $empty,*/
		minLength: 1,
		markQuery: true,
		width: 'inherit',
		maxChoices: 10,
		injectChoice: null,
		customChoices: null,
		emptyChoices: null,
		visibleChoices: true,
		className: 'autocompleter-choices',
		zIndex: 42,
		delay: 400,
		observerOptions: {},
		fxOptions: {},

		autoSubmit: false,
		overflow: false,
		overflowMargin: 25,
		selectFirst: false,
		filter: null,
		filterCase: false,
		filterSubset: false,
		forceSelect: false,
		selectMode: true,
		choicesMatch: null,

		multiple: false,
		separator: ', ',
		separatorSplit: /\s*[,;]\s*/,
		autoTrim: false,
		allowDupes: false,

		cache: true,
		relative: false
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		var mode = this.options.selectMode;
		this.typeAhead = (mode == 'type-ahead');
		this.selectMode = (mode === true) ? 'selection' : mode;
		this.cached = [];
	},

	/**
	 * build - Initialize DOM
	 *
	 * Builds the html structure for choices and appends the events to the element.
	 * Override this function to modify the html generation.
	 */
	build: function() {
		if ($(this.options.customChoices)) {
			this.choices = this.options.customChoices;
		} else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				'styles': {
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);
			this.relative = false;
			if (this.options.relative) {
				this.choices.inject(this.element, 'after');
				this.relative = this.element.getOffsetParent();
			}
			this.fix = new OverlayFix(this.choices);
		}
		if (!this.options.separator.test(this.options.separatorSplit)) {
			this.options.separatorSplit = this.options.separator;
		}
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'property': 'opacity',
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);
		this.element.setProperty('autocomplete', 'off')
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
			.addEvent('click', this.onCommand.bind(this, [false]))
			.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
			.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100}));
	},

	destroy: function() {
		if (this.fix) this.fix.destroy();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(state) {
		this.focussed = state;
		if (!state) this.hideChoices(true);
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (!e && this.focussed) return this.prefetch();
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					if (this.element.value != this.opted) return true;
					if (this.selected && this.visible) {
						this.choiceSelect(this.selected);
						return !!(this.options.autoSubmit);
					}
					break;
				case 'up': case 'down':
					if (!this.prefetch() && this.queryValue !== null) {
						var up = (e.key == 'up');
						this.choiceOver((this.selected || this.choices)[
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						](this.options.choicesMatch), true);
					}
					return false;
				case 'esc': case 'tab':
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	setSelection: function(finish) {
		var input = this.selected.inputValue, value = input;
		var start = this.queryValue.length, end = input.length;
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var tokens = value.split(this.options.separatorSplit).filter(function(entry) {
					return this.test(entry);
				}, /[^\s,]+/);
				if (!this.options.allowDupes) tokens = [].combine(tokens);
				var sep = this.options.separator;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}
		this.observer.setValue(value);
		this.opted = value;
		if (finish || this.selectMode == 'pick') start = end;
		this.element.selectRange(start, end);
		this.fireEvent('onSelection', [this.element, this.selected, value, input]);
	},

	showChoices: function() {
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
		this.selected = this.selectedValue = null;
		if (this.fix) {
			var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto';
			this.choices.setStyles({
				'left': pos.left,
				'top': pos.bottom,
				'width': (width === true || width == 'inherit') ? pos.width : width
			});
		}
		if (!first) return;
		if (!this.visible) {
			this.visible = true;
			this.choices.setStyle('display', '');
			if (this.fx) this.fx.start(1);
			this.fireEvent('onShow', [this.element, this.choices]);
		}
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
		var styles = {'overflowY': 'hidden', 'height': ''};
		this.overflown = false;
		if (items.length > max) {
			var item = items[max - 1];
			styles.overflowY = 'scroll';
			styles.height = item.getCoordinates(this.choices).bottom;
			this.overflown = true;
		};
		this.choices.setStyles(styles);
		this.fix.show();
		if (this.options.visibleChoices) {
			var scroll = document.getScroll(),
			size = document.getSize(),
			coords = this.choices.getCoordinates();
			if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x;
			if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y;
			window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top));
		}
	},

	hideChoices: function(clear) {
		if (clear) {
			var value = this.element.value;
			if (this.options.forceSelect) value = this.opted;
			if (this.options.autoTrim) {
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
			}
			this.observer.setValue(value);
		}
		if (!this.visible) return;
		this.visible = false;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.observer.clear();
		var hide = function(){
			this.choices.setStyle('display', 'none');
			this.fix.hide();
		}.bind(this);
		if (this.fx) this.fx.start(0).chain(hide);
		else hide();
		this.fireEvent('onHide', [this.element, this.choices]);
	},

	prefetch: function() {
		var value = this.element.value, query = value;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			var index = this.element.getSelectedRange().start;
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}
		if (query.length < this.options.minLength) {
			this.hideChoices();
		} else {
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryValue = query;
				this.queryIndex = index;
				if (!this.fetchCached()) this.query();
			}
		}
		return true;
	},

	fetchCached: function() {
		return false;
		if (!this.options.cache
			|| !this.cached
			|| !this.cached.length
			|| this.cached.length >= this.options.maxChoices
			|| this.queryValue) return false;
		this.update(this.filter(this.cached));
		return true;
	},

	update: function(tokens) {
		this.choices.empty();
		this.cached = tokens;
		var type = tokens && $type(tokens);
		if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) {
			(this.options.emptyChoices || this.hideChoices).call(this);
		} else {
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
			tokens.each(this.options.injectChoice || function(token){
				var choice = new Element('li', {'html': this.markQueryValue(token)});
				choice.inputValue = token;
				this.addChoiceEvents(choice).inject(this.choices);
			}, this);
			this.showChoices();
		}
	},

	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = choice.addClass('autocompleter-selected');
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!this.selectMode) this.opted = this.element.value;
		if (!selection) return;
		this.selectedValue = this.selected.inputValue;
		if (this.overflown) {
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
		}
		if (this.selectMode) this.setSelection();
	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.setSelection(true);
		this.queryValue = false;
		this.hideChoices();
	},

	filter: function(tokens) {
		return (tokens || this.tokens).filter(function(token) {
			return this.test(token);
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
	},

	/**
	 * markQueryValue
	 *
	 * Marks the queried word in the given string with <span class="autocompleter-queried">*</span>
	 * Call this i.e. from your custom parseChoices, same for addChoiceEvents
	 *
	 * @param		{String} Text
	 * @return		{String} Text
	 */
	markQueryValue: function(str) {
		return (!this.options.markQuery || !this.queryValue) ? str
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
	},

	/**
	 * addChoiceEvents
	 *
	 * Appends the needed event handlers for a choice-entry to the given element.
	 *
	 * @param		{Element} Choice entry
	 * @return		{Element} Choice entry
	 */
	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	}
});

var OverlayFix = new Class({

	initialize: function(el) {
		if (Browser.Engine.trident) {
			this.element = $(el);
			this.relative = this.element.getOffsetParent();
			this.fix = new Element('iframe', {
				'frameborder': '0',
				'scrolling': 'no',
				'src': 'javascript:false;',
				'styles': {
					'position': 'absolute',
					'border': 'none',
					'display': 'none',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).inject(this.element, 'after');
		}
	},

	show: function() {
		if (this.fix) {
			var coords = this.element.getCoordinates(this.relative);
			delete coords.right;
			delete coords.bottom;
			this.fix.setStyles($extend(coords, {
				'display': '',
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
			}));
		}
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		if (this.fix) this.fix = this.fix.destroy();
	}

});

Element.implement({

	getSelectedRange: function() {
		if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd};
		var pos = {start: 0, end: 0};
		var range = this.getDocument().selection.createRange();
		if (!range || range.parentElement() != this) return pos;
		var dup = range.duplicate();
		if (this.type == 'text') {
			pos.start = 0 - dup.moveStart('character', -100000);
			pos.end = pos.start + range.text.length;
		} else {
			var value = this.value;
			var offset = value.length - value.match(/[\n\r]*$/)[0].length;
			dup.moveToElementText(this);
			dup.setEndPoint('StartToEnd', range);
			pos.end = offset - dup.text.length;
			dup.setEndPoint('StartToStart', range);
			pos.start = offset - dup.text.length;
		}
		return pos;
	},

	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var diff = this.value.substr(start, end - start).replace(/\r/g, '').length;
			start = this.value.substr(0, start).replace(/\r/g, '').length;
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', start + diff);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});

/* compatibility */

Autocompleter.Base = Autocompleter;

/**
 * Autocompleter.Local
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

Autocompleter.Local = new Class({

	Extends: Autocompleter,

	options: {
		minLength: 0,
		delay: 200
	},

	initialize: function(element, tokens, options) {
		this.parent(element, options);
		this.tokens = tokens;
	},

	query: function() {
		this.update(this.filter());
	}

});


/* Clientcide Copyright (c) 2006-2009, http://www.clientcide.com/wiki/cnet-libraries#license*/

//Contents: Fx.Marquee

//This lib: http://www.clientcide.com/js/build.php?excludeLibs[]=mootools-core&excludeLibs[]=mootools-more&require[]=Fx.Marquee&compression=none

/*
Script: Fx.Marquee.js
	Defines Fx.Marquee, a marquee class for animated notifications.

License:
	http://www.clientcide.com/wiki/cnet-libraries#license
*/

Fx.Marquee = new Class({
	Extends: Fx.Morph,
	options: {
		mode: 'horizontal', //or vertical
		message: '', //the message to display
		revert: true, //revert back to the previous message after a specified time
		delay: 5000, //how long to wait before reverting
		cssClass: 'msg', //the css class to apply to that message
		showEffect: { opacity: 1 },
		hideEffect: {opacity: 0},
		revertEffect: { opacity: [0,1] },
		currentMessage: null
/*	onRevert: $empty,
		onMessage: $empty */
	},
	initialize: function(container, options){
		container = document.id(container); 
		var msg = this.options.currentMessage || (container.getChildren().length == 1)?container.getFirst():''; 
		var wrapper = new Element('div', {	
				styles: { position: 'relative' },
				'class':'fxMarqueeWrapper'
			}).inject(container); 
		this.parent(wrapper, options);
		this.current = this.wrapMessage(msg);
	},
	wrapMessage: function(msg){
		if (document.id(msg) && document.id(msg).hasClass('fxMarquee')) { //already set up
			var wrapper = document.id(msg);
		} else {
			//create the wrapper
			var wrapper = new Element('span', {
				'class':'fxMarquee',
				styles: {
					position: 'relative'
				}
			});
			if (document.id(msg)) wrapper.grab(document.id(msg)); //if the message is a dom element, inject it inside the wrapper
			else if ($type(msg) == "string") wrapper.set('html', msg); //else set it's value as the inner html
		}
		return wrapper.inject(this.element); //insert it into the container
	},
	announce: function(options) {
		this.setOptions(options).showMessage();
		return this;
	},
	showMessage: function(reverting){
		//delay the fuction if we're reverting
		(function(){
			//store a copy of the current chained functions
			var chain = this.$chain?$A(this.$chain):[];
			//clear teh chain
			this.clearChain();
			this.element = document.id(this.element);
			this.current = document.id(this.current);
			this.message = document.id(this.message);
			//execute the hide effect
			this.start(this.options.hideEffect).chain(function(){
				//if we're reverting, hide the message and show the original
				if (reverting) {
					this.message.hide();
					if (this.current) this.current.show();
				} else {
					//else we're showing; remove the current message
					if (this.message) this.message.dispose();
					//create a new one with the message supplied
					this.message = this.wrapMessage(this.options.message);
					//hide the current message
					if (this.current) this.current.hide();
				}
				//if we're reverting, execute the revert effect, else the show effect
				this.start((reverting)?this.options.revertEffect:this.options.showEffect).chain(function(){
					//merge the chains we set aside back into this.$chain
					if (this.$chain) this.$chain.combine(chain);
					else this.$chain = chain;
					this.fireEvent((reverting)?'onRevert':'onMessage');
					//then, if we're reverting, show the original message
					if (!reverting && this.options.revert) this.showMessage(true);
					//if we're done, call the chain stack
					else this.callChain.delay(this.options.delay, this);
				}.bind(this));
			}.bind(this));
		}).delay((reverting)?this.options.delay:10, this);
		return this;
	}
});



/**
 * Sexy Alert Box - for mootools 1.2 - jQUery 1.3
 * @name sexyalertbox.v1.2.js
 * @author Eduardo D. Sada - http://www.coders.me/web-js-html/javascript/sexy-alert-box
 * @version 1.2.2
 * @date 25-May-2009
 * @copyright (c) 2009 Eduardo D. Sada (www.coders.me)
 * @license MIT - http://es.wikipedia.org/wiki/Licencia_MIT
 * @example http://www.coders.me/ejemplos/sexy-alert-box/
 * @based in <PBBAcpBox> (Pokemon_JOJO, <http://www.mibhouse.org/pokemon_jojo>)
 * @thanks to Pokemon_JOJO!
 * @features:
 * * Chain Implemented (Cola de mensajes)
 * * More styles (info, error, alert, prompt, confirm)
 * * ESC would close the window
 * * Focus on a default button
*/

/*
Class: SexyAlertBox
	Clone class of original javascript function : 'alert', 'confirm' and 'prompt'

Arguments:
	options - see Options below

Options:
	name - name of the box for use different style
	zIndex - integer, zindex of the box
	onReturn - return value when box is closed. defaults to false
	onReturnFunction - a function to fire when return box value
	BoxStyles - stylesheets of the box
	OverlayStyles - stylesheets of overlay
	showDuration - duration of the box transition when showing (defaults to 200 ms)
	showEffect - transitions, to be used when showing
	closeDuration - Duration of the box transition when closing (defaults to 100 ms)
	closeEffect - transitions, to be used when closing
	onShowStart - a function to fire when box start to showing
	onCloseStart - a function to fire when box start to closing
	onShowComplete - a function to fire when box done showing
	onCloseComplete - a function to fire when box done closing
*/

var SexyAlertBox = new Class({
  Implements: [Options, Chain],
	getOptions: function() {
		return {
			name            : 'SexyAlertBox',
			zIndex          : 65555,
			onReturn        : false,
			onReturnFunction: $empty,
			BoxStyles       : { 'width': 500 },
			OverlayStyles   : { 'background-color': '#000', 'opacity': 0.7 },
			showDuration    : 200,
			showEffect      : Fx.Transitions.linear,
      closeDuration   : 100,
			closeEffect     : Fx.Transitions.linear,
			moveDuration    : 500,
			moveEffect      : Fx.Transitions.Back.easeOut,
			onShowStart     : $empty,
			onShowComplete  : $empty,
			onCloseStart    : $empty,
			onCloseComplete : function(properties) {
				this.options.onReturnFunction(this.options.onReturn);
			}.bind(this)
		};
	},

	initialize: function(options) {
    this.i=0;
    
		this.setOptions(this.getOptions(), options);

		this.Overlay = new Element('div', {
			'id'    : 'BoxOverlay',
			'styles': {
          'display'           : 'none',
          'position'          : 'absolute',
          'top'               : '0',
          'left'              : '0',
          'opacity'           : 0,
          'z-index'           : this.options.zIndex,
          'background-color'  : this.options.OverlayStyles['background-color'],
          'height'            : window.getScrollHeight() + 'px',
          'width'             : window.getScrollWidth() + 'px'
			}
		});

		this.Content = new Element('div', {
			'id': this.options.name + '-BoxContenedor'
		});

    this.Contenedor = new Element('div', {
      'id': this.options.name + '-BoxContent'
    }).adopt(this.Content);

		this.InBox = new Element('div', {
			'id': this.options.name + '-InBox'
		}).adopt(this.Contenedor);
		
		this.Box = new Element('div', {
			'id': this.options.name + '-Box',
			'styles': {
				'display': 'none',
				'z-index': this.options.zIndex + 2,
				'position': 'absolute',
				'top': '0',
				'left': '0',
				'width': this.options.BoxStyles['width'] + 'px'
			}
		}).adopt(this.InBox);

    this.Overlay.injectInside(document.body);
    this.Box.injectInside(document.body);

    this.preloadImages();
    
		window.addEvent('resize', function() {
			if(this.options.display == 1) {
				this.Overlay.setStyles({
					'height': window.getScrollHeight() + 'px',
					'width': window.getScrollWidth() + 'px'
				});
				this.replaceBox();
			}
		}.bind(this));
		
		this.Box.addEvent('keydown', function(event) {
        if (event.key == 'esc'){
          this.options.onReturn = false;
          this.display(0);
        }
    }.bind(this));
		
		window.addEvent('scroll', this.replaceBox.bind(this));
	},

  preloadImages: function() {
    var img = new Array(2);
    img[0] = new Image();img[1] = new Image();img[2] = new Image();
    img[0].src = this.Box.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
    img[1].src = this.InBox.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
    img[2].src = this.Contenedor.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
  },


  togFlashObjects: function(state) {
    var hideobj=new Array("embed", "iframe", "object");
    for (y = 0; y < hideobj.length; y++) {
     var objs = document.getElementsByTagName(hideobj[y]);
     for(i = 0; i < objs.length; i++) {
      objs[i].style.visibility = state;
     }
    }
  },


	/*
	Property: display
		Show or close box
		
	Argument:
		option - integer, 1 to Show box and 0 to close box (with a transition).
	*/	
	display: function(option){
		if(this.Transition)
			this.Transition.cancel();				

		// Show Box	
		if(this.options.display == 0 && option != 0 || option == 1) {

      if(Browser.Engine.trident4)
        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });
        
      this.togFlashObjects('hidden');

			this.Overlay.setStyle('display', 'block');
			this.options.display = 1;
			this.fireEvent('onShowStart', [this.Overlay]);

			this.Transition = new Fx.Tween(this.Overlay,
				{
          property: 'opacity',
					duration: this.options.showDuration,
					transition: this.options.showEffect,
					onComplete: function() {

						sizes = window.getSize();
						scrollito = window.getScroll();

						this.Box.setStyles({
							'display': 'block',
							'left': (scrollito.x + (sizes.x - this.options.BoxStyles['width']) / 2).toInt()
						});

						this.replaceBox();
						this.fireEvent('onShowComplete', [this.Overlay]);
					}.bind(this)
				}
			).start(this.options.OverlayStyles['opacity']);

		}
		// Close Box
		else {

      if(Browser.Engine.trident4)
        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });

      this.togFlashObjects('visible');

      this.queue.delay(500,this);

			this.Box.setStyles({
				'display': 'none',
				'top': 0
			});
			this.Content.empty();
			this.options.display = 0;

			this.fireEvent('onCloseStart', [this.Overlay]);

      if(this.i==1) {
        this.Transition = new Fx.Tween(this.Overlay,
          {
            property: 'opacity',
            duration: this.options.closeDuration,
            transition: this.options.closeEffect,
            onComplete: function() {
                this.fireEvent('onCloseComplete', [this.Overlay]);
            }.bind(this)
          }
        ).start(0);
      }

		}
	},

	/*
	Property: replaceBox
		Move Box in screen center when brower is resize or scroll
	*/
	replaceBox: function() {
		if(this.options.display == 1) {
			sizes = window.getSize();
      scrollito = window.getScroll();

			if(this.MoveBox)
				this.MoveBox.cancel();
			
			this.MoveBox = new Fx.Morph(this.Box, {
				duration: this.options.moveDuration,
				transition: this.options.moveEffect
			}).start({

				'left': (scrollito.x + (sizes.x - this.options.BoxStyles['width']) / 2).toInt(),
				'top': (scrollito.y + (sizes.y - this.Box.offsetHeight) / 2).toInt()

			});
			
      this.focusin.delay(this.options.moveDuration,this);
			
		}
	},

  focusin: function() {
    if ($chk($('BoxAlertBtnOk'))) {
      $('BoxAlertBtnOk').focus();
    } else if ($chk($('BoxPromptInput'))) {
        $('BoxPromptInput').focus();
    } else if ($chk($('BoxConfirmBtnOk'))) {
      $('BoxConfirmBtnOk').focus();
    }
  },

	queue: function() {
		this.i--;
		this.callChain();
	},


	/*
	Property: messageBox
		Core system for show all type of box
		
	Argument:
		type - string, 'alert' or 'confirm' or 'prompt'
		message - text to show in the box
		properties - see Options below
		input - text value of default 'input' when prompt
		
	Options:
		textBoxBtnOk - text value of 'Ok' button
		textBoxBtnCancel - text value of 'Cancel' button
		onComplete - a function to fire when return box value
	*/	
	messageBox: function(type, message, properties, input) {

		this.chain(function () {

      properties = $extend({
        'textBoxBtnOk': 'OK',
        'textBoxBtnCancel': 'Cancelar',
        'textBoxInputPrompt': null,
        'password': false,
        'onComplete': $empty
      }, properties || {});


      this.options.onReturnFunction = properties.onComplete;

      this.ContenedorBotones = new Element('div', {
        'id': this.options.name + '-Buttons'
      });
      

      if(type == 'alert' || type == 'info' || type == 'error')
      {
          this.AlertBtnOk = new Element('input', {
            'id': 'BoxAlertBtnOk',
            'type': 'submit',
            'value': properties.textBoxBtnOk,
            'styles': {
              'width': '70px'
            }
          });
          
          this.AlertBtnOk.addEvent('click', function() {
            this.options.onReturn = true;
            this.display(0);
          }.bind(this));
        
          if(type == 'alert')
            this.clase = 'BoxAlert';
          else if(type == 'error')
            this.clase = 'BoxError';
          else if(type == 'info')
            this.clase = 'BoxInfo';
        
          this.Content.setProperty('class',this.clase).set('html',message);

          this.AlertBtnOk.injectInside(this.ContenedorBotones);
          
          this.ContenedorBotones.injectInside(this.Content);
          this.display(1);
      }
      else if(type == 'confirm')
      {
          this.ConfirmBtnOk = new Element('input', {
            'id': 'BoxConfirmBtnOk',
            'type': 'submit',
            'value': properties.textBoxBtnOk,
            'styles': {
              'width': '70px'
            }
          });

          this.ConfirmBtnCancel = new Element('input', {
            'id': 'BoxConfirmBtnCancel',
            'type': 'submit',
            'value': properties.textBoxBtnCancel,
            'styles': {
              'width': '70px'
            }
          });

          this.ConfirmBtnOk.addEvent('click', function() {
            this.options.onReturn = true;
            this.display(0);
          }.bind(this));

          this.ConfirmBtnCancel.addEvent('click', function() {
            this.options.onReturn = false;
            this.display(0);
          }.bind(this));

          this.Content.setProperty('class','BoxConfirm').set('html',message);

          this.ConfirmBtnOk.injectInside(this.ContenedorBotones);
          this.ConfirmBtnCancel.injectInside(this.ContenedorBotones);
          
          this.ContenedorBotones.injectInside(this.Content);
          this.display(1);
      }
      else if(type == 'prompt')
      {
          this.PromptBtnOk = new Element('input', {
            'id': 'BoxPromptBtnOk',
            'type': 'submit',
            'value': properties.textBoxBtnOk,
            'styles': {
              'width': '70px'
            }
          });

          this.PromptBtnCancel = new Element('input', {
            'id': 'BoxPromptBtnCancel',
            'type': 'submit',
            'value': properties.textBoxBtnCancel,
            'styles': {
              'width': '70px'
            }
          });
          
          type = properties.password ? 'password' : 'text';
          this.PromptInput = new Element('input', {
            'id': 'BoxPromptInput',
            'type': type,
            'value': input,
            'styles': {
              'width': '250px'
            }
          });

          this.PromptBtnOk.addEvent('click', function() {
            this.options.onReturn = this.PromptInput.value;
            this.display(0);
          }.bind(this));

          this.PromptBtnCancel.addEvent('click', function() {
            this.options.onReturn = false;
            this.display(0);
          }.bind(this));

          this.Content.setProperty('class','BoxPrompt').set('html',message + '<br />');
          this.PromptInput.injectInside(this.Content);
          new Element('br').injectInside(this.Content);
          this.PromptBtnOk.injectInside(this.ContenedorBotones);
          this.PromptBtnCancel.injectInside(this.ContenedorBotones);


          this.ContenedorBotones.injectInside(this.Content);

          this.display(1);
      }
      else
      {
          this.options.onReturn = false;
          this.display(0);		
      }

    });

		this.i++;

		if(this.i==1) this.callChain();

	},

	/*
	Property: alert
		Shortcut for alert
		
	Argument:
		properties - see Options in messageBox
	*/		
	alert: function(message, properties){
		this.messageBox('alert', message, properties);
	},

	/*
	Property: info
		Shortcut for alert info
		
	Argument:
		properties - see Options in messageBox
	*/		
	info: function(message, properties){
		this.messageBox('info', message, properties);
	},

	/*
	Property: error
		Shortcut for alert error
		
	Argument:
		properties - see Options in messageBox
	*/		
	error: function(message, properties){
		this.messageBox('error', message, properties);
	},

	/*
	Property: confirm
		Shortcut for confirm
		
	Argument:
		properties - see Options in messageBox
	*/
	confirm: function(message, properties){
		this.messageBox('confirm', message, properties);
	},

	/*
	Property: prompt
		Shortcut for prompt
		
	Argument:
		properties - see Options in messageBox
	*/	
	prompt: function(message, input, properties){
		this.messageBox('prompt', message, properties, input);
	}
});

SexyAlertBox.implement(new Events, new Options);

window.addEvent('domready', function() {
  Sexy = new SexyAlertBox();
});

/* dotter */
var Dotter = new Class({
	
	/* implements */
	Implements: [Options,Events],

	/* options */
	options: {
		delay: 1000,
		dot: '.',
		message: 'Sending',
		numDots: 3,
		property: 'text',
		reset: false/*,
		onDot,
		onStart,
		onStop
		*/
	},
	
	/* initialization */
	initialize: function(container,options) {
		/* set options */
		this.setOptions(options);
		this.container = document.id(container);
		this.dots = 0;
		this.running = false;
	},
	
	/* adds dot */
	dot: function() {
		if(this.running) {
			var text = this.container.get(this.options.property);
			this.dots++;
			this.container.set(this.options.property,(this.dots % this.options.numDots != 0 ? text : this.options.message) + '' + this.options.dot);
		}
		return this;
	},
	
	/* loads or resets the dotter */
	load: function() {
		this.loaded = true;
		this.dots = 0;
		this.dotter = function(){ this.dot(); this.fireEvent('dot'); }.bind(this);
		this.periodical = this.dotter.periodical(this.options.delay);
		this.container.set(this.options.property,this.options.message + '' + this.options.dot);
		return this;
	},
	
	/* start the dotter */
	start: function() {
		if(!this.loaded || this.options.reset) this.load();
		this.running = true;
		this.fireEvent('start');
		return this;
	},
	
	/* stop the dotter */
	stop: function() {
		this.running = this.loaded = false;
		$clear(this.periodical);
		this.fireEvent('stop');
		return this;
	}
});	

///overlay/////
var Overlay = new Class({
	
	Implements: [Options,Events],
	
	options:  {
		id: 'overlay',
		color: '#000',
		duration: 500,
		opacity: 0.7,
		zIndex: 50000/*,
		onClick: $empty,
		onClose: $empty,
		onHide: $empty,
		onOpen: $empty,
		onShow: $empty
		*/
	},
	
	initialize: function(container,options) {
		this.setOptions(options);
		this.container = document.id(container);
		this.overlay = new Element('div',{
			id: this.options.id,
			opacity: 0,
			styles: {
				position: 'absolute',
				background: this.options.color,
				left: 0,
				top: 0,
				'z-index': this.options.zIndex
			},
			events: {
				click: function() {
					this.fireEvent('click');
				}.bind(this)
			}
		}).inject(this.container);
		this.tween = new Fx.Tween(this.overlay,{ 
			duration: this.options.duration,
			link: 'cancel',
			property: 'opacity',
			onStart: function() {
				var size = this.container.getScrollSize();
				this.overlay.setStyles({
					width: size.x,
					height: size.y
				});
			}.bind(this),
			onComplete: function() {
				this.fireEvent(this.overlay.get('opacity') == this.options.opacity ? 'show' : 'hide');
			}.bind(this)
		});
	},
	open: function() {
		this.fireEvent('open');
		this.tween.start(this.options.opacity);
	},
	close: function() {
		this.fireEvent('close');
		this.tween.start(0);
	}
});	

////element flash/////
Element.implement({
	flash: function(to,from,reps,prop,dur) {
		
		//defaults
		if(!reps) { reps = 1; }
		if(!prop) { prop = 'background-color'; }
		if(!dur) { dur = 250; }
		
		//create effect
		var effect = new Fx.Tween(this, {
				duration: dur,
				link: 'chain'
			})
		
		//do it!
		for(x = 1; x <= reps; x++)
		{
			effect.start(prop,from,to).start(prop,to,from);
		}
	}
});

/**
	SlideItMoo v1.1 - Image slider
	(c) 2007-2010 Constantin Boiangiu <http://www.php-help.ro>
	MIT-style license.
	
	Changes from version 1.0
	- added continuous navigation
	- changed the navigation from Fx.Scroll to Fx.Morph
	- added new parameters: itemsSelector: pass the CSS class for divs
	- itemWidth: for elements with margin/padding pass their width including margin/padding
	
	Updates ( August 4th 2009 )
	- added new parameter 'elemsSlide'. When this is set to a value lower that the actual number of elements in HTML, it will slide at once that number of elements when navigation clicked. Default: null
	- added onChange event that returns the index of the current element
	
	Updates ( January 12th 2010 )
	- vertical sliding available. First, set your HTML to display vertically and set itemHeight:height of individual items ( including padding, border and so on ) and slideVertical:true
	- navigators ( forward/back ) no longer added by script. Instead, add them into overallContainer making their display from CSS and after add the CSS selector class to navs parameter
		IE: navs:{ 
				fwd:'.SlideItMoo_forward', 
				bk:'.SlideItMoo_back' 
			}
	- new method available resetAll(). When called, this will reset the previous settings and restart the script. Useful if you change slider content on-the-fly
	- new method available to stop autoSlide ( stopAutoSlide() ). To start autoslide back, use startAutoSlide()
**/
var SlideItMoo = new Class({
	
	Implements: [Events,Options],
	options: {
		overallContainer: null,/* outer container, contains fwd/back buttons and container for thumbnails */
		elementScrolled: null, /* has a set width/height with overflow hidden to allow sliding of elements */
		thumbsContainer: null,	/* actual thumbnails container */	
		itemsSelector: null, /* css class for inner elements ( ie: .SlideItMoo_element ) */
		itemsVisible:5, /* number of elements visible at once */
		elemsSlide: null, /* number of elements that slide at once */
		itemWidth: null, /* single element width */
		itemHeight: null, /* single element height */
		navs:{ /* starting this version, you'll need to put your back/forward navigators in your HTML */
			fwd:'.SlideItMoo_forward', /* forward button CSS selector */
			bk:'.SlideItMoo_back' /* back button CSS selector */
		},
		slideVertical: false, /* vertical sliding enabled */
		showControls:1, /* show forward/back controls */
		transition: Fx.Transitions.linear, /* transition */
		duration: 800, /* transition duration */
		direction: 1, /* sliding direction ( 1: enter from left/top; -1:enter from right/bottom ) */
		autoSlide: false, /* auto slide - as milliseconds ( ie: 10000 = 10 seconds ) */
		mouseWheelNav: false, /* enable mouse wheel nav */
		startIndex: null
		/*onChange: $empty*/
	},
	
	initialize: function(options){
		this.setOptions(options);
		/* all elements are identified on CSS selector (itemsSelector) */
		this.elements = $(this.options.thumbsContainer).getElements(this.options.itemsSelector);
		this.totalElements = this.elements.length;
		if( this.totalElements <= this.options.itemsVisible ) return;
		// width of thumbsContainer children
		var defaultSize = this.elements[0].getSize();
		this.elementWidth = this.options.itemWidth || defaultSize.x;
		this.elementHeight = this.options.itemHeight || defaultSize.y;
		this.currentElement = 0;
		this.direction = this.options.direction;
		this.autoSlideTotal = this.options.autoSlide + this.options.duration;
		if( this.options.elemsSlide == 1 ) this.options.elemsSlide = null;
		this.begin();		
	},
		
	begin: function(){	
		/* if navigation is needed and enabled, add it */
		this.addControls();
				
		// resizes the container div's according to the number of itemsVisible thumbnails
		this.setContainersSize();
		
		this.myFx = new Fx.Tween(this.options.thumbsContainer, { 
			property: (this.options.slideVertical ? 'margin-top':'margin-left'),
			wait: true, 
			transition: this.options.transition,
			duration: this.options.duration
		});		
				
		/* if autoSlide is not set, scoll on mouse wheel */
		if( this.options.mouseWheelNav && !this.options.autoSlide ){
			$(this.options.thumbsContainer).addEvent('mousewheel', function(ev){
				new Event(ev).stop();
				this.slide(-ev.wheel);								
			}.bind(this));
		}
		
		/* start index element */
		if( this.options.startIndex && this.options.startIndex > 0 && this.options.startIndex < this.elements.length ){
			for( var t = 1; t < this.options.startIndex; t++ )
				this.rearange();
		}
		
		if( this.options.autoSlide && this.elements.length > this.options.itemsVisible )
			this.startAutoSlide();		
	},
	/* resets the whole slider in case content changes */
	resetAll: function(){
		$(this.options.overallContainer).removeProperty('style');
		$(this.options.elementScrolled).removeProperty('style');
		$(this.options.thumbsContainer).removeProperty('style');
		this.stopAutoSlide();
		if( $defined( this.fwd ) ){
			this.fwd.dispose();
			this.bkwd.dispose();
		}
		this.initialize();
	},
	/* sets the containers width to leave visible only the specified number of elements */
	setContainersSize: function(){
		var overallSize = {};
		var scrollSize = {};
		var thumbsSize = {};
		
		if( this.options.slideVertical ){
			//overallSize.height = this.options.itemsVisible * this.elementHeight + 50 * this.options.showControls;
			scrollSize.height = this.options.itemsVisible * this.elementHeight;
			thumbsSize.height = this.totalElements * (this.elementHeight + 10);			
		}else{
			/* if navigation is enabled, add the width to the overall size */
			var navsSize = 0;
			if( this.options.showControls ){
				var s1 = this.fwd.getSize();
				var s2 = this.bkwd.getSize();
				var navsSize = 0;
			}
			overallSize.width = this.options.itemsVisible * this.elementWidth + navsSize;
			scrollSize.width = this.options.itemsVisible * this.elementWidth;
			thumbsSize.width = this.totalElements * (this.elementWidth + 10);			
		}
		$(this.options.overallContainer).set({
			styles : overallSize
		});
		$(this.options.elementScrolled).set({
			styles : scrollSize
		});
		$(this.options.thumbsContainer).set({
			styles : thumbsSize
		});
	},
	/* adds forward/back buttons */
	addControls: function(){
		if( !this.options.showControls || this.elements.length <= this.options.itemsVisible ) return;
		
		this.fwd = $(this.options.overallContainer).getElement(this.options.navs.fwd);
		this.bkwd = $(this.options.overallContainer).getElement(this.options.navs.bk);
		
		if( this.fwd )
			this.fwd.addEvent('click', this.slide.pass(1, this));
		if( this.bkwd )
			this.bkwd.addEvent('click', this.slide.pass(-1, this));		
	},
	/* slides elements */
	slide: function( direction ){
		
		if(this.started) return;
		this.direction = direction ? direction : this.direction;
		var currentIndex = this.currentIndex();
		/* if multiple elements are to be skipped (elemsSlide > 1), calculate the ending element */
		if( this.options.elemsSlide && this.options.elemsSlide>1 && this.endingElem==null ){
			this.endingElem = this.currentElement;			
			for(var i = 0; i < this.options.elemsSlide; i++ ){
				this.endingElem += direction;
				if( this.endingElem >= this.totalElements ) this.endingElem = 0;
				if( this.endingElem < 0 ) this.endingElem = this.totalElements-1;
			}
		}	
		
		var s = new Hash();
		var fxDist = 0;
		if( this.options.slideVertical ){
			s.include('margin-top', -this.elementHeight);
			fxDist = this.direction == 1 ? -this.elementHeight : 0;
		}else{
			s.include('margin-left', -this.elementWidth);
			fxDist = this.direction == 1 ? -this.elementWidth : 0;
		}
		
		if( this.direction == -1 ){
			this.rearange();
			$(this.options.thumbsContainer).setStyles(s);			
		}
		this.started = true;
		
		this.myFx.start( fxDist ).chain( function(){			
			this.rearange(true);			
			if(this.options.elemsSlide){
				if( this.endingElem !== this.currentElement ){ 
					if( this.options.autoSlide )
						this.stopAutoSlide();
					this.slide(this.direction);
				}
				else {
					if( this.options.autoSlide )
						this.startAutoSlide();
					this.endingElem = null;
				}
			}
		}.bind(this)  );
		
		this.fireEvent('onChange', currentIndex);
		
	},
	/* rearanges elements for continuous navigation */
	rearange: function( rerun ){
		
		if(rerun) this.started = false;
		if( rerun && this.direction == -1 ) return;
		
		this.currentElement = this.currentIndex( this.direction );
		
		var s = new Hash();
		if( this.options.slideVertical ) s.include('margin-top', 0);
		else s.include('margin-left', 0);
		
		$(this.options.thumbsContainer).setStyles(s);
		
		if( this.currentElement == 1 && this.direction == 1 ){
			this.elements[0].injectAfter(this.elements[this.totalElements-1]);
			return;
		}
		if( (this.currentElement == 0 && this.direction ==1) || (this.direction==-1 && this.currentElement == this.totalElements-1) ){
			this.rearrangeElement( this.elements.getLast(), this.direction == 1 ? this.elements[this.totalElements-2] : this.elements[0]);
			return;
		}
		
		if( this.direction == 1 ) this.rearrangeElement( this.elements[this.currentElement-1], this.elements[this.currentElement-2]);
		else this.rearrangeElement( this.elements[this.currentElement], this.elements[this.currentElement+1]);			
	},
	/* rearanges a single element for continuous navigation */
	rearrangeElement: function( element , indicator ){
		this.direction == 1 ? element.injectAfter(indicator) : element.injectBefore(indicator);
	},
	/* determines the current index in element list */
	currentIndex: function(){
		var elemIndex = null;
		switch( this.direction ){
			/* forward */
			case 1:
				elemIndex = this.currentElement >= this.totalElements-1 ? 0 : this.currentElement + this.direction;				
			break;
			/* backwards */
			case -1:
				elemIndex = this.currentElement == 0 ? this.totalElements - 1 : this.currentElement + this.direction;
			break;
		}
		return elemIndex;
	},
	/* starts auto sliding */
	startAutoSlide: function(){
		this.startIt = this.slide.bind(this).pass(this.direction|1);
		this.autoSlide = this.startIt.periodical(this.autoSlideTotal, this);
		this.isRunning = true;
		this.elements.addEvents({
			'mouseenter':function(){
				$clear(this.autoSlide);
				this.isRunning = false;
			}.bind(this),
			'mouseleave':function(){
				this.autoSlide = this.startIt.periodical(this.autoSlideTotal, this);
				this.isRunning = true;
			}.bind(this)
		})
	},
	/* stops auto sliding */
	stopAutoSlide: function(){
		$clear(this.autoSlide);
		this.isRunning = false;
	}
})

/**
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: {/*
		onComplete: $empty,
		onEnd: $empty,
		onStart: $empty,*/
		captions: false,
		center: true,
		classes: [],
		controller: false,
		delay: 2000,
		duration: 750,
		fast: false,
		height: false,
		href: '',
		hu: '',
		linked: false,
		loader: {'animate': ['css/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(p){return -(Math.cos(Math.PI * p) - 1) / 2;},
		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.slideshow = $(el);
		if (!this.slideshow) 
			return;
		this.slideshow.set('styles', {'display': 'block', 'position': 'relative', 'z-index': 0});
		var match = window.location.href.match(this.options.match);
		this.slide = (this.options.match && match) ? match[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 anchor = this.slideshow.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'];
		var 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.slideshow.getElements(this.classes.get('thumbnails') + ' img');
			this.slideshow.getElements(this.classes.get('images') + ' img').each(function(img, i){
				var src = img.get('src');
				var caption = $pick(img.get('alt'), img.get('title'), '');
				var parent = img.getParent();
				var properties = (parent.get('tag') == 'a') ? parent.getProperties : {};
				var href = img.getParent().get('href') || '';
				var thumbnail = (thumbnails[i]) ? thumbnails[i].get('src') : '';
				data[src] = {'caption': caption, 'href': href, 'thumbnail': thumbnail};
			});
		}
		var loaded = this.load(data);
		if (!loaded)
			return; 
		
		// events
		
		this.events = $H({'keydown': [], 'keyup': [], 'mousemove': []});
		var keyup = function(e){
			switch(e.key){
				case 'left': 
					this.prev(e.shift); break;
				case 'right': 
					this.next(e.shift); break;
				case 'p': 
					this.pause(); break;
			}
		}.bind(this);		
		this.events.keyup.push(keyup);
		document.addEvent('keyup', keyup);

		// required elements
			
		var el = this.slideshow.getElement(this.classes.get('images'));
		var images = (el) ? el.empty() : new Element('div', {'class': this.classes.get('images').substr(1)}).inject(this.slideshow);
		var div = images.getSize();
		this.height = this.options.height || div.y;		
		this.width = this.options.width || div.x;
		images.set({'styles': {'display': 'block', 'height': this.height, 'overflow': 'hidden', 'position': 'relative', 'width': this.width}});
		this.slideshow.store('images', images);
		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(img){
			anchor.clone().cloneEvents(anchor).grab(img).inject(images);
		});
		
		// optional elements
		
		if (this.options.captions)
 			this._captions();
		if (this.options.controller)
			this._controller();
		if (this.options.loader)
 			this._loader();
		if (this.options.thumbnails)
			this._thumbnails();
			
		// 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 - 1 + this.data.images.length) % this.data.images.length == n || $time() < this.transition)
			return;		
		$clear(this.timer);
		this.delay = 0;		
		this.direction = (direction) ? direction : ((n < this.slide) ? 'right' : 'left');
		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 it's a random show get the previous slide from the showed array

				if (this.showed.i < 2)
					return;
				this.showed.i -= 2;
				n = this.showed.array[this.showed.i];
			}
			else
				n = (this.slide - 2 + 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 ($chk(p))
			this.paused = (p) ? 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(img){
				['morph', 'tween'].each(function(p){
					if (this.retrieve(p)) this.get(p).resume();
				}, img);
			});
			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(img){
				['morph', 'tween'].each(function(p){
					if (this.retrieve(p)) this.get(p).pause();
				}, img);
			});
			if (this.options.controller)
				this.slideshow.getElement('.' + this.classes.pause).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 ($type(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': []};
		for (var image in data){
			var obj = data[image] || {};
			var caption = (obj.caption) ? obj.caption.trim() : '';
			var href = (obj.href) ? obj.href.trim() : ((this.options.linked) ? this.options.hu + image : this.options.href);
			var thumbnail = (obj.thumbnail) ? obj.thumbnail.trim() : 't' + image;
			this.data.images.push(image);
			this.data.captions.push(caption);
			this.data.hrefs.push(href);
			this.data.thumbnails.push(thumbnail);
		}
		if (this.options.random)
			this.slide = $random(0, this.data.images.length - 1);
		
		// only run when data is loaded dynamically into an existing slideshow instance
		
		if (this.options.thumbnails && this.slideshow.retrieve('thumbnails'))
			this._thumbnails();
		if (this.slideshow.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.transition = 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){
		this.events.each(function(array, e){
			array.each(function(fn){ document.removeEvent(e, fn); });
		});
		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 (p)
			this.slideshow[p]();
	},
	
/**
Private method: preload
	Preloads the next slide in the show, once loaded triggers the show, updates captions, thumbnails, etc.
*/

	_preload: function(fast){
		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(prop){
				this.image.set(prop, this.preloader.get(prop));
			}, this);
			this._resize(this.image);
			this._center(this.image);
			var anchor = this.image.getParent();
			if (this.data.hrefs[this.slide])
				anchor.set('href', this.data.hrefs[this.slide]);			
			else
				anchor.erase('href');
			var text = (this.data.captions[this.slide])
				? this.data.captions[this.slide].replace(/<.+?>/gm, '').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, "'") 
				: '';
			this.image.set('alt', text);		
			if (this.options.titles)
				anchor.set('title', text);
			if (this.options.loader)
				this.slideshow.retrieve('loader').fireEvent('hide');
			if (this.options.captions)
				this.slideshow.retrieve('captions').fireEvent('update', fast);				
			if (this.options.thumbnails)
				this.slideshow.retrieve('thumbnails').fireEvent('update', fast); 			
			this._show(fast);
			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, 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', $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'));
		var visible = this.classes.get('images', 'visible');
		var 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').set(hidden).start(visible);
				}.pass([hidden, visible], this);
				hidden = this.classes.get('images', ((this.direction == 'left') ? 'prev' : 'next'));
				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 = (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 n = this.slide;
				if (this.showed.array.getLast() != n) this.showed.array.push(n);
				while (this.slide == n)
					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();
	},

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

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

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

	_resize: function(img){
		if (this.options.resize){
			var h = this.preloader.get('height'), w = this.preloader.get('width');
			var dh = this.height / h, dw = this.width / w, d;
			if (this.options.resize == 'length')
				d = (dh > dw) ? dw : dh;
			else
				d = (dh > dw) ? dh : dw;
			img.set('styles', {height: Math.ceil(h * d), width: Math.ceil(w * d)});
		}	
	},

/**
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.firstrun = false;
			this.pause(1);
		}
		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.
*/

	_captions: function(){
 		if (this.options.captions === true) 
 			this.options.captions = {};
		var el = this.slideshow.getElement(this.classes.get('captions'));
		var captions = (el) ? el.empty() : new Element('div', {'class': this.classes.get('captions').substr(1)}).inject(this.slideshow);
		captions.set({
			'events': {
				'update': function(fast){	
					var captions = this.slideshow.retrieve('captions');
					var empty = (this.data.captions[this.slide] === '');
					if (fast){
						var p = (empty) ? 'hidden' : 'visible';
						captions.set('html', this.data.captions[this.slide]).get('morph').cancel().set(this.classes.get('captions', p));
					}
					else {
						var fn = (empty) ? $empty : function(n){
							this.slideshow.retrieve('captions').set('html', this.data.captions[n]).morph(this.classes.get('captions', 'visible'))
						}.pass(this.slide, this);		
						captions.get('morph').cancel().start(this.classes.get('captions', 'hidden')).chain(fn);
					}
				}.bind(this)
			},
			'morph': $merge(this.options.captions, {'link': 'chain'})
		});
		this.slideshow.store('captions', captions);
	},

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

	_controller: function(){
 		if (this.options.controller === true)
 			this.options.controller = {};
		var el = this.slideshow.getElement(this.classes.get('controller'));
		var controller = (el) ? el.empty() : new Element('div', {'class': this.classes.get('controller').substr(1)}).inject(this.slideshow);
		var ul = new Element('ul').inject(controller);
		$H({'first': 'Shift + Leftwards Arrow', 'prev': 'Leftwards Arrow', 'pause': 'P', 'next': 'Rightwards Arrow', 'last': 'Shift + Rightwards Arrow'}).each(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.slideshow.retrieve(action, new Element('a', {
				'title': ((action == 'pause') ? this.classes.play.capitalize() + ' / ' : '') + this.classes[action].capitalize() + ' [' + accesskey + ']'				
			}).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)
			});		
		}, this);
		controller.set({
			'events': {
				'hide': function(hidden){  
					if (!this.retrieve('hidden'))
						this.store('hidden', true).morph(hidden);
				}.pass(this.classes.get('controller', 'hidden'), controller),
				'show': function(visible){  
					if (this.retrieve('hidden'))
						this.store('hidden', false).morph(visible);
				}.pass(this.classes.get('controller', 'visible'), controller)
			},
			'morph': $merge(this.options.controller, {'link': 'cancel'})
		}).store('hidden', false);
		var keydown = function(e){
			if (['left', 'right', 'p'].contains(e.key)){
				var controller = this.slideshow.retrieve('controller');
				if (controller.retrieve('hidden'))
					controller.get('morph').set(this.classes.get('controller', 'visible')); 			
				switch(e.key){
					case 'left': 
						this.slideshow.retrieve((e.shift) ? 'first' : 'prev').fireEvent('mouseenter'); break;
					case 'right':
						this.slideshow.retrieve((e.shift) ? 'last' : 'next').fireEvent('mouseenter'); break;
					default:
						this.slideshow.retrieve('pause').fireEvent('mouseenter'); break;
				}
			}
		}.bind(this);
		this.events.keydown.push(keydown);
		var keyup = function(e){
			if (['left', 'right', 'p'].contains(e.key)){
				var controller = this.slideshow.retrieve('controller');
				if (controller.retrieve('hidden'))
					controller.store('hidden', false).fireEvent('hide'); 
				switch(e.key){
					case 'left': 
						this.slideshow.retrieve((e.shift) ? 'first' : 'prev').fireEvent('mouseleave'); break;
					case 'right': 
						this.slideshow.retrieve((e.shift) ? 'last' : 'next').fireEvent('mouseleave'); break;
					default:
						this.slideshow.retrieve('pause').fireEvent('mouseleave'); break;
				}
			}
		}.bind(this);
		this.events.keyup.push(keyup);
		var mousemove = function(e){
			var images = this.slideshow.retrieve('images').getCoordinates();
			if (e.page.x > images.left && e.page.x < images.right && e.page.y > images.top && e.page.y < images.bottom)
				this.slideshow.retrieve('controller').fireEvent('show');
			else
				this.slideshow.retrieve('controller').fireEvent('hide');
		}.bind(this);
		this.events.mousemove.push(mousemove);
		document.addEvents({'keydown': keydown, 'keyup': keyup, 'mousemove': mousemove});
		this.slideshow.retrieve('controller', controller).fireEvent('hide');
	},

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

	_loader: function(){
 		if (this.options.loader === true) 
 			this.options.loader = {};
		var loader = 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 i = 0; i < this.options.loader.animate[1]; i++)
				img = new Asset.image(this.options.loader.animate[0].replace(/#/, i));
			if (Browser.Engine.trident4 && this.options.loader.animate[0].contains('png'))
				loader.setStyle('backgroundImage', 'none');					
		}
		loader.set('events', {
			'animate': function(){  
				var loader = this.slideshow.retrieve('loader');				
				var i = (loader.retrieve('i').toInt() + 1) % this.options.loader.animate[1];
				loader.store('i', i);
				var img = this.options.loader.animate[0].replace(/#/, i);
				if (Browser.Engine.trident4 && this.options.loader.animate[0].contains('png'))
					loader.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + img + '", sizingMethod="scale")';
				else 
					loader.setStyle('backgroundImage', 'url(' + img + ')');
			}.bind(this),
			'hide': function(){  
				var loader = this.slideshow.retrieve('loader');
				if (!loader.retrieve('hidden')){
					loader.store('hidden', true).morph(this.classes.get('loader', 'hidden'));
					if (this.options.loader.animate)
						$clear(loader.retrieve('timer'));					
				}
			}.bind(this),
			'show': function(){  
				var loader = this.slideshow.retrieve('loader');
				if (loader.retrieve('hidden')){
					loader.store('hidden', false).morph(this.classes.get('loader', 'visible'));
					if (this.options.loader.animate)
						loader.store('timer', function(){this.fireEvent('animate');}.periodical(50, loader));
				}
			}.bind(this)
		});
		this.slideshow.retrieve('loader', loader).fireEvent('hide');
	},
	
/**
Private method: thumbnails
	Builds the optional thumbnails element, adds interactivity.
	This method can safely be removed if the thumbnails option is not enabled.
*/

	_thumbnails: function(){
 		if (this.options.thumbnails === true) 
 			this.options.thumbnails = {}; 
		var el = this.slideshow.getElement(this.classes.get('thumbnails'));
		var thumbnails = (el) ? el.empty() : new Element('div', {'class': this.classes.get('thumbnails').substr(1)}).inject(this.slideshow);
		thumbnails.setStyle('overflow', 'hidden');
		var ul = new Element('ul', {'tween': {'link': 'cancel'}}).inject(thumbnails);
		this.data.thumbnails.each(function(thumbnail, i){
			var li = new Element('li').inject(ul);
			var a = new Element('a', {
				'events': {
					'click': function(i){
						this.go(i); 
						return false; 
					}.pass(i, this),
					'loaded': function(){
						this.data.thumbnails.pop();
						if (!this.data.thumbnails.length){
							var div = thumbnails.getCoordinates();
							var props = thumbnails.retrieve('props');			
							var limit = 0, pos = props[1], size = props[2];		
							thumbnails.getElements('li').each(function(li){			
								var li = li.getCoordinates();		
								if (li[pos] > limit) limit = li[pos];
							}, this);			
							thumbnails.store('limit', div[size] + div[props[0]] - limit);
						}
					}.bind(this)
				},
				'href': this.options.hu + this.data.images[i],
				'morph': $merge(this.options.thumbnails, {'link': 'cancel'})
			}).inject(li);
			if (this.data.captions[i] && this.options.titles)
				a.set('title', this.data.captions[i].replace(/<.+?>/gm, '').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, "'"));
			var img = new Asset.image(this.options.hu + thumbnail, {
				'onload': function(){this.fireEvent('loaded');}.bind(a) 
			}).inject(a);
		}, this);
		thumbnails.set('events', {
			'scroll': function(n, fast){
				var div = this.getCoordinates();
				var ul = this.getElement('ul').getPosition();
				var props = this.retrieve('props');
				var axis = props[3], delta, pos = props[0], size = props[2], value;				
				var tween = this.getElement('ul').get('tween', {'property': pos});	
				if ($chk(n)){
					var li = this.getElements('li')[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 = -0.2;			
					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);
					}
				}				
			}.bind(thumbnails),
			'update': function(fast){
				var thumbnails = this.slideshow.retrieve('thumbnails');
				thumbnails.getElements('a').each(function(a, i){	
					if (i == 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]);
			}.bind(this)
		})
		var div = thumbnails.getCoordinates();
		thumbnails.store('props', (div.height > div.width) ? ['top', 'bottom', 'height', 'y'] : ['left', 'right', 'width', 'x']);
		var mousemove = function(e){
			var div = this.getCoordinates();
			if (e.page.x > div.left && e.page.x < div.right && e.page.y > div.top && e.page.y < div.bottom){
				this.store('page', e.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(thumbnails);
		this.events.mousemove.push(mousemove);
		document.addEvent('mousemove', mousemove);
		this.slideshow.store('thumbnails', thumbnails);
	}
});


/**
Script: Slideshow.KenBurns.js
	Slideshow.KenBurns - KenBurns extension for Slideshow, includes zooming and panning effects.

License:
	MIT-style license.

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

Slideshow.KenBurns = new Class({
	Extends: Slideshow,
	
	options: {
		pan: [100, 100],
		zoom: [50, 50]
	},
	
/**
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.KenBurns(element, data, options);
*/

	initialize: function(el, data, options){
		options.overlap = true;
		options.resize = true;
		['pan', 'zoom'].each(function(p){
				if ($chk(this[p])){
					if ($type(this[p]) != 'array') this[p] = [this[p], this[p]];
					this[p].map(function(n){return (n.toInt() || 0).limit(0, 100);});					
				}
		}, options);
		this.parent(el, data, options);
	},

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

	_show: function(fast){
		if (!this.image.retrieve('morph')){
			['a', 'b'].each(function(image){
				this[image].set('tween', {
					'duration': this.options.duration, 'link': 'cancel', 'onStart': this._start.bind(this), 'onComplete': this._complete.bind(this), 'property': 'opacity'}
				).get('morph', {
					'duration': (this.options.delay + this.options.duration * 2), 'link': 'cancel', 'transition': $arguments(0)}
				);
			}, this);
		}
		this.image.set('styles', {'bottom': 'auto', 'left': 'auto', 'right': 'auto', 'top': 'auto'});
		var props = ['top left', 'top right', 'bottom left', 'bottom right'][this.counter % 4].split(' ');
		props.each(function(prop){this.image.setStyle(prop, 0);}, this);
		dh = this.height / this.preloader.height;
		dw = this.width / this.preloader.width;
		delta = (dw > dh) ? dw : dh;
		var values = {};
		var zoom = ($random.run(this.options.zoom) / 100.0) + 1;
		var pan = Math.abs(($random.run(this.options.pan) / 100.0) - 1);
		['height', 'width'].each(function(prop, i){
			var e = Math.ceil(this.preloader[prop] * delta);
			var s = (e * zoom).toInt();		
			values[prop] = [s, e];
			if (dw > dh || i){
				e = (this[prop] - this.image[prop]);
				s = (e * pan).toInt();			
				values[props[i]] = [s, e];
			}
		}, this);
		var paused = (this.firstrun && this.options.paused);
		if (fast || paused){
			this._center(this.image);
			this.image.get('morph').cancel();
			if (paused)
				this.image.get('tween').cancel().set(0).start(1);
			else
				this.image.get('tween').cancel().set(1);
		} 
		else{
			this.image.get('morph').start(values);
			this.image.get('tween').set(0).start(1);
		}
	}
});
