/* 
-------------------------------------------------------------
	moo.rd plus MooTools
-------------------------------------------------------------
	moo.rd 1.3.2 Copyright (c) 2007 by Riccardo Degni
	MooTools 1.2 Copyright (c) 2006-2007 by Valerio Proietti
-------------------------------------------------------------
*/

//MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006-2007 Valerio Proietti, <http://mad4milk.net>, MIT Style License.

var MooTools={version:"1.2dev",build:"1553"};var Native=function(J){J=J||{};var F=J.afterImplement||function(){};var G=J.generics;G=(G!==false);var H=J.legacy;
var E=J.initialize;var B=J.protect;var A=J.name;var C=E||H;C.constructor=Native;C.$family={name:"native"};if(H&&E){C.prototype=H.prototype;}C.prototype.constructor=C;
if(A){var D=A.toLowerCase();C.prototype.$family={name:D};Native.typize(C,D);}var I=function(M,K,N,L){if(!B||L||!M.prototype[K]){M.prototype[K]=N;}if(G){Native.genericize(M,K,B);
}F.call(M,K,N);return M;};C.implement=function(L,K,N){if(typeof L=="string"){return I(this,L,K,N);}for(var M in L){I(this,M,L[M],K);}return this;};C.alias=function(M,K,N){if(typeof M=="string"){M=this.prototype[M];
if(M){I(this,K,M,N);}}else{for(var L in M){this.alias(L,M[L],K);}}return this;};return C;};Native.implement=function(D,C){for(var B=0,A=D.length;B<A;B++){D[B].implement(C);
}};Native.genericize=function(B,C,A){if((!A||!B[C])&&typeof B.prototype[C]=="function"){B[C]=function(){var D=Array.prototype.slice.call(arguments);return B.prototype[C].apply(D.shift(),D);
};}};Native.typize=function(A,B){if(!A.type){A.type=function(C){return($type(C)===B);};}};Native.alias=function(E,B,A,F){for(var D=0,C=E.length;D<C;D++){E[D].alias(B,A,F);
}};(function(B){for(var A in B){Native.typize(B[A],A);}})({"boolean":Boolean,"native":Native,object:Object});(function(B){for(var A in B){new Native({name:A,initialize:B[A],protect:true});
}})({String:String,Function:Function,Number:Number,Array:Array,RegExp:RegExp,Date:Date});(function(B,A){for(var C=A.length;C--;C){Native.genericize(B,A[C],true);
}return arguments.callee;})(Array,["pop","push","reverse","shift","sort","splice","unshift","concat","join","slice","toString","valueOf","indexOf","lastIndexOf"])(String,["charAt","charCodeAt","concat","indexOf","lastIndexOf","match","replace","search","slice","split","substr","substring","toLowerCase","toUpperCase","valueOf"]);
function $chk(A){return !!(A||A===0);}function $clear(A){clearTimeout(A);clearInterval(A);return null;}function $defined(A){return(A!=undefined);}function $empty(){}function $arguments(A){return function(){return arguments[A];
};}function $lambda(A){return(typeof A=="function")?A:function(){return A;};}function $extend(C,A){for(var B in (A||{})){C[B]=A[B];}return C;}function $unlink(C){var B;
switch($type(C)){case"object":B={};for(var E in C){B[E]=$unlink(C[E]);}break;case"hash":B=$unlink(C.getClean());break;case"array":B=[];for(var D=0,A=C.length;
D<A;D++){B[D]=$unlink(C[D]);}break;default:return C;}return B;}function $merge(){var E={};for(var D=0,A=arguments.length;D<A;D++){var B=arguments[D];if($type(B)!="object"){continue;
}for(var C in B){var G=B[C],F=E[C];E[C]=(F&&$type(G)=="object"&&$type(F)=="object")?$merge(F,G):$unlink(G);}}return E;}function $pick(){for(var B=0,A=arguments.length;
B<A;B++){if(arguments[B]!=undefined){return arguments[B];}}return null;}function $random(B,A){return Math.floor(Math.random()*(A-B+1)+B);}function $splat(B){var A=$type(B);
return(A)?((A!="array"&&A!="arguments")?[B]:B):[];}var $time=Date.now||function(){return new Date().getTime();};function $try(){for(var B=0,A=arguments.length;
B<A;B++){try{return arguments[B]();}catch(C){}}return null;}function $type(A){if(A==undefined){return false;}if(A.$family){return(A.$family.name=="number"&&!isFinite(A))?false:A.$family.name;
}if(A.nodeName){switch(A.nodeType){case 1:return"element";case 3:return(/\S/).test(A.nodeValue)?"textnode":"whitespace";}}else{if(typeof A.length=="number"){if(A.callee){return"arguments";
}else{if(A.item){return"collection";}}}}return typeof A;}var Hash=new Native({name:"Hash",initialize:function(A){if($type(A)=="hash"){A=$unlink(A.getClean());
}for(var B in A){this[B]=A[B];}return this;}});Hash.implement({getLength:function(){var B=0;for(var A in this){if(this.hasOwnProperty(A)){B++;}}return B;
},forEach:function(B,C){for(var A in this){if(this.hasOwnProperty(A)){B.call(C,this[A],A,this);}}},getClean:function(){var B={};for(var A in this){if(this.hasOwnProperty(A)){B[A]=this[A];
}}return B;}});Hash.alias("forEach","each");function $H(A){return new Hash(A);}Array.implement({forEach:function(C,D){for(var B=0,A=this.length;B<A;B++){C.call(D,this[B],B,this);
}}});Array.alias("forEach","each");function $A(C){if(C.item){var D=[];for(var B=0,A=C.length;B<A;B++){D[B]=C[B];}return D;}return Array.prototype.slice.call(C);
}function $each(C,B,D){var A=$type(C);((A=="arguments"||A=="collection"||A=="array")?Array:Hash).each(C,B,D);}var Browser=new Hash({Engine:{name:"unknown",version:""},Platform:{name:(navigator.platform.match(/mac|win|linux/i)||["other"])[0].toLowerCase()},Features:{xpath:!!(document.evaluate),air:!!(window.runtime)},Plugins:{}});
if(window.opera){Browser.Engine={name:"presto",version:(document.getElementsByClassName)?950:925};}else{if(window.ActiveXObject){Browser.Engine={name:"trident",version:(window.XMLHttpRequest)?5:4};
}else{if(!navigator.taintEnabled){Browser.Engine={name:"webkit",version:(Browser.Features.xpath)?420:419};}else{if(document.getBoxObjectFor!=null){Browser.Engine={name:"gecko",version:(document.getElementsByClassName)?19:18};
}}}}Browser.Engine[Browser.Engine.name]=Browser.Engine[Browser.Engine.name+Browser.Engine.version]=true;if(window.orientation!=undefined){Browser.Platform.name="ipod";
}Browser.Platform[Browser.Platform.name]=true;Browser.Request=function(){return $try(function(){return new XMLHttpRequest();},function(){return new ActiveXObject("MSXML2.XMLHTTP");
});};Browser.Features.xhr=!!(Browser.Request());Browser.Plugins.Flash=(function(){var A=($try(function(){return navigator.plugins["Shockwave Flash"].description;
},function(){return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version");})||"0 r0").match(/\d+/g);return{version:parseInt(A[0]||0+"."+A[1]||0),build:parseInt(A[2]||0)};
})();function $exec(B){if(!B){return B;}if(window.execScript){window.execScript(B);}else{var A=document.createElement("script");A.setAttribute("type","text/javascript");
A.text=B;document.head.appendChild(A);document.head.removeChild(A);}return B;}Native.UID=1;var $uid=(Browser.Engine.trident)?function(A){return(A.uid||(A.uid=[Native.UID++]))[0];
}:function(A){return A.uid||(A.uid=Native.UID++);};var Window=new Native({name:"Window",legacy:(Browser.Engine.trident)?null:window.Window,initialize:function(A){$uid(A);
if(!A.Element){A.Element=$empty;if(Browser.Engine.webkit){A.document.createElement("iframe");}A.Element.prototype=(Browser.Engine.webkit)?window["[[DOMElement.prototype]]"]:{};
}return $extend(A,Window.Prototype);},afterImplement:function(B,A){window[B]=Window.Prototype[B]=A;}});Window.Prototype={$family:{name:"window"}};new Window(window);
var Document=new Native({name:"Document",legacy:(Browser.Engine.trident)?null:window.Document,initialize:function(A){$uid(A);A.head=A.getElementsByTagName("head")[0];
A.html=A.getElementsByTagName("html")[0];A.window=A.defaultView||A.parentWindow;if(Browser.Engine.trident4){$try(function(){A.execCommand("BackgroundImageCache",false,true);
});}return $extend(A,Document.Prototype);},afterImplement:function(B,A){document[B]=Document.Prototype[B]=A;}});Document.Prototype={$family:{name:"document"}};
new Document(document);Array.implement({every:function(C,D){for(var B=0,A=this.length;B<A;B++){if(!C.call(D,this[B],B,this)){return false;}}return true;
},filter:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){if(D.call(E,this[B],B,this)){C.push(this[B]);}}return C;},clean:function(){return this.filter($defined);
},indexOf:function(C,D){var A=this.length;for(var B=(D<0)?Math.max(0,A+D):D||0;B<A;B++){if(this[B]===C){return B;}}return -1;},map:function(D,E){var C=[];
for(var B=0,A=this.length;B<A;B++){C[B]=D.call(E,this[B],B,this);}return C;},some:function(C,D){for(var B=0,A=this.length;B<A;B++){if(C.call(D,this[B],B,this)){return true;
}}return false;},associate:function(C){var D={},B=Math.min(this.length,C.length);for(var A=0;A<B;A++){D[C[A]]=this[A];}return D;},link:function(C){var A={};
for(var E=0,B=this.length;E<B;E++){for(var D in C){if(C[D](this[E])){A[D]=this[E];delete C[D];break;}}}return A;},contains:function(A,B){return this.indexOf(A,B)!=-1;
},extend:function(C){for(var B=0,A=C.length;B<A;B++){this.push(C[B]);}return this;},getLast:function(){return(this.length)?this[this.length-1]:null;},getRandom:function(){return(this.length)?this[$random(0,this.length-1)]:null;
},include:function(A){if(!this.contains(A)){this.push(A);}return this;},combine:function(C){for(var B=0,A=C.length;B<A;B++){this.include(C[B]);}return this;
},erase:function(B){for(var A=this.length;A--;A){if(this[A]===B){this.splice(A,1);}}return this;},empty:function(){this.length=0;return this;},flatten:function(){var D=[];
for(var B=0,A=this.length;B<A;B++){var C=$type(this[B]);if(!C){continue;}D=D.concat((C=="array"||C=="collection"||C=="arguments")?Array.flatten(this[B]):this[B]);
}return D;},hexToRgb:function(B){if(this.length!=3){return null;}var A=this.map(function(C){if(C.length==1){C+=C;}return C.toInt(16);});return(B)?A:"rgb("+A+")";
},rgbToHex:function(D){if(this.length<3){return null;}if(this.length==4&&this[3]==0&&!D){return"transparent";}var B=[];for(var A=0;A<3;A++){var C=(this[A]-0).toString(16);
B.push((C.length==1)?"0"+C:C);}return(D)?B:"#"+B.join("");}});Function.implement({extend:function(A){for(var B in A){this[B]=A[B];}return this;},create:function(B){var A=this;
B=B||{};return function(D){var C=B.arguments;C=(C!=undefined)?$splat(C):Array.slice(arguments,(B.event)?1:0);if(B.event){C=[D||window.event].extend(C);
}var E=function(){return A.apply(B.bind||null,C);};if(B.delay){return setTimeout(E,B.delay);}if(B.periodical){return setInterval(E,B.periodical);}if(B.attempt){return $try(E);
}return E();};},pass:function(A,B){return this.create({arguments:A,bind:B});},attempt:function(A,B){return this.create({arguments:A,bind:B,attempt:true})();
},bind:function(B,A){return this.create({bind:B,arguments:A});},bindWithEvent:function(B,A){return this.create({bind:B,event:true,arguments:A});},delay:function(B,C,A){return this.create({delay:B,bind:C,arguments:A})();
},periodical:function(A,C,B){return this.create({periodical:A,bind:C,arguments:B})();},run:function(A,B){return this.apply(B,$splat(A));}});Number.implement({limit:function(B,A){return Math.min(A,Math.max(B,this));
},round:function(A){A=Math.pow(10,A||0);return Math.round(this*A)/A;},times:function(B,C){for(var A=0;A<this;A++){B.call(C,A,this);}},toFloat:function(){return parseFloat(this);
},toInt:function(A){return parseInt(this,A||10);}});Number.alias("times","each");(function(B){var A={};B.each(function(C){if(!Number[C]){A[C]=function(){return Math[C].apply(null,[this].concat($A(arguments)));
};}});Number.implement(A);})(["abs","acos","asin","atan","atan2","ceil","cos","exp","floor","log","max","min","pow","sin","sqrt","tan"]);String.implement({test:function(A,B){return((typeof A=="string")?new RegExp(A,B):A).test(this);
},contains:function(A,B){return(B)?(B+this+B).indexOf(B+A+B)>-1:this.indexOf(A)>-1;},trim:function(){return this.replace(/^\s+|\s+$/g,"");},clean:function(){return this.replace(/\s+/g," ").trim();
},camelCase:function(){return this.replace(/-\D/g,function(A){return A.charAt(1).toUpperCase();});},hyphenate:function(){return this.replace(/[A-Z]/g,function(A){return("-"+A.charAt(0).toLowerCase());
});},capitalize:function(){return this.replace(/\b[a-z]/g,function(A){return A.toUpperCase();});},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1");
},toInt:function(A){return parseInt(this,A||10);},toFloat:function(){return parseFloat(this);},hexToRgb:function(B){var A=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
return(A)?A.slice(1).hexToRgb(B):null;},rgbToHex:function(B){var A=this.match(/\d{1,3}/g);return(A)?A.rgbToHex(B):null;},stripScripts:function(B){var A="";
var C=this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi,function(){A+=arguments[1]+"\n";return"";});if(B===true){$exec(A);}else{if($type(B)=="function"){B(A,C);
}}return C;},substitute:function(A,B){return this.replace(B||(/\\?\{([^}]+)\}/g),function(D,C){if(D.charAt(0)=="\\"){return D.slice(1);}return(A[C]!=undefined)?A[C]:"";
});}});Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(B){for(var A in this){if(this.hasOwnProperty(A)&&this[A]===B){return A;}}return null;
},hasValue:function(A){return(Hash.keyOf(this,A)!==null);},extend:function(A){Hash.each(A,function(C,B){Hash.set(this,B,C);},this);return this;},combine:function(A){Hash.each(A,function(C,B){Hash.include(this,B,C);
},this);return this;},erase:function(A){if(this.hasOwnProperty(A)){delete this[A];}return this;},get:function(A){return(this.hasOwnProperty(A))?this[A]:null;
},set:function(A,B){if(!this[A]||this.hasOwnProperty(A)){this[A]=B;}return this;},empty:function(){Hash.each(this,function(B,A){delete this[A];},this);
return this;},include:function(B,C){var A=this[B];if(A==undefined){this[B]=C;}return this;},map:function(B,C){var A=new Hash;Hash.each(this,function(E,D){A.set(D,B.call(C,E,D,this));
},this);return A;},filter:function(B,C){var A=new Hash;Hash.each(this,function(E,D){if(B.call(C,E,D,this)){A.set(D,E);}},this);return A;},every:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&!B.call(C,this[A],A)){return false;
}}return true;},some:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&B.call(C,this[A],A)){return true;}}return false;},getKeys:function(){var A=[];
Hash.each(this,function(C,B){A.push(B);});return A;},getValues:function(){var A=[];Hash.each(this,function(B){A.push(B);});return A;},toQueryString:function(A){var B=[];
Hash.each(this,function(F,E){if(A){E=A+"["+E+"]";}var D;switch($type(F)){case"object":D=Hash.toQueryString(F,E);break;case"array":var C={};F.each(function(H,G){C[G]=H;
});D=Hash.toQueryString(C,E);break;default:D=E+"="+encodeURIComponent(F);}if(F!=undefined){B.push(D);}});return B.join("&");}});Hash.alias({keyOf:"indexOf",hasValue:"contains"});
var Event=new Native({name:"Event",initialize:function(A,F){F=F||window;var K=F.document;A=A||F.event;if(A.$extended){return A;}this.$extended=true;var J=A.type;
var G=A.target||A.srcElement;while(G&&G.nodeType==3){G=G.parentNode;}if(J.test(/key/)){var B=A.which||A.keyCode;var M=Event.Keys.keyOf(B);if(J=="keydown"){var D=B-111;
if(D>0&&D<13){M="f"+D;}}M=M||String.fromCharCode(B).toLowerCase();}else{if(J.match(/(click|mouse|menu)/i)){K=(!K.compatMode||K.compatMode=="CSS1Compat")?K.html:K.body;
var I={x:A.pageX||A.clientX+K.scrollLeft,y:A.pageY||A.clientY+K.scrollTop};var C={x:(A.pageX)?A.pageX-F.pageXOffset:A.clientX,y:(A.pageY)?A.pageY-F.pageYOffset:A.clientY};
if(J.match(/DOMMouseScroll|mousewheel/)){var H=(A.wheelDelta)?A.wheelDelta/120:-(A.detail||0)/3;}var E=(A.which==3)||(A.button==2);var L=null;if(J.match(/over|out/)){switch(J){case"mouseover":L=A.relatedTarget||A.fromElement;
break;case"mouseout":L=A.relatedTarget||A.toElement;}if(!(function(){while(L&&L.nodeType==3){L=L.parentNode;}return true;}).create({attempt:Browser.Engine.gecko})()){L=false;
}}}}return $extend(this,{event:A,type:J,page:I,client:C,rightClick:E,wheel:H,relatedTarget:L,target:G,code:B,key:M,shift:A.shiftKey,control:A.ctrlKey,alt:A.altKey,meta:A.metaKey});
}});Event.Keys=new Hash({enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,"delete":46});Event.implement({stop:function(){return this.stopPropagation().preventDefault();
},stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation();}else{this.event.cancelBubble=true;}return this;},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault();
}else{this.event.returnValue=false;}return this;}});var Class=new Native({name:"Class",initialize:function(B){B=B||{};var A=function(E){for(var D in this){this[D]=$unlink(this[D]);
}for(var F in Class.Mutators){if(!this[F]){continue;}Class.Mutators[F](this,this[F]);delete this[F];}this.constructor=A;if(E===$empty){return this;}var C=(this.initialize)?this.initialize.apply(this,arguments):this;
if(this.options&&this.options.initialize){this.options.initialize.call(this);}return C;};$extend(A,this);A.constructor=Class;A.prototype=B;return A;}});
Class.implement({implement:function(){Class.Mutators.Implements(this.prototype,Array.slice(arguments));return this;}});Class.Mutators={Implements:function(A,B){$splat(B).each(function(C){$extend(A,($type(C)=="class")?new C($empty):C);
});},Extends:function(self,klass){var instance=new klass($empty);delete instance.parent;delete instance.parentOf;for(var key in instance){var current=self[key],previous=instance[key];
if(current==undefined){self[key]=previous;continue;}var ctype=$type(current),ptype=$type(previous);if(ctype!=ptype){continue;}switch(ctype){case"function":if(!arguments.callee.caller){self[key]=eval("("+String(current).replace(/\bthis\.parent\(\s*(\))?/g,function(full,close){return"arguments.callee._parent_.call(this"+(close||", ");
})+")");}self[key]._parent_=previous;break;case"object":self[key]=$merge(previous,current);}}self.parent=function(){return arguments.callee.caller._parent_.apply(this,arguments);
};self.parentOf=function(descendant){return descendant._parent_.apply(this,Array.slice(arguments,1));};}};var Chain=new Class({chain:function(){this.$chain=(this.$chain||[]).extend(arguments);
return this;},callChain:function(){return(this.$chain&&this.$chain.length)?this.$chain.shift().apply(this,arguments):false;},clearChain:function(){if(this.$chain){this.$chain.empty();
}return this;}});var Events=new Class({addEvent:function(C,B,A){C=Events.removeOn(C);if(B!=$empty){this.$events=this.$events||{};this.$events[C]=this.$events[C]||[];
this.$events[C].include(B);if(A){B.internal=true;}}return this;},addEvents:function(A){for(var B in A){this.addEvent(B,A[B]);}return this;},fireEvent:function(C,B,A){C=Events.removeOn(C);
if(!this.$events||!this.$events[C]){return this;}this.$events[C].each(function(D){D.create({bind:this,delay:A,"arguments":B})();},this);return this;},removeEvent:function(B,A){B=Events.removeOn(B);
if(!this.$events||!this.$events[B]){return this;}if(!A.internal){this.$events[B].erase(A);}return this;},removeEvents:function(C){for(var D in this.$events){if(C&&C!=D){continue;
}var B=this.$events[D];for(var A=B.length;A--;A){this.removeEvent(D,B[A]);}}return this;}});Events.removeOn=function(A){return A.replace(/^on([A-Z])/,function(B,C){return C.toLowerCase();
});};var Options=new Class({setOptions:function(){this.options=$merge.run([this.options].extend(arguments));if(!this.addEvent){return this;}for(var A in this.options){if($type(this.options[A])!="function"||!(/^on[A-Z]/).test(A)){continue;
}this.addEvent(A,this.options[A]);delete this.options[A];}return this;}});Document.implement({newElement:function(A,B){if(Browser.Engine.trident&&B){["name","type","checked"].each(function(C){if(!B[C]){return ;
}A+=" "+C+'="'+B[C]+'"';if(C!="checked"){delete B[C];}});A="<"+A+">";}return $.element(this.createElement(A)).set(B);},newTextNode:function(A){return this.createTextNode(A);
},getDocument:function(){return this;},getWindow:function(){return this.defaultView||this.parentWindow;},purge:function(){var C=this.getElementsByTagName("*");
for(var B=0,A=C.length;B<A;B++){Browser.freeMem(C[B]);}}});var Element=new Native({name:"Element",legacy:window.Element,initialize:function(A,B){var C=Element.Constructors.get(A);
if(C){return C(B);}if(typeof A=="string"){return document.newElement(A,B);}return $(A).set(B);},afterImplement:function(A,B){if(!Array[A]){Elements.implement(A,Elements.multi(A));
}Element.Prototype[A]=B;}});Element.Prototype={$family:{name:"element"}};Element.Constructors=new Hash;var IFrame=new Native({name:"IFrame",generics:false,initialize:function(){var E=Array.link(arguments,{properties:Object.type,iframe:$defined});
var C=E.properties||{};var B=$(E.iframe)||false;var D=C.onload||$empty;delete C.onload;C.id=C.name=$pick(C.id,C.name,B.id,B.name,"IFrame_"+$time());B=new Element(B||"iframe",C);
var A=function(){var F=$try(function(){return B.contentWindow.location.host;});if(F&&F==window.location.host){var H=new Window(B.contentWindow);var G=new Document(B.contentWindow.document);
$extend(H.Element.prototype,Element.Prototype);}D.call(B.contentWindow,B.contentWindow.document);};(!window.frames[C.id])?B.addListener("load",A):A();return B;
}});var Elements=new Native({initialize:function(F,B){B=$extend({ddup:true,cash:true},B);F=F||[];if(B.ddup||B.cash){var G={},E=[];for(var C=0,A=F.length;
C<A;C++){var D=$.element(F[C],!B.cash);if(B.ddup){if(G[D.uid]){continue;}G[D.uid]=true;}E.push(D);}F=E;}return(B.cash)?$extend(F,this):F;}});Elements.implement({filter:function(A,B){if(!A){return this;
}return new Elements(Array.filter(this,(typeof A=="string")?function(C){return C.match(A);}:A,B));}});Elements.multi=function(A){return function(){var B=[];
var F=true;for(var D=0,C=this.length;D<C;D++){var E=this[D][A].apply(this[D],arguments);B.push(E);if(F){F=($type(E)=="element");}}return(F)?new Elements(B):B;
};};Window.implement({$:function(B,C){if(B&&B.$family&&B.uid){return B;}var A=$type(B);return($[A])?$[A](B,C,this.document):null;},$$:function(A){if(arguments.length==1&&typeof A=="string"){return this.document.getElements(A);
}var F=[];var C=Array.flatten(arguments);for(var D=0,B=C.length;D<B;D++){var E=C[D];switch($type(E)){case"element":E=[E];break;case"string":E=this.document.getElements(E,true);
break;default:E=false;}if(E){F.extend(E);}}return new Elements(F);},getDocument:function(){return this.document;},getWindow:function(){return this;}});
$.string=function(C,B,A){C=A.getElementById(C);return(C)?$.element(C,B):null;};$.element=function(A,D){$uid(A);if(!D&&!A.$family&&!(/^object|embed$/i).test(A.tagName)){var B=Element.Prototype;
for(var C in B){A[C]=B[C];}}return A;};$.object=function(B,C,A){if(B.toElement){return $.element(B.toElement(A),C);}return null;};$.textnode=$.whitespace=$.window=$.document=$arguments(0);
Native.implement([Element,Document],{getElement:function(A,B){return $(this.getElements(A,true)[0]||null,B);},getElements:function(A,D){A=A.split(",");
var C=[];var B=(A.length>1);A.each(function(E){var F=this.getElementsByTagName(E.trim());(B)?C.extend(F):C=F;},this);return new Elements(C,{ddup:B,cash:!D});
}});Element.Storage={get:function(A){return(this[A]||(this[A]={}));}};Element.Inserters=new Hash({before:function(B,A){if(A.parentNode){A.parentNode.insertBefore(B,A);
}},after:function(B,A){if(!A.parentNode){return ;}var C=A.nextSibling;(C)?A.parentNode.insertBefore(B,C):A.parentNode.appendChild(B);},bottom:function(B,A){A.appendChild(B);
},top:function(B,A){var C=A.firstChild;(C)?A.insertBefore(B,C):A.appendChild(B);}});Element.Inserters.inside=Element.Inserters.bottom;Element.Inserters.each(function(C,B){var A=B.capitalize();
Element.implement("inject"+A,function(D){C(this,$(D,true));return this;});Element.implement("grab"+A,function(D){C($(D,true),this);return this;});});Element.implement({getDocument:function(){return this.ownerDocument;
},getWindow:function(){return this.ownerDocument.getWindow();},getElementById:function(D,C){var B=this.ownerDocument.getElementById(D);if(!B){return null;
}for(var A=B.parentNode;A!=this;A=A.parentNode){if(!A){return null;}}return $.element(B,C);},set:function(D,B){switch($type(D)){case"object":for(var C in D){this.set(C,D[C]);
}break;case"string":var A=Element.Properties.get(D);(A&&A.set)?A.set.apply(this,Array.slice(arguments,1)):this.setProperty(D,B);}return this;},get:function(B){var A=Element.Properties.get(B);
return(A&&A.get)?A.get.apply(this,Array.slice(arguments,1)):this.getProperty(B);},erase:function(B){var A=Element.Properties.get(B);(A&&A.erase)?A.erase.apply(this,Array.slice(arguments,1)):this.removeProperty(B);
return this;},match:function(A){return(!A||Element.get(this,"tag")==A);},inject:function(B,A){Element.Inserters.get(A||"bottom")(this,$(B,true));return this;
},wraps:function(B,A){B=$(B,true);return this.replaces(B).grab(B,A);},grab:function(B,A){Element.Inserters.get(A||"bottom")($(B,true),this);return this;
},appendText:function(B,A){return this.grab(this.getDocument().newTextNode(B),A);},adopt:function(){Array.flatten(arguments).each(function(A){A=$(A,true);
if(A){this.appendChild(A);}},this);return this;},dispose:function(){return(this.parentNode)?this.parentNode.removeChild(this):this;},clone:function(D,C){switch($type(this)){case"element":var H={};
for(var G=0,E=this.attributes.length;G<E;G++){var B=this.attributes[G],L=B.nodeName.toLowerCase();if(Browser.Engine.trident&&(/input/i).test(this.tagName)&&(/width|height/).test(L)){continue;
}var K=(L=="style"&&this.style)?this.style.cssText:B.nodeValue;if(!$chk(K)||L=="uid"||(L=="id"&&!C)){continue;}if(K!="inherit"&&["string","number"].contains($type(K))){H[L]=K;
}}var J=new Element(this.nodeName.toLowerCase(),H);if(D!==false){for(var I=0,F=this.childNodes.length;I<F;I++){var A=Element.clone(this.childNodes[I],true,C);
if(A){J.grab(A);}}}return J;case"textnode":return document.newTextNode(this.nodeValue);}return null;},replaces:function(A){A=$(A,true);A.parentNode.replaceChild(this,A);
return this;},hasClass:function(A){return this.className.contains(A," ");},addClass:function(A){if(!this.hasClass(A)){this.className=(this.className+" "+A).clean();
}return this;},removeClass:function(A){this.className=this.className.replace(new RegExp("(^|\\s)"+A+"(?:\\s|$)"),"$1").clean();return this;},toggleClass:function(A){return this.hasClass(A)?this.removeClass(A):this.addClass(A);
},getComputedStyle:function(B){if(this.currentStyle){return this.currentStyle[B.camelCase()];}var A=this.getWindow().getComputedStyle(this,null);return(A)?A.getPropertyValue([B.hyphenate()]):null;
},empty:function(){$A(this.childNodes).each(function(A){Browser.freeMem(A);Element.empty(A);Element.dispose(A);},this);return this;},destroy:function(){Browser.freeMem(this.empty().dispose());
return null;},getSelected:function(){return new Elements($A(this.options).filter(function(A){return A.selected;}));},toQueryString:function(){var A=[];
this.getElements("input, select, textarea").each(function(B){if(!B.name||B.disabled){return ;}var C=(B.tagName.toLowerCase()=="select")?Element.getSelected(B).map(function(D){return D.value;
}):((B.type=="radio"||B.type=="checkbox")&&!B.checked)?null:B.value;$splat(C).each(function(D){if(D){A.push(B.name+"="+encodeURIComponent(D));}});});return A.join("&");
},getProperty:function(C){var B=Element.Attributes,A=B.Props[C];var D=(A)?this[A]:this.getAttribute(C,2);return(B.Bools[C])?!!D:(A)?D:D||null;},getProperties:function(){var A=$A(arguments);
return A.map(function(B){return this.getProperty(B);},this).associate(A);},setProperty:function(D,E){var C=Element.Attributes,B=C.Props[D],A=$defined(E);
if(B&&C.Bools[D]){E=(E||!A)?true:false;}else{if(!A){return this.removeProperty(D);}}(B)?this[B]=E:this.setAttribute(D,E);return this;},setProperties:function(A){for(var B in A){this.setProperty(B,A[B]);
}return this;},removeProperty:function(D){var C=Element.Attributes,B=C.Props[D],A=(B&&C.Bools[D]);(B)?this[B]=(A)?false:"":this.removeAttribute(D);return this;
},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this;}});(function(){var A=function(D,B,I,C,F,H){var E=D[I||B];var G=[];
while(E){if(E.nodeType==1&&(!C||Element.match(E,C))){G.push(E);if(!F){break;}}E=E[B];}return(F)?new Elements(G,{ddup:false,cash:!H}):$(G[0],H);};Element.implement({getPrevious:function(B,C){return A(this,"previousSibling",null,B,false,C);
},getAllPrevious:function(B,C){return A(this,"previousSibling",null,B,true,C);},getNext:function(B,C){return A(this,"nextSibling",null,B,false,C);},getAllNext:function(B,C){return A(this,"nextSibling",null,B,true,C);
},getFirst:function(B,C){return A(this,"nextSibling","firstChild",B,false,C);},getLast:function(B,C){return A(this,"previousSibling","lastChild",B,false,C);
},getParent:function(B,C){return A(this,"parentNode",null,B,false,C);},getParents:function(B,C){return A(this,"parentNode",null,B,true,C);},getChildren:function(B,C){return A(this,"nextSibling","firstChild",B,true,C);
},hasChild:function(B){B=$(B,true);return(!!B&&$A(this.getElementsByTagName(B.tagName)).contains(B));}});})();Element.Properties=new Hash;Element.Properties.style={set:function(A){this.style.cssText=A;
},get:function(){return this.style.cssText;},erase:function(){this.style.cssText="";}};Element.Properties.tag={get:function(){return this.tagName.toLowerCase();
}};Element.Properties.href={get:function(){return(!this.href)?null:this.href.replace(new RegExp("^"+document.location.protocol+"//"+document.location.host),"");
}};Element.Properties.html={set:function(){return this.innerHTML=Array.flatten(arguments).join("");}};Native.implement([Element,Window,Document],{addListener:function(B,A){if(this.addEventListener){this.addEventListener(B,A,false);
}else{this.attachEvent("on"+B,A);}return this;},removeListener:function(B,A){if(this.removeEventListener){this.removeEventListener(B,A,false);}else{this.detachEvent("on"+B,A);
}return this;},retrieve:function(B,A){var D=Element.Storage.get(this.uid);var C=D[B];if($defined(A)&&!$defined(C)){C=D[B]=A;}return $pick(C);},store:function(B,A){var C=Element.Storage.get(this.uid);
C[B]=A;return this;},eliminate:function(A){var B=Element.Storage.get(this.uid);delete B[A];return this;}});Element.Attributes=new Hash({Props:{html:"innerHTML","class":"className","for":"htmlFor",text:(Browser.Engine.trident)?"innerText":"textContent"},Bools:["compact","nowrap","ismap","declare","noshade","checked","disabled","readonly","multiple","selected","noresize","defer"],Camels:["value","accessKey","cellPadding","cellSpacing","colSpan","frameBorder","maxLength","readOnly","rowSpan","tabIndex","useMap"]});
Browser.freeMem=function(A){if(!A){return ;}if(Browser.Engine.trident&&(/object/i).test(A.tagName)){for(var B in A){if(typeof A[B]=="function"){A[B]=$empty;
}}Element.dispose(A);}if(A.uid&&A.removeEvents){A.removeEvents();}};(function(B){var C=B.Bools,A=B.Camels;B.Bools=C=C.associate(C);Hash.extend(Hash.combine(B.Props,C),A.associate(A.map(function(D){return D.toLowerCase();
})));B.erase("Camels");})(Element.Attributes);window.addListener("unload",function(){window.removeListener("unload",arguments.callee);document.purge();
if(Browser.Engine.trident){CollectGarbage();}});Element.Properties.events={set:function(A){this.addEvents(A);}};Native.implement([Element,Window,Document],{addEvent:function(E,G){var H=this.retrieve("events",{});
H[E]=H[E]||{keys:[],values:[]};if(H[E].keys.contains(G)){return this;}H[E].keys.push(G);var F=E,A=Element.Events.get(E),C=G,I=this;if(A){if(A.onAdd){A.onAdd.call(this,G);
}if(A.condition){C=function(J){if(A.condition.call(this,J)){return G.call(this,J);}return false;};}F=A.base||F;}var D=function(){return G.call(I);};var B=Element.NativeEvents[F]||0;
if(B){if(B==2){D=function(J){J=new Event(J,I.getWindow());if(C.call(I,J)===false){J.stop();}};}this.addListener(F,D);}H[E].values.push(D);return this;},removeEvent:function(D,C){var B=this.retrieve("events");
if(!B||!B[D]){return this;}var G=B[D].keys.indexOf(C);if(G==-1){return this;}var A=B[D].keys.splice(G,1)[0];var F=B[D].values.splice(G,1)[0];var E=Element.Events.get(D);
if(E){if(E.onRemove){E.onRemove.call(this,C);}D=E.base||D;}return(Element.NativeEvents[D])?this.removeListener(D,F):this;},addEvents:function(A){for(var B in A){this.addEvent(B,A[B]);
}return this;},removeEvents:function(B){var A=this.retrieve("events");if(!A){return this;}if(!B){for(var C in A){this.removeEvents(C);}A=null;}else{if(A[B]){while(A[B].keys[0]){this.removeEvent(B,A[B].keys[0]);
}A[B]=null;}}return this;},fireEvent:function(D,B,A){var C=this.retrieve("events");if(!C||!C[D]){return this;}C[D].keys.each(function(E){E.create({bind:this,delay:A,"arguments":B})();
},this);return this;},cloneEvents:function(D,A){D=$(D);var C=D.retrieve("events");if(!C){return this;}if(!A){for(var B in C){this.cloneEvents(D,B);}}else{if(C[A]){C[A].keys.each(function(E){this.addEvent(A,E);
},this);}}return this;}});Element.NativeEvents={click:2,dblclick:2,mouseup:2,mousedown:2,contextmenu:2,mousewheel:2,DOMMouseScroll:2,mouseover:2,mouseout:2,mousemove:2,selectstart:2,selectend:2,keydown:2,keypress:2,keyup:2,focus:2,blur:2,change:2,reset:2,select:2,submit:2,load:1,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1};
(function(){var A=function(B){var C=B.relatedTarget;if(C==undefined){return true;}if(C===false){return false;}return($type(this)!="document"&&C!=this&&C.prefix!="xul"&&!this.hasChild(C));
};Element.Events=new Hash({mouseenter:{base:"mouseover",condition:A},mouseleave:{base:"mouseout",condition:A},mousewheel:{base:(Browser.Engine.gecko)?"DOMMouseScroll":"mousewheel"}});
})();Element.Properties.styles={set:function(A){this.setStyles(A);}};Element.Properties.opacity={set:function(A,B){if(!B){if(A==0){if(this.style.visibility!="hidden"){this.style.visibility="hidden";
}}else{if(this.style.visibility!="visible"){this.style.visibility="visible";}}}if(!this.currentStyle||!this.currentStyle.hasLayout){this.style.zoom=1;}if(Browser.Engine.trident){this.style.filter=(A==1)?"":"alpha(opacity="+A*100+")";
}this.style.opacity=A;this.store("opacity",A);},get:function(){return this.retrieve("opacity",1);}};Element.implement({setOpacity:function(A){return this.set("opacity",A,true);
},getOpacity:function(){return this.get("opacity");},setStyle:function(B,A){switch(B){case"opacity":return this.set("opacity",parseFloat(A));case"float":B=(Browser.Engine.trident)?"styleFloat":"cssFloat";
}B=B.camelCase();if($type(A)!="string"){var C=(Element.Styles.get(B)||"@").split(" ");A=$splat(A).map(function(E,D){if(!C[D]){return"";}return($type(E)=="number")?C[D].replace("@",Math.round(E)):E;
}).join(" ");}else{if(A==String(Number(A))){A=Math.round(A);}}this.style[B]=A;return this;},getStyle:function(G){switch(G){case"opacity":return this.get("opacity");
case"float":G=(Browser.Engine.trident)?"styleFloat":"cssFloat";}G=G.camelCase();var A=this.style[G];if(!$chk(A)){A=[];for(var F in Element.ShortStyles){if(G!=F){continue;
}for(var E in Element.ShortStyles[F]){A.push(this.getStyle(E));}return A.join(" ");}A=this.getComputedStyle(G);}if(A){A=String(A);var C=A.match(/rgba?\([\d\s,]+\)/);
if(C){A=A.replace(C[0],C[0].rgbToHex());}}if(Browser.Engine.presto||(Browser.Engine.trident&&!$chk(parseInt(A)))){if(G.test(/^(height|width)$/)){var B=(G=="width")?["left","right"]:["top","bottom"],D=0;
B.each(function(H){D+=this.getStyle("border-"+H+"-width").toInt()+this.getStyle("padding-"+H).toInt();},this);return this["offset"+G.capitalize()]-D+"px";
}if(Browser.Engine.presto&&String(A).test("px")){return A;}if(G.test(/(border(.+)Width|margin|padding)/)){return"0px";}}return A;},setStyles:function(B){for(var A in B){this.setStyle(A,B[A]);
}return this;},getStyles:function(){var A={};Array.each(arguments,function(B){A[B]=this.getStyle(B);},this);return A;}});Element.Styles=new Hash({left:"@px",top:"@px",bottom:"@px",right:"@px",width:"@px",height:"@px",maxWidth:"@px",maxHeight:"@px",minWidth:"@px",minHeight:"@px",backgroundColor:"rgb(@, @, @)",backgroundPosition:"@px @px",color:"rgb(@, @, @)",fontSize:"@px",letterSpacing:"@px",lineHeight:"@px",clip:"rect(@px @px @px @px)",margin:"@px @px @px @px",padding:"@px @px @px @px",border:"@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)",borderWidth:"@px @px @px @px",borderStyle:"@ @ @ @",borderColor:"rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)",zIndex:"@",zoom:"@",fontWeight:"@",textIndent:"@px",opacity:"@"});
Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};["Top","Right","Bottom","Left"].each(function(G){var F=Element.ShortStyles;
var B=Element.Styles;["margin","padding"].each(function(H){var I=H+G;F[H][I]=B[I]="@px";});var E="border"+G;F.border[E]=B[E]="@px @ rgb(@, @, @)";var D=E+"Width",A=E+"Style",C=E+"Color";
F[E]={};F.borderWidth[D]=F[E][D]=B[D]="@px";F.borderStyle[A]=F[E][A]=B[A]="@";F.borderColor[C]=F[E][C]=B[C]="rgb(@, @, @)";});(function(){Element.implement({scrollTo:function(H,I){if(B(this)){this.getWindow().scrollTo(H,I);
}else{this.scrollLeft=H;this.scrollTop=I;}return this;},getSize:function(){if(B(this)){return this.getWindow().getSize();}return{x:this.offsetWidth,y:this.offsetHeight};
},getScrollSize:function(){if(B(this)){return this.getWindow().getScrollSize();}return{x:this.scrollWidth,y:this.scrollHeight};},getScroll:function(){if(B(this)){return this.getWindow().getScroll();
}return{x:this.scrollLeft,y:this.scrollTop};},getScrolls:function(){var I=this,H={x:0,y:0};while(I&&!B(I)){H.x+=I.scrollLeft;H.y+=I.scrollTop;I=I.parentNode;
}return H;},getOffsetParent:function(){var H=this;if(B(H)){return null;}if(!Browser.Engine.trident){return H.offsetParent;}while((H=H.parentNode)&&!B(H)){if(D(H,"position")!="static"){return H;
}}return null;},getOffsets:function(){var I=this,H={x:0,y:0};if(B(this)){return H;}while(I&&!B(I)){H.x+=I.offsetLeft;H.y+=I.offsetTop;if(Browser.Engine.gecko){if(!F(I)){H.x+=C(I);
H.y+=G(I);}var J=I.parentNode;if(J&&D(J,"overflow")!="visible"){H.x+=C(J);H.y+=G(J);}}else{if(I!=this&&(Browser.Engine.trident||Browser.Engine.webkit)){H.x+=C(I);
H.y+=G(I);}}I=I.offsetParent;if(Browser.Engine.trident){while(I&&!I.currentStyle.hasLayout){I=I.offsetParent;}}}if(Browser.Engine.gecko&&!F(this)){H.x-=C(this);
H.y-=G(this);}return H;},getPosition:function(K){if(B(this)){return{x:0,y:0};}var L=this.getOffsets(),I=this.getScrolls();var H={x:L.x-I.x,y:L.y-I.y};var J=(K&&(K=$(K)))?K.getPosition():{x:0,y:0};
return{x:H.x-J.x,y:H.y-J.y};},getCoordinates:function(J){if(B(this)){return this.getWindow().getCoordinates();}var H=this.getPosition(J),I=this.getSize();
var K={left:H.x,top:H.y,width:I.x,height:I.y};K.right=K.left+K.width;K.bottom=K.top+K.height;return K;},computePosition:function(H){return{left:H.x-E(this,"margin-left"),top:H.y-E(this,"margin-top")};
},position:function(H){return this.setStyles(this.computePosition(H));}});Native.implement([Document,Window],{getSize:function(){var I=this.getWindow();
if(Browser.Engine.presto||Browser.Engine.webkit){return{x:I.innerWidth,y:I.innerHeight};}var H=A(this);return{x:H.clientWidth,y:H.clientHeight};},getScroll:function(){var I=this.getWindow();
var H=A(this);return{x:I.pageXOffset||H.scrollLeft,y:I.pageYOffset||H.scrollTop};},getScrollSize:function(){var I=A(this);var H=this.getSize();return{x:Math.max(I.scrollWidth,H.x),y:Math.max(I.scrollHeight,H.y)};
},getPosition:function(){return{x:0,y:0};},getCoordinates:function(){var H=this.getSize();return{top:0,left:0,bottom:H.y,right:H.x,height:H.y,width:H.x};
}});var D=Element.getComputedStyle;function E(H,I){return D(H,I).toInt()||0;}function F(H){return D(H,"-moz-box-sizing")=="border-box";}function G(H){return E(H,"border-top-width");
}function C(H){return E(H,"border-left-width");}function B(H){return(/^(?:body|html)$/i).test(H.tagName);}function A(H){var I=H.getDocument();return(!I.compatMode||I.compatMode=="CSS1Compat")?I.html:I.body;
}})();Native.implement([Window,Document,Element],{getHeight:function(){return this.getSize().y;},getWidth:function(){return this.getSize().x;},getScrollTop:function(){return this.getScroll().y;
},getScrollLeft:function(){return this.getScroll().x;},getScrollHeight:function(){return this.getScrollSize().y;},getScrollWidth:function(){return this.getScrollSize().x;
},getTop:function(){return this.getPosition().y;},getLeft:function(){return this.getPosition().x;}});Native.implement([Document,Element],{getElements:function(H,G){H=H.split(",");
var C,E={};for(var D=0,B=H.length;D<B;D++){var A=H[D],F=Selectors.Utils.search(this,A,E);if(D!=0&&F.item){F=$A(F);}C=(D==0)?F:(C.item)?$A(C).concat(F):C.concat(F);
}return new Elements(C,{ddup:(H.length>1),cash:!G});}});Element.implement({match:function(B){if(!B){return true;}var D=Selectors.Utils.parseTagAndID(B);
var A=D[0],E=D[1];if(!Selectors.Filters.byID(this,E)||!Selectors.Filters.byTag(this,A)){return false;}var C=Selectors.Utils.parseSelector(B);return(C)?Selectors.Utils.filter(this,C,{}):true;
}});var Selectors={Cache:{nth:{},parsed:{}}};Selectors.RegExps={id:(/#([\w-]+)/),tag:(/^(\w+|\*)/),quick:(/^(\w+|\*)$/),splitter:(/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),combined:(/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)["']?(.*?)["']?)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)};
Selectors.Utils={chk:function(B,C){if(!C){return true;}var A=$uid(B);if(!C[A]){return C[A]=true;}return false;},parseNthArgument:function(F){if(Selectors.Cache.nth[F]){return Selectors.Cache.nth[F];
}var C=F.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);if(!C){return false;}var E=parseInt(C[1]);var B=(E||E===0)?E:1;var D=C[2]||false;var A=parseInt(C[3])||0;
if(B!=0){A--;while(A<1){A+=B;}while(A>=B){A-=B;}}else{B=A;D="index";}switch(D){case"n":C={a:B,b:A,special:"n"};break;case"odd":C={a:2,b:0,special:"n"};
break;case"even":C={a:2,b:1,special:"n"};break;case"first":C={a:0,special:"index"};break;case"last":C={special:"last-child"};break;case"only":C={special:"only-child"};
break;default:C={a:(B-1),special:"index"};}return Selectors.Cache.nth[F]=C;},parseSelector:function(E){if(Selectors.Cache.parsed[E]){return Selectors.Cache.parsed[E];
}var D,H={classes:[],pseudos:[],attributes:[]};while((D=Selectors.RegExps.combined.exec(E))){var I=D[1],G=D[2],F=D[3],B=D[4],C=D[5],J=D[6];if(I){H.classes.push(I);
}else{if(C){var A=Selectors.Pseudo.get(C);if(A){H.pseudos.push({parser:A,argument:J});}else{H.attributes.push({name:C,operator:"=",value:J});}}else{if(G){H.attributes.push({name:G,operator:F,value:B});
}}}}if(!H.classes.length){delete H.classes;}if(!H.attributes.length){delete H.attributes;}if(!H.pseudos.length){delete H.pseudos;}if(!H.classes&&!H.attributes&&!H.pseudos){H=null;
}return Selectors.Cache.parsed[E]=H;},parseTagAndID:function(B){var A=B.match(Selectors.RegExps.tag);var C=B.match(Selectors.RegExps.id);return[(A)?A[1]:"*",(C)?C[1]:false];
},filter:function(F,C,E){var D;if(C.classes){for(D=C.classes.length;D--;D){var G=C.classes[D];if(!Selectors.Filters.byClass(F,G)){return false;}}}if(C.attributes){for(D=C.attributes.length;
D--;D){var B=C.attributes[D];if(!Selectors.Filters.byAttribute(F,B.name,B.operator,B.value)){return false;}}}if(C.pseudos){for(D=C.pseudos.length;D--;D){var A=C.pseudos[D];
if(!Selectors.Filters.byPseudo(F,A.parser,A.argument,E)){return false;}}}return true;},getByTagAndID:function(B,A,D){if(D){var C=(B.getElementById)?B.getElementById(D,true):Element.getElementById(B,D,true);
return(C&&Selectors.Filters.byTag(C,A))?[C]:[];}else{return B.getElementsByTagName(A);}},search:function(J,I,O){var B=[];var C=I.trim().replace(Selectors.RegExps.splitter,function(Z,Y,X){B.push(Y);
return":)"+X;}).split(":)");var K,F,E,V;for(var U=0,Q=C.length;U<Q;U++){var T=C[U];if(U==0&&Selectors.RegExps.quick.test(T)){K=J.getElementsByTagName(T);
continue;}var A=B[U-1];var L=Selectors.Utils.parseTagAndID(T);var W=L[0],M=L[1];if(U==0){K=Selectors.Utils.getByTagAndID(J,W,M);}else{var D={},H=[];for(var S=0,R=K.length;
S<R;S++){H=Selectors.Getters[A](H,K[S],W,M,D);}K=H;}var G=Selectors.Utils.parseSelector(T);if(G){E=[];for(var P=0,N=K.length;P<N;P++){V=K[P];if(Selectors.Utils.filter(V,G,O)){E.push(V);
}}K=E;}}return K;}};Selectors.Getters={" ":function(H,G,I,A,E){var D=Selectors.Utils.getByTagAndID(G,I,A);for(var C=0,B=D.length;C<B;C++){var F=D[C];if(Selectors.Utils.chk(F,E)){H.push(F);
}}return H;},">":function(H,G,I,A,F){var C=Selectors.Utils.getByTagAndID(G,I,A);for(var E=0,D=C.length;E<D;E++){var B=C[E];if(B.parentNode==G&&Selectors.Utils.chk(B,F)){H.push(B);
}}return H;},"+":function(C,B,A,E,D){while((B=B.nextSibling)){if(B.nodeType==1){if(Selectors.Utils.chk(B,D)&&Selectors.Filters.byTag(B,A)&&Selectors.Filters.byID(B,E)){C.push(B);
}break;}}return C;},"~":function(C,B,A,E,D){while((B=B.nextSibling)){if(B.nodeType==1){if(!Selectors.Utils.chk(B,D)){break;}if(Selectors.Filters.byTag(B,A)&&Selectors.Filters.byID(B,E)){C.push(B);
}}}return C;}};Selectors.Filters={byTag:function(B,A){return(A=="*"||(B.tagName&&B.tagName.toLowerCase()==A));},byID:function(A,B){return(!B||(A.id&&A.id==B));
},byClass:function(B,A){return(B.className&&B.className.contains(A," "));},byPseudo:function(A,D,C,B){return D.call(A,C,B);},byAttribute:function(C,D,B,E){var A=Element.prototype.getProperty.call(C,D);
if(!A){return false;}if(!B||E==undefined){return true;}switch(B){case"=":return(A==E);case"*=":return(A.contains(E));case"^=":return(A.substr(0,E.length)==E);
case"$=":return(A.substr(A.length-E.length)==E);case"!=":return(A!=E);case"~=":return A.contains(E," ");case"|=":return A.contains(E,"-");}return false;
}};Selectors.Pseudo=new Hash({empty:function(){return !(this.innerText||this.textContent||"").length;},not:function(A){return !Element.match(this,A);},contains:function(A){return(this.innerText||this.textContent||"").contains(A);
},"first-child":function(){return Selectors.Pseudo.index.call(this,0);},"last-child":function(){var A=this;while((A=A.nextSibling)){if(A.nodeType==1){return false;
}}return true;},"only-child":function(){var B=this;while((B=B.previousSibling)){if(B.nodeType==1){return false;}}var A=this;while((A=A.nextSibling)){if(A.nodeType==1){return false;
}}return true;},"nth-child":function(G,E){G=(G==undefined)?"n":G;var C=Selectors.Utils.parseNthArgument(G);if(C.special!="n"){return Selectors.Pseudo[C.special].call(this,C.a,E);
}var F=0;E.positions=E.positions||{};var D=$uid(this);if(!E.positions[D]){var B=this;while((B=B.previousSibling)){if(B.nodeType!=1){continue;}F++;var A=E.positions[$uid(B)];
if(A!=undefined){F=A+F;break;}}E.positions[D]=F;}return(E.positions[D]%C.a==C.b);},index:function(A){var B=this,C=0;while((B=B.previousSibling)){if(B.nodeType==1&&++C>A){return false;
}}return(C==A);},even:function(B,A){return Selectors.Pseudo["nth-child"].call(this,"2n+1",A);},odd:function(B,A){return Selectors.Pseudo["nth-child"].call(this,"2n",A);
}});Element.Events.domready={onAdd:function(A){if(Browser.loaded){A.call(this);}}};(function(){var B=function(){if(Browser.loaded){return ;}Browser.loaded=true;
window.fireEvent("domready");document.fireEvent("domready");};switch(Browser.Engine.name){case"webkit":(function(){(["loaded","complete"].contains(document.readyState))?B():arguments.callee.delay(50);
})();break;case"trident":var A=document.createElement("div");(function(){($try(function(){A.doScroll("left");return $(A).inject(document.body).set("html","temp").dispose();
}))?B():arguments.callee.delay(50);})();break;default:window.addEvent("load",B);document.addEvent("DOMContentLoaded",B);}})();var Fx=new Class({Implements:[Chain,Events,Options],options:{fps:50,unit:false,duration:500,link:"ignore",transition:function(A){return -(Math.cos(Math.PI*A)-1)/2;
}},initialize:function(A){this.subject=this.subject||this;this.setOptions(A);this.options.duration=Fx.Durations[this.options.duration]||this.options.duration.toInt();
var B=this.options.wait;if(B===false){this.options.link="cancel";}},step:function(){var A=$time();if(A<this.time+this.options.duration){var B=this.options.transition((A-this.time)/this.options.duration);
this.set(this.compute(this.from,this.to,B));}else{this.set(this.compute(this.from,this.to,1));this.complete();}},set:function(A){return A;},compute:function(C,B,A){return Fx.compute(C,B,A);
},check:function(A){if(!this.timer){return true;}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(A.bind(this,Array.slice(arguments,1)));
return false;}return false;},start:function(B,A){if(!this.check(arguments.callee,B,A)){return this;}this.from=B;this.to=A;this.time=0;this.startTimer();
this.onStart();return this;},complete:function(){if(this.stopTimer()){this.onComplete();}return this;},cancel:function(){if(this.stopTimer()){this.onCancel();
}return this;},onStart:function(){this.fireEvent("start",this.subject);},onComplete:function(){this.fireEvent("complete",this.subject);if(!this.callChain()){this.fireEvent("chainComplete",this.subject);
}},onCancel:function(){this.fireEvent("cancel",this.subject).clearChain();},pause:function(){this.stopTimer();return this;},resume:function(){this.startTimer();
return this;},stopTimer:function(){if(!this.timer){return false;}this.time=$time()-this.time;this.timer=$clear(this.timer);return true;},startTimer:function(){if(this.timer){return false;
}this.time=$time()-this.time;this.timer=this.step.periodical(Math.round(1000/this.options.fps),this);return true;}});Fx.compute=function(C,B,A){return(B-C)*A+C;
};Fx.Durations={"short":250,normal:500,"long":1000};Fx.CSS=new Class({Extends:Fx,prepare:function(D,E,B){B=$splat(B);var C=B[1];if(!$chk(C)){B[1]=B[0];
B[0]=D.getStyle(E);}var A=B.map(this.parse);return{from:A[0],to:A[1]};},parse:function(A){A=$lambda(A)();A=(typeof A=="string")?A.split(" "):$splat(A);
return A.map(function(C){C=String(C);var B=false;Fx.CSS.Parsers.each(function(F,E){if(B){return ;}var D=F.parse(C);if($chk(D)){B={value:D,parser:F};}});
B=B||{value:C,parser:Fx.CSS.Parsers.String};return B;});},compute:function(D,C,B){var A=[];(Math.min(D.length,C.length)).times(function(E){A.push({value:D[E].parser.compute(D[E].value,C[E].value,B),parser:D[E].parser});
});A.$family={name:"fx:css:value"};return A;},serve:function(C,B){if($type(C)!="fx:css:value"){C=this.parse(C);}var A=[];C.each(function(D){A=A.concat(D.parser.serve(D.value,B));
});return A;},render:function(A,D,C,B){A.setStyle(D,this.serve(C,B));},search:function(A){if(Fx.CSS.Cache[A]){return Fx.CSS.Cache[A];}var B={};Array.each(document.styleSheets,function(E,D){var C=E.href;
if(C&&C.contains("://")&&!C.contains(document.domain)){return ;}var F=E.rules||E.cssRules;Array.each(F,function(I,G){if(!I.style){return ;}var H=(I.selectorText)?I.selectorText.replace(/^\w+/,function(J){return J.toLowerCase();
}):null;if(!H||!H.test("^"+A+"$")){return ;}Element.Styles.each(function(K,J){if(!I.style[J]||Element.ShortStyles[J]){return ;}K=String(I.style[J]);B[J]=(K.test(/^rgb/))?K.rgbToHex():K;
});});});return Fx.CSS.Cache[A]=B;}});Fx.CSS.Cache={};Fx.CSS.Parsers=new Hash({Color:{parse:function(A){if(A.match(/^#[0-9a-f]{3,6}$/i)){return A.hexToRgb(true);
}return((A=A.match(/(\d+),\s*(\d+),\s*(\d+)/)))?[A[1],A[2],A[3]]:false;},compute:function(C,B,A){return C.map(function(E,D){return Math.round(Fx.compute(C[D],B[D],A));
});},serve:function(A){return A.map(Number);}},Number:{parse:parseFloat,compute:Fx.compute,serve:function(B,A){return(A)?B+A:B;}},String:{parse:$lambda(false),compute:$arguments(1),serve:$arguments(0)}});
Fx.Tween=new Class({Extends:Fx.CSS,initialize:function(B,A){this.element=this.subject=$(B);this.parent(A);},set:function(B,A){if(arguments.length==1){A=B;
B=this.property||this.options.property;}this.render(this.element,B,A,this.options.unit);return this;},start:function(C,E,D){if(!this.check(arguments.callee,C,E,D)){return this;
}var B=Array.flatten(arguments);this.property=this.options.property||B.shift();var A=this.prepare(this.element,this.property,B);return this.parent(A.from,A.to);
}});Element.Properties.tween={set:function(A){var B=this.retrieve("tween");if(B){B.cancel();}return this.eliminate("tween").store("tween:options",$extend({link:"cancel"},A));
},get:function(A){if(A||!this.retrieve("tween")){if(A||!this.retrieve("tween:options")){this.set("tween",A);}this.store("tween",new Fx.Tween(this,this.retrieve("tween:options")));
}return this.retrieve("tween");}};Element.implement({tween:function(A,C,B){this.get("tween").start(arguments);return this;},fade:function(C){var E=this.get("tween"),D="opacity",A;
C=$pick(C,"toggle");switch(C){case"in":E.start(D,1);break;case"out":E.start(D,0);break;case"show":E.set(D,1);break;case"hide":E.set(D,0);break;case"toggle":var B=this.retrieve("fade:flag",this.get("opacity")==1);
E.start(D,(B)?0:1);this.store("fade:flag",!B);A=true;break;default:E.start(D,arguments);}if(!A){this.eliminate("fade:flag");}return this;},highlight:function(C,A){if(!A){A=this.retrieve("highlight:original",this.getStyle("background-color"));
A=(A=="transparent")?"#fff":A;}var B=this.get("tween");B.start("background-color",C||"#ffff88",A).chain(function(){this.setStyle("background-color",this.retrieve("highlight:original"));
B.callChain();}.bind(this));return this;}});Fx.Morph=new Class({Extends:Fx.CSS,initialize:function(B,A){this.element=this.subject=$(B);this.parent(A);},set:function(A){if(typeof A=="string"){A=this.search(A);
}for(var B in A){this.render(this.element,B,A[B],this.options.unit);}return this;},compute:function(E,D,C){var A={};for(var B in E){A[B]=this.parent(E[B],D[B],C);
}return A;},start:function(B){if(!this.check(arguments.callee,B)){return this;}if(typeof B=="string"){B=this.search(B);}var E={},D={};for(var C in B){var A=this.prepare(this.element,C,B[C]);
E[C]=A.from;D[C]=A.to;}return this.parent(E,D);}});Element.Properties.morph={set:function(A){var B=this.retrieve("morph");if(B){B.cancel();}return this.eliminate("morph").store("morph:options",$extend({link:"cancel"},A));
},get:function(A){if(A||!this.retrieve("morph")){if(A||!this.retrieve("morph:options")){this.set("morph",A);}this.store("morph",new Fx.Morph(this,this.retrieve("morph:options")));
}return this.retrieve("morph");}};Element.implement({morph:function(A){this.get("morph").start(A);return this;}});(function(){var A=Fx.prototype.initialize;
Fx.prototype.initialize=function(B){A.call(this,B);var C=this.options.transition;if(typeof C=="string"&&(C=C.split(":"))){var D=Fx.Transitions;D=D[C[0]]||D[C[0].capitalize()];
if(C[1]){D=D["ease"+C[1].capitalize()+(C[2]?C[2].capitalize():"")];}this.options.transition=D;}};})();Fx.Transition=function(B,A){A=$splat(A);return $extend(B,{easeIn:function(C){return B(C,A);
},easeOut:function(C){return 1-B(1-C,A);},easeInOut:function(C){return(C<=0.5)?B(2*C,A)/2:(2-B(2*(1-C),A))/2;}});};Fx.Transitions=new Hash({linear:$arguments(0)});
Fx.Transitions.extend=function(A){for(var B in A){Fx.Transitions[B]=new Fx.Transition(A[B]);}};Fx.Transitions.extend({Pow:function(B,A){return Math.pow(B,A[0]||6);
},Expo:function(A){return Math.pow(2,8*(A-1));},Circ:function(A){return 1-Math.sin(Math.acos(A));},Sine:function(A){return 1-Math.sin((1-A)*Math.PI/2);
},Back:function(B,A){A=A[0]||1.618;return Math.pow(B,2)*((A+1)*B-A);},Bounce:function(D){var C;for(var B=0,A=1;1;B+=A,A/=2){if(D>=(7-4*B)/11){C=-Math.pow((11-6*B-11*D)/4,2)+A*A;
break;}}return C;},Elastic:function(B,A){return Math.pow(2,10*--B)*Math.cos(20*B*Math.PI*(A[0]||1)/3);}});["Quad","Cubic","Quart","Quint"].each(function(B,A){Fx.Transitions[B]=new Fx.Transition(function(C){return Math.pow(C,[A+2]);
});});var Request=new Class({Implements:[Chain,Events,Options],options:{url:"",data:"",headers:{"X-Requested-With":"XMLHttpRequest",Accept:"text/javascript, text/html, application/xml, text/xml, */*"},async:true,format:false,method:"post",link:"ignore",isSuccess:null,emulation:true,urlEncoded:true,encoding:"utf-8",evalScripts:false,evalResponse:false},initialize:function(A){this.xhr=new Browser.Request();
this.setOptions(A);this.options.isSuccess=this.options.isSuccess||this.isSuccess;this.headers=new Hash(this.options.headers);},onStateChange:function(){if(this.xhr.readyState!=4||!this.running){return ;
}this.running=false;this.status=0;$try(function(){this.status=this.xhr.status;}.bind(this));if(this.options.isSuccess.call(this,this.status)){this.response={text:this.xhr.responseText,xml:this.xhr.responseXML};
this.success(this.response.text,this.response.xml);}else{this.response={text:null,xml:null};this.failure();}this.xhr.onreadystatechange=$empty;},isSuccess:function(){return((this.status>=200)&&(this.status<300));
},processScripts:function(A){if(this.options.evalResponse||(/(ecma|java)script/).test(this.getHeader("Content-type"))){return $exec(A);}return A.stripScripts(this.options.evalScripts);
},success:function(B,A){this.onSuccess(this.processScripts(B),A);},onSuccess:function(){this.fireEvent("complete",arguments).fireEvent("success",arguments).callChain();
},failure:function(){this.onFailure();},onFailure:function(){this.fireEvent("complete").fireEvent("failure",this.xhr);},setHeader:function(A,B){this.headers.set(A,B);
return this;},getHeader:function(A){return $try(function(){return this.xhr.getResponseHeader(A);}.bind(this));},check:function(A){if(!this.running){return true;
}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(A.bind(this,Array.slice(arguments,1)));return false;}return false;
},send:function(I){if(!this.check(arguments.callee,I)){return this;}this.running=true;var G=$type(I);if(G=="string"||G=="element"){I={data:I};}var D=this.options;
I=$extend({data:D.data,url:D.url,method:D.method},I);var E=I.data,B=I.url,A=I.method;switch($type(E)){case"element":E=$(E).toQueryString();break;case"object":case"hash":E=Hash.toQueryString(E);
}if(this.options.format){var H="format="+this.options.format;E=(E)?H+"&"+E:H;}if(this.options.emulation&&["put","delete"].contains(A)){var F="_method="+A;
E=(E)?F+"&"+E:F;A="post";}if(this.options.urlEncoded&&A=="post"){var C=(this.options.encoding)?"; charset="+this.options.encoding:"";this.headers.set("Content-type","application/x-www-form-urlencoded"+C);
}if(E&&A=="get"){B=B+(B.contains("?")?"&":"?")+E;E=null;}this.xhr.open(A.toUpperCase(),B,this.options.async);this.xhr.onreadystatechange=this.onStateChange.bind(this);
this.headers.each(function(K,J){if(!$try(function(){this.xhr.setRequestHeader(J,K);return true;}.bind(this))){this.fireEvent("exception",[J,K]);}},this);
this.fireEvent("request");this.xhr.send(E);if(!this.options.async){this.onStateChange();}return this;},cancel:function(){if(!this.running){return this;
}this.running=false;this.xhr.abort();this.xhr.onreadystatechange=$empty;this.xhr=new Browser.Request();this.fireEvent("cancel");return this;}});(function(){var A={};
["get","post","put","delete","GET","POST","PUT","DELETE"].each(function(B){A[B]=function(){var C=Array.link(arguments,{url:String.type,data:$defined});
return this.send($extend(C,{method:B.toLowerCase()}));};});Request.implement(A);})();Element.Properties.send={set:function(A){var B=this.retrieve("send");
if(B){B.cancel();}return this.eliminate("send").store("send:options",$extend({data:this,link:"cancel",method:this.get("method")||"post",url:this.get("action")},A));
},get:function(A){if(A||!this.retrieve("send")){if(A||!this.retrieve("send:options")){this.set("send",A);}this.store("send",new Request(this.retrieve("send:options")));
}return this.retrieve("send");}};Element.implement({send:function(A){var B=this.get("send");B.send({data:this,url:A||B.options.url});return this;}});Request.HTML=new Class({Extends:Request,options:{update:false,evalScripts:true,filter:false},processHTML:function(C){var B=C.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
C=(B)?B[1]:C;var A=new Element("div");return $try(function(){var D="<root>"+C+"</root>",G;if(Browser.Engine.trident){G=new ActiveXObject("Microsoft.XMLDOM");
G.async=false;G.loadXML(D);}else{G=new DOMParser().parseFromString(D,"text/xml");}D=G.getElementsByTagName("root")[0];for(var F=0,E=D.childNodes.length;
F<E;F++){var H=Element.clone(D.childNodes[F],true,true);if(H){A.grab(H);}}return A;})||A.set("html",C);},success:function(D){var C=this.options,B=this.response;
B.html=D.stripScripts(function(E){B.javascript=E;});var A=this.processHTML(B.html);B.tree=A.childNodes;B.elements=A.getElements("*");if(C.filter){B.tree=B.elements.filter(C.filter);
}if(C.update){$(C.update).empty().adopt(B.tree);}if(C.evalScripts){$exec(B.javascript);}this.onSuccess(B.tree,B.elements,B.html,B.javascript);}});Element.Properties.load={set:function(A){var B=this.retrieve("load");
if(B){send.cancel();}return this.eliminate("load").store("load:options",$extend({data:this,link:"cancel",update:this,method:"get"},A));},get:function(A){if(A||!this.retrieve("load")){if(A||!this.retrieve("load:options")){this.set("load",A);
}this.store("load",new Request.HTML(this.retrieve("load:options")));}return this.retrieve("load");}};Element.implement({load:function(){this.get("load").send(Array.link(arguments,{data:Object.type,url:String.type}));
return this;}});Fx.Slide=new Class({Extends:Fx,options:{mode:"vertical"},initialize:function(B,A){this.addEvent("complete",function(){this.open=(this.wrapper["offset"+this.layout.capitalize()]!=0);
if(this.open&&Browser.Engine.webkit419){this.element.dispose().inject(this.wrapper);}},true);this.element=this.subject=$(B);this.parent(A);var C=this.element.retrieve("wrapper");
this.wrapper=C||new Element("div",{styles:$extend(this.element.getStyles("margin","position"),{overflow:"hidden"})}).wraps(this.element);this.element.store("wrapper",this.wrapper).setStyle("margin",0);
this.now=[];this.open=true;},vertical:function(){this.margin="margin-top";this.layout="height";this.offset=this.element.offsetHeight;},horizontal:function(){this.margin="margin-left";
this.layout="width";this.offset=this.element.offsetWidth;},set:function(A){this.element.setStyle(this.margin,A[0]);this.wrapper.setStyle(this.layout,A[1]);
return this;},compute:function(E,D,C){var B=[];var A=2;A.times(function(F){B[F]=Fx.compute(E[F],D[F],C);});return B;},start:function(B,E){if(!this.check(arguments.callee,B,E)){return this;
}this[E||this.options.mode]();var D=this.element.getStyle(this.margin).toInt();var C=this.wrapper.getStyle(this.layout).toInt();var A=[[D,C],[0,this.offset]];
var G=[[D,C],[-this.offset,0]];var F;switch(B){case"in":F=A;break;case"out":F=G;break;case"toggle":F=(this.wrapper["offset"+this.layout.capitalize()]==0)?A:G;
}return this.parent(F[0],F[1]);},slideIn:function(A){return this.start("in",A);},slideOut:function(A){return this.start("out",A);},hide:function(A){this[A||this.options.mode]();
this.open=false;return this.set([-this.offset,0]);},show:function(A){this[A||this.options.mode]();this.open=true;return this.set([0,this.offset]);},toggle:function(A){return this.start("toggle",A);
}});Element.Properties.slide={set:function(B){var A=this.retrieve("slide");if(A){A.cancel();}return this.eliminate("slide").store("slide:options",$extend({link:"cancel"},B));
},get:function(A){if(A||!this.retrieve("slide")){if(A||!this.retrieve("slide:options")){this.set("slide",A);}this.store("slide",new Fx.Slide(this,this.retrieve("slide:options")));
}return this.retrieve("slide");}};Element.implement({slide:function(D,E){D=D||"toggle";var B=this.get("slide"),A;switch(D){case"hide":B.hide(E);break;case"show":B.show(E);
break;case"toggle":var C=this.retrieve("slide:flag",B.open);B[(C)?"slideOut":"slideIn"](E);this.store("slide:flag",!C);A=true;break;default:B.start(D,E);
}if(!A){this.eliminate("slide:flag");}return this;}});Fx.Scroll=new Class({Extends:Fx,options:{offset:{x:0,y:0},wheelStops:true},initialize:function(B,A){this.element=this.subject=$(B);
this.parent(A);var D=this.cancel.bind(this,false);if($type(this.element)!="element"){this.element=$(this.element.getDocument().body);}var C=this.element;
if(this.options.wheelStops){this.addEvent("start",function(){C.addEvent("mousewheel",D);},true);this.addEvent("complete",function(){C.removeEvent("mousewheel",D);
},true);}},set:function(){var A=Array.flatten(arguments);this.element.scrollTo(A[0],A[1]);},compute:function(E,D,C){var B=[];var A=2;A.times(function(F){B.push(Fx.compute(E[F],D[F],C));
});return B;},start:function(C,H){if(!this.check(arguments.callee,C,H)){return this;}var E=this.element.getSize(),F=this.element.getScrollSize();var B=this.element.getScroll(),D={x:C,y:H};
for(var G in D){var A=F[G]-E[G];if($chk(D[G])){D[G]=($type(D[G])=="number")?D[G].limit(0,A):A;}else{D[G]=B[G];}D[G]+=this.options.offset[G];}return this.parent([B.x,B.y],[D.x,D.y]);
},toTop:function(){return this.start(false,0);},toLeft:function(){return this.start(0,false);},toRight:function(){return this.start("right",false);},toBottom:function(){return this.start(false,"bottom");
},toElement:function(B){var A=$(B).getPosition(this.element);return this.start(A.x,A.y);}});Fx.Elements=new Class({Extends:Fx.CSS,initialize:function(B,A){this.elements=this.subject=$$(B);
this.parent(A);},compute:function(G,H,I){var C={};for(var D in G){var A=G[D],E=H[D],F=C[D]={};for(var B in A){F[B]=this.parent(A[B],E[B],I);}}return C;
},set:function(B){for(var C in B){var A=B[C];for(var D in A){this.render(this.elements[C],D,A[D],this.options.unit);}}return this;},start:function(C){if(!this.check(arguments.callee,C)){return this;
}var H={},I={};for(var D in C){var F=C[D],A=H[D]={},G=I[D]={};for(var B in F){var E=this.prepare(this.elements[D],B,F[B]);A[B]=E.from;G[B]=E.to;}}return this.parent(H,I);
}});var Drag=new Class({Implements:[Events,Options],options:{snap:6,unit:"px",grid:false,style:true,limit:false,handle:false,invert:false,preventDefault:false,modifiers:{x:"left",y:"top"}},initialize:function(){var B=Array.link(arguments,{options:Object.type,element:$defined});
this.element=$(B.element);this.document=this.element.getDocument();this.setOptions(B.options||{});var A=$type(this.options.handle);this.handles=(A=="array"||A=="collection")?$$(this.options.handle):$(this.options.handle)||this.element;
this.mouse={now:{},pos:{}};this.value={start:{},now:{}};this.selection=(Browser.Engine.trident)?"selectstart":"mousedown";this.bound={start:this.start.bind(this),check:this.check.bind(this),drag:this.drag.bind(this),stop:this.stop.bind(this),cancel:this.cancel.bind(this),eventStop:$lambda(false)};
this.attach();},attach:function(){this.handles.addEvent("mousedown",this.bound.start);return this;},detach:function(){this.handles.removeEvent("mousedown",this.bound.start);
return this;},start:function(C){if(this.options.preventDefault){C.preventDefault();}this.fireEvent("beforeStart",this.element);this.mouse.start=C.page;
var A=this.options.limit;this.limit={x:[],y:[]};for(var D in this.options.modifiers){if(!this.options.modifiers[D]){continue;}if(this.options.style){this.value.now[D]=this.element.getStyle(this.options.modifiers[D]).toInt();
}else{this.value.now[D]=this.element[this.options.modifiers[D]];}if(this.options.invert){this.value.now[D]*=-1;}this.mouse.pos[D]=C.page[D]-this.value.now[D];
if(A&&A[D]){for(var B=2;B--;B){if($chk(A[D][B])){this.limit[D][B]=$lambda(A[D][B])();}}}}if($type(this.options.grid)=="number"){this.options.grid={x:this.options.grid,y:this.options.grid};
}this.document.addEvents({mousemove:this.bound.check,mouseup:this.bound.cancel});this.document.addEvent(this.selection,this.bound.eventStop);},check:function(A){if(this.options.preventDefault){A.preventDefault();
}var B=Math.round(Math.sqrt(Math.pow(A.page.x-this.mouse.start.x,2)+Math.pow(A.page.y-this.mouse.start.y,2)));if(B>this.options.snap){this.cancel();this.document.addEvents({mousemove:this.bound.drag,mouseup:this.bound.stop});
this.fireEvent("start",this.element).fireEvent("snap",this.element);}},drag:function(A){if(this.options.preventDefault){A.preventDefault();}this.mouse.now=A.page;
for(var B in this.options.modifiers){if(!this.options.modifiers[B]){continue;}this.value.now[B]=this.mouse.now[B]-this.mouse.pos[B];if(this.options.invert){this.value.now[B]*=-1;
}if(this.options.limit&&this.limit[B]){if($chk(this.limit[B][1])&&(this.value.now[B]>this.limit[B][1])){this.value.now[B]=this.limit[B][1];}else{if($chk(this.limit[B][0])&&(this.value.now[B]<this.limit[B][0])){this.value.now[B]=this.limit[B][0];
}}}if(this.options.grid[B]){this.value.now[B]-=(this.value.now[B]%this.options.grid[B]);}if(this.options.style){this.element.setStyle(this.options.modifiers[B],this.value.now[B]+this.options.unit);
}else{this.element[this.options.modifiers[B]]=this.value.now[B];}}this.fireEvent("drag",this.element);},cancel:function(A){this.document.removeEvent("mousemove",this.bound.check);
this.document.removeEvent("mouseup",this.bound.cancel);if(A){this.document.removeEvent(this.selection,this.bound.eventStop);this.fireEvent("cancel",this.element);
}},stop:function(A){this.document.removeEvent(this.selection,this.bound.eventStop);this.document.removeEvent("mousemove",this.bound.drag);this.document.removeEvent("mouseup",this.bound.stop);
if(A){this.fireEvent("complete",this.element);}}});Element.implement({makeResizable:function(A){return new Drag(this,$merge({modifiers:{x:"width",y:"height"}},A));
}});Drag.Move=new Class({Extends:Drag,options:{droppables:[],container:false},initialize:function(C,B){this.parent(C,B);this.droppables=$$(this.options.droppables);
this.container=$(this.options.container);if(this.container&&$type(this.container)!="element"){this.container=$(this.container.getDocument().body);}C=this.element;
var D=C.getStyle("position");var A=(D!="static")?D:"absolute";if(C.getStyle("left")=="auto"||C.getStyle("top")=="auto"){C.position(C.getPosition(C.offsetParent));
}C.setStyle("position",A);this.addEvent("start",function(){this.checkDroppables();},true);},start:function(B){if(this.container){var D=this.element,J=this.container,E=J.getCoordinates(D.offsetParent),F={},A={};
["top","right","bottom","left"].each(function(K){F[K]=J.getStyle("padding-"+K).toInt();A[K]=D.getStyle("margin-"+K).toInt();},this);var C=D.offsetWidth+A.left+A.right,I=D.offsetHeight+A.top+A.bottom;
var H=[E.left+F.left,E.right-F.right-C];var G=[E.top+F.top,E.bottom-F.bottom-I];this.options.limit={x:H,y:G};}this.parent(B);},checkAgainst:function(B){B=B.getCoordinates();
var A=this.mouse.now;return(A.x>B.left&&A.x<B.right&&A.y<B.bottom&&A.y>B.top);},checkDroppables:function(){var A=this.droppables.filter(this.checkAgainst,this).getLast();
if(this.overed!=A){if(this.overed){this.fireEvent("leave",[this.element,this.overed]);}if(A){this.overed=A;this.fireEvent("enter",[this.element,A]);}else{this.overed=null;
}}},drag:function(A){this.parent(A);if(this.droppables.length){this.checkDroppables();}},stop:function(A){this.checkDroppables();this.fireEvent("drop",[this.element,this.overed]);
this.overed=null;return this.parent(A);}});Element.implement({makeDraggable:function(A){return new Drag.Move(this,A);}});var Asset=new Hash({javascript:function(F,D){D=$extend({onload:$empty,document:document,check:$lambda(true)},D);
var B=new Element("script",{src:F,type:"text/javascript"});var E=D.onload.bind(B),A=D.check,G=D.document;delete D.onload;delete D.check;delete D.document;
B.addEvents({load:E,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){E();}}}).setProperties(D);if(Browser.Engine.webkit419){var C=(function(){if(!$try(A)){return ;
}$clear(C);E();}).periodical(50);}return B.inject(G.head);},css:function(B,A){return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:B},A)).inject(document.head);
},image:function(C,B){B=$merge({onload:$empty,onabort:$empty,onerror:$empty},B);var D=new Image();var A=$(D)||new Element("img");["load","abort","error"].each(function(E){var F="on"+E;
var G=B[F];delete B[F];D[F]=function(){if(!D){return ;}if(!A.parentNode){A.width=D.width;A.height=D.height;}D=D.onload=D.onabort=D.onerror=null;G.delay(1,A,A);
A.fireEvent(E,A,1);};});D.src=A.src=C;if(D&&D.complete){D.onload.delay(1);}return A.setProperties(B);},images:function(D,C){C=$merge({onComplete:$empty,onProgress:$empty},C);
if(!D.push){D=[D];}var A=[];var B=0;D.each(function(F){var E=new Asset.image(F,{onload:function(){C.onProgress.call(this,B,D.indexOf(F));B++;if(B==D.length){C.onComplete();
}}});A.push(E);});return new Elements(A);}});

/*
	Filename: moo.rd - A lightweight Mootools extension
	
	Author: Riccardo Degni, <http://www.riccardodegni.it/> and the moo.rd Team
	
	License: GNU GPL License
	
	Copyright: copyright 2007 Riccardo Degni
	
	[Credits]
		[li] moo.rd is based on the MooTools framework <http://mootools.net/>, and uses the MooTools syntax
		[li] moo.rd constructors extends some of the MooTools Classes
		[li] moo.rd Documentation is written by Riccardo Degni
	[/Credits]
*/

var Moo = {};

Moo.Rd = {
	version: '1.3.2',
	author: 'Riccardo Degni',
	members: [
		'Cristiano Fino',
		'Moocha'
	]
};

/*
	Filename: constructors.js
	
	[Description] 
		Contains some of the moo.rd native Constructors based on the MooTools Class. It permits a major modularity.
	[/Description]
	
	Contains: Class Table, Class Make
*/
/*
	Class: Table
	Description: Allows you to customize tables, tables rows, cells and columns 
*/
var Table = new Class({	
	initialize: function(element) {
		this.element = $(element);
		this.rows = this.element.getElements('tr');
		this.cells = this.element.getElements('tr').getElements('td');
	}
});

/*
	Class: Make
	Description: Wrapper to create Classes that make dinamically Elements.  
*/
var Make = new Class({
	Implements: [Options],
	options: {
		content: 'text'
	}
});

/*
	Filename: type.js
	
	[Description]
		Contains shortcut functions to detect the type of an object using the $type function and the $dump function to detect the value and the type of every objects
	[/Description]
	
	Contains: A collection of functions based on the $type function plus the $dump function
	
	[Functions]
		$dump --- returns the value and the type of the object passed in
		$string --- returns true if the object is a string
		$int --- returns true if the object is a number
		$array --- returns true if the object is an array
		$object --- returns true if the object is an object
		$function --- returns true if the object is a function
		$date --- returns true if the object is a date
		$class --- returns true if the object is a class
		$element --- returns true if the object is an element
		$collection --- returns true if the object is a collection
		$arguments --- returns true if the object is the arguments object
		$textnode --- returns true if the object is a textnode
		$whitespace --- returns true if the object is a whitespace
		$window --- returns true if the object is the window object
		$document --- returns true if the object is the document object
	[/Functions]
*/
/*
	Function: $dump
	Description: returns the value and the type of the object passed in
	[Arguments]
		obj :: the object to analize
		results :: optional. the element to put the results to. If false returns the result string.
	[/Arguments]
	[Example] 
		> var s = 'some data';
		>
		> $dump(s, 'box');
		> // returns
		> '(
		>   Value: some data
		>   Type: string
		> )'
		>
		> var a = ['a', 'b', 'c', 'd'];
		>
		> $dump(a, 'box');
		> // returns
		> '(
		>   Value: a, b, c, d
		>   Type: array
		> )'
	[/Example]
*/
function $dump(obj, result) {
	var r = '(' + '<br />';
	var tinyspaces = '&nbsp;&nbsp;';
	r += tinyspaces + 'Value: ' + obj.toString() + '<br />';
	r += tinyspaces + 'Type: ' + $type(obj) + '<br />';
	r += ')';
	return (result) ? $(result).set('html', r) : r;
}

/*
	Function: $string
	Description: returns true if the object is a string
*/
function $string(obj) {
	return $type(obj) == 'string';
}

/*
	Function: $int
	Description: returns true if the object is a number
*/
function $int(obj) {
	return $type(obj) == 'number';
}

/*
	Function: $array
	Description: returns true if the object is an array
*/
function $array(obj) {
	return $type(obj) == 'array';
}

/*
	Function: $object
	Description: returns true if the object is an object
*/
function $object(obj) {
	return $type(obj) == 'object';
}

/*
	Function: $function
	Description: returns true if the object is a function
*/
function $function(obj) {
	return $type(obj) == 'function';
}

/*
	Function: $date
	Description: returns true if the object is a date
*/
function $date(obj) {
	return $type(obj) == 'date';
}

/*
	Function: $class
	Description: returns true if the object is a class
*/
function $class(obj) {
	return $type(obj) == 'class';
}

/*
	Function: $element
	Description: returns true if the object is an element
*/
function $element(obj) {
	return $type(obj) == 'element';
}

/*
	Function: $collection
	Description: returns true if the object is a collection
*/
function $collection(obj) {
	return $type(obj) == 'collection';
}

/*
	Function: $arguments
	Description: returns true if the object is the arguments object
*/
function $arguments(obj) {
	return $type(obj) == 'arguments';
}

/*
	Function: $textnode
	Description: returns true if the object is a textnode
*/
function $textnode(obj) {
	return $type(obj) == 'textnode';
}

/*
	Function: $whitespace
	Description: returns true if the object is a whitespace
*/
function $whitespace(obj) {
	return $type(obj) == 'whitespace';
}

/*
	Function: $window
	Description: returns true if the object is the window object
*/
function $window(obj) {
	return $type(obj) == 'window';
}

/*
	Function: $document
	Description: returns true if the object is the document object
*/
function $document(obj) {
	return $type(obj) == 'document';
}

/*
	Filename: browser.js
	
	[Description]
		Contains some Browser properties to ease the detection of the browser which is working
	[/Description]
	
	Contains: Hash Browser
	
	[Summary]
		Browser ::: Extends the Browser Hash with new properties 
	[/Summary]
*/
/*
	Hash: Browser
	
	[Description]  
		Extends the Browser Hash with new properties, to speed up and ease the detection of the browser which is working.
	[/Description]
	
	[Hash]
		 Browser.ie : alias of Browser.Engine.trident
		 Browser.ie6 : alias of Browser.Engine.trident4
		 Browser.ie7 : alias of Browser.Engine.trident5
		 Browser.firefox : alias of Browser.Engine.gecko
		 Browser.safari : alias of Browser.Engine.webkit
		 Browser.safari2 : alias of Browser.Engine.webkit419
		 Browser.safari3 : alias of Browser.Engine.webkit420
		 Browser.opera : alias of Browser.Engine.presto
		 Browser.opera925 : alias of Browser.Engine.presto925
		 Browser.opera950 : alias of Browser.Engine.presto950
	[/Hash]
*/
Browser.ie = Browser.Engine.trident;
Browser.ie6 = Browser.Engine.trident4;
Browser.ie7 = Browser.Engine.trident5;
Browser.firefox = Browser.Engine.gecko;
Browser.safari = Browser.Engine.webkit;
Browser.safari2 = Browser.Engine.webkit419;
Browser.safari3 = Browser.Engine.webkit420;
Browser.opera = Browser.Engine.presto;
Browser.opera925 = Browser.Engine.presto925;
Browser.opera950 = Browser.Engine.presto950;

/*
	Filename: overlay.js
	
	[Description]
		Contains the Overlay Utility Class, that can be implemented with Implements property into any Class
	[/Description]
	
	Contains: Class Overlay
	
	Requires: browser.js
	
	[Summary]
		Overlay ::: Utility Class for creating customized and advanced overlays
	[/Summary]
*/
/*
	Class: Overlay
	
	[Description]  
		Utility Class for creating customized and advanced overlays. Adds the Overlay properties to the Classes
	[/Description]
	
	Constructor: new Overlay()
	
	[Methods]
		createOverlay -- creates the overlay property which represents the overlay
		createFullPage -- creates the full page overlay which represents the upper level
		setLight -- sets the light of the overlay. Can be 'draken', 'lighten', false or a color
		injectOverlay -- injects the overlay and indicates that the overlay is active
		removeOverlay -- removes the overlay with additional controls for IE 6
	[/Methods]
*/
var Overlay = new Class({
						
	/*
	Method: createOverlay
	Description:  creates the overlay property which represents the overlay
	[Arguments]
		id :: the overlay id
		light :: the overlay light. It can be 'darken' 'lighten', false or a color
	[/Arguments]
	*/
	createOverlay: function(id, light) {
		this.overlay = new Element('div', {
			'id': id || 'overlay',
			'styles': {
				'position': (Browser.ie6) ? 'absolute' : 'fixed',
				'top': '0px',
				'left': '0px',
				'width': (Browser.ie6) ? window.getWidth() : '100%',
				'height': '100%',
				'background-image':'url(g.gif)',
				'z-index': 800
			}
		});
		
		if(Browser.Engine.presto) this.overlay.setStyle('overflow', 'hidden');  
	
		this.setLight(light);
		
		return this;
	},
	
	/*
	Method: createFullPage
	Description:  creates the full page overlay which represents the upper level
	[Arguments]
		id :: the fullpage id
	[/Arguments]
	*/
	createFullPage: function(id) {
		this.fullpage = new Element('div', {
			'id': id || 'fullpage',
			'styles': {
				'position': (Browser.ie6) ? 'absolute' : 'fixed',
				'top': '0px',
				'left': '0px',
				'width': (Browser.ie6) ? window.getWidth() : '100%',
				'height': '100%',
				'background-image':'url(g.gif)',
				'z-index': 900
			}
		});
		
		if(Browser.Engine.presto) this.fullpage.setStyle('overflow', 'hidden');  
		
		return this;
	},
	
	/*
	Method: setLight
	Description:  sets the light of the overlay. Can be 'darken', 'lighten', false or a color
	[Arguments]
		light :: the light of the overlay 
		opacity :: optional. the opacity value of the overlay
	[/Arguments]
	*/
	setLight: function(light, opacity) {
		switch(light) {
			case 'darken': 
				var color = '#333333';
				break;
			case 'lighten':
				var color = '#FFFFFF';
				break;
			case false:
				var color = 'transparent';
				break;
			default: 
				var color = light;
				break;
		};
		this.overlay.setStyles({
			'background-color': color,
			'opacity': opacity || '0.8'			   
		});
		
		return this;
	},
	
	/*
	Method: injectOverlay
	Description:  injects the overlay and indicates that the overlay is active
	[Arguments]
		fullpage :: if true the fullpage will be injected too
	[/Arguments]
	*/
	injectOverlay: function(fullpage) {
		this.overlay.inject(document.body);
		if(fullpage) this.fullpage.inject(document.body);
		this.overlayActive = true;
		this.fixOverlay();
		return this;
	},
	
	/*
	Method: removeOverlay
	Description:  removes the overlay with additional controls for IE 6
	*/
	removeOverlay: function() {
		this.overlay.dispose();
		this.fullpage.dispose();
		if(Browser.ie6) {
			document.body.setStyles({'height': this.bodyHeightTrident4, 'overflow': this.bodyOverflowTrident4});
		}
		this.overlayActive = false;
		return this;
	},
	
	fixOverlay: function() {
		if(Browser.ie6) {
			if(!this.bodyHeightTrident4) this.bodyHeightTrident4 = $(document.body).getStyle('height');
			this.bodyOverflowTrident4 = $(document.body).getStyle('overflow');
			
			$$(this.overlay, this.fullpage).setStyle('overflow', 'hidden');
			
			$$(window, document.body).setStyles({
				'height': '100%',
				'overflow': 'auto',
				'margin': 0,
				'padding': 0
			});
		}
		return this;
	}
});

/*
	Filename: string.js
	
	[Description]
		Contains prototypes which extend the String constructor
	[/Description]
	
	Contains: Class String
	
	[Summary]
		String ::: Contains prototypes which extend the String constructor
	[/Summary]
*/
/*
	Class: String
	
	[Description]
		Extends the native String object with many methods which are very useful but aren't contained in the core Javascript language. 
		Others are shortcuts to existing Javascript String native methods. 
	[/Description]
	
	Extends: Class String
	
	[Methods]
		upper -- converts the string to upper case
		lower -- converts the string to lower case
		firstChar -- tests if the passed in character is the first of the string
		hasChar -- tests if the string contains the passed in character
		lastChar -- tests if the passed in character is the last of the string
		stripPhp -- strips all php tags from the string
		stripJs -- strips all script tags from the string
		globalReplace -- replaces all occurrences with a regular expression
		contains -- tests if a string contains the passed in substring
		poOf -- returns an array which represents the position of all occurences in the string
		getFirst -- returns the first character of the string
		getLast -- returns the last character of the string
		camelize -- returns a string camelized
		upperFirst -- converts the first char of the string to upper case
	[/Methods]
*/
String.implement({
	
	/*
	Method: upper
	Description: converts the string to upper case
	[Example]  
		> var s = 'a string';
		> // returns 'A STRING'
		> s.upper(); 
	[/Example]
	*/
	upper: function() {
 		return this.toUpperCase();
 	},
	
	/*
	Method: lower
	Description: converts the string to lower case
	[Example]  
		> var s = 'A STRING';
		> // returns 'a string'
		> s.lower(); 
	[/Example]
	*/
 	lower: function() {
 		return this.toLowerCase();
 	},
	
	/*
	Method: firstChar
	Description: tests if the passed in character is the first of the string
	[Arguments]
		char :: the character
	[/Arguments]
	[Example]  
		> var s = 'a string';
		> // returns true
		> s.firstChar('a');
		> // returns false
		> s.firstChar('f');
	[/Example]
	*/
	firstChar: function (n) {	
		return (this.charAt(0)==n) ? true : false;
	},
	
	/*
	Method: hasChar
	Description: tests if the string contains the passed in character
	[Arguments]
		char :: the character
	[/Arguments]
	[Example]  
		> var s = 'a string';
		> // returns true
		> s.hasChar('a');
		> // returns false
		> s.hasChar('f');  
	[/Example]
	*/
	hasChar: function (n) {
		for(var i=0; i<=this.length; i++)
			if(this.charAt(i)==n) return true;
		return false;
	},
	
	/*
	Method: lastChar
	Description: tests if the passed in character is the last of the string
	[Arguments]
		char :: the character
	[/Arguments]
	[Example]  
	 	> var s = 'a string';
		> // returns true
		> s.lastChar('g');
		> // returns false
		> s.lastChar('f');
	[/Example]
	*/
	lastChar: function (n) {	
		return (this.charAt(this.length-1)==n) ? true : false;
	},
	
	/*
	Method: stripPhp
	Description: strips all php tags from the string
	[Example]  
		> var s = '&lt;?php a string ?&gt;';
		> //returns 'a string'
		> s.stripPhp();
	[/Example]
	*/
	stripPhp: function() {
		return this.replace(/<\?php|\?>/gi, '');
	},
	
	/*
	Method: stripJs
	Description: strips all script tags from the string
	[Example]  
		> var s = '&lt;script type='text/javascript'&gt; &lt;i&gt; a string &lt;/i&gt; &lt;/script&gt;';
		> // returns '&lt;i&gt; a string &lt;/i&gt;'
		> s.stripJs();
	[/Example]
	*/
	stripJs: function() {
		return this.replace(/<script[^>]{0,}>|<\/script>/gi, '');
	},
	
	/*
	Method: globalReplace
	Description: replaces all occurrences with a regular expression
	[Arguments]
		value :: it can be a regular expression that specifies the pattern which must be replaced, or a string. If it's a string it is not first converted to a RegExp object.
		replacement :: a string that specifies the replacement text or a function that is invoked to generate the replacement text
		options :: a string that specifies the regular expression attributes
	[/Arguments]
	[Example]  
		> var s = 'some data some';
		> // returns 'many data many'
		> s.globalReplace('some', 'many');
	[/Example]
	*/
	globalReplace: function(val, repl, regexAttr) {
		return this.replace(new RegExp(val, regexAttr || 'gi'), repl);
	},
	
	/*
	Method: contains
	Description: tests if a string contains the passed in substring
	[Arguments]
		substring :: the substring to search
	[/Arguments]
	[Example]  
		> var s = 'some data';
		> // returns true
		> s.contains('some');
	[/Example]
	*/
	contains: function (phrase) {
		return (this.indexOf(phrase) != -1) ? true : false;
	},
	
	/*
	Method: posOf
	Description: returns an array which represents the position of all occurences in the string
	[Arguments]
		char :: the character to search
	[/Arguments]
	[Example]  
		> var s = 'insert a string';
		> // returns [2,9]
		> s.posOf('s');
	[/Example]
	*/
	posOf: function (n) {
		var positions = new Array();
			for (var i=0; i<this.length; i++)
				if(this.charAt(i)==n)
					positions.push(i);
			if(positions.length==0)
				return false;
			else
				return positions;
	},
	
	/*
	Method: getFirst
	Description: returns the first character of the string
	[Example]  
		> var s = 'some data';
		> // returns 's'
		> s.getFirst();
	[/Example]
	*/
	getFirst: function() {
		return this.charAt(0);
	},
	
	/*
	Method: getLast
	Description: returns the last character of the string
	[Example]  
	 	> var s = 'insert a string';
		> // returns 'g'
		> s.getLast();
	[/Example]
	*/
	getLast: function() {
		return this.charAt(this.length-1);
	},
	
	/*
	Method: camelize
	Description: returns a string camelized
	[Example]  
		> var s = 'a string';
		> // returns 'A StRiNg'
		> s = s.camelize();
	[/Example]
	*/
	camelize: function() {
		var s = '';
		for(var i=0; i<this.length; i++) {
			if(i%2 == 0) s+= this.charAt(i).upper();
			else s+= this.charAt(i).lower();
		}
		
		return s;
	},
	
	/*
	Method: upperFirst
	Description: converts the first char of the string to upper case
	[Example]  
	 	> var s = 'england';
		> // returns 'England'
		> s.upperFirst('s');
	[/Example]
	*/
	upperFirst: function() {
		return this.replace(this.charAt(0), this.charAt(0).upper());	
	}
			  
});

/*
	Filename: string_php.js
	
	[Description]
		Contains prototypes to apply some php string methods to String constructor
	[/Description]
	
	Contains: Class String
	
	[Summary]
		String ::: Extends the native String object with many methods that works like PHP string methods
	[/Summary]
*/
/*
	Class: String
	
	[Description]
		Extends the native String object with many methods that works like PHP string methods. 
		These are indispensable into server-side applications, but their functionalities can be very useful into client-side
		applications too.  This String extension allows you to use PHP string methods with Javascript.
	[/Description]
	
	Extends: Class String

	[Methods]
		stripTags -- strips all HTML tags from the string
		addslashes -- adds slashes before all ' or " characters
		nl2br -- replaces all newline characters with the XHTML 'br' tags
		br2nl -- replaces all XHTML 'br' tags with the newline characters
		stripslashes -- strips slashes before all ' or " characters
		htmlEntities -- converts all possible characters into HTML entities
		html_entity_decode -- converts all HTML entities into normal characters
		trim -- trims a string
		ltrim -- deletes all spaces at beginning of the string
		rtrim -- deletes all spaces at the end of the string
	[/Methods]
*/
String.implement({
	
	/*
	Method: stripTags
	Description: strips all HTML tags from the string
	[Example]  
		> var s = '<table><tr><td>some data</td></tr></table>';
		>
		> // returns 'some data'
		> s.stripTags();
	[/Example]
	*/
	stripTags: function () {
		return this.replace(/<([^>]+)>/g,'');
	},

	/*
	Method: addslashes
	Description: adds slashes before all ' or " characters
	[Example]  
		> var s = 'som'e da'ta'
		>
		> // s is now 'som\'e da\'ta'
		> s.addslashes(); 
	[/Example]
	*/
	addslashes: function() {
		return this.replace(/['"]/g, function(match){
			return ('\\' + match.charAt(0) + match.charAt(1));
		});
	},
	
	/*
	Method: nl2br
	Description: replaces all newline characters with the XHTML 'br' tags
	[Example]  
		> var s = 'this is \n some data \n'; 
		>
		> // s is now: 'this is <br /> some data <br />'
		> s.nl2br(); 
	[/Example]
	*/
	nl2br: function() {
		return this.replace(/\\n/g, '<br />');
	},
	
	/*
	Method: br2nl
	Description: replaces all XHTML 'br' tags with the newline characters
	[Example]  
		> var s = 'this is <br /> some data <br />'; 
		>
		> // s is now: 'this is \n some data \n'
		> s.br2ln(); 
	[/Example]
	*/
	br2nl: function() {
		return this.replace(/<br>|<br\/>|<br \/>/g, '\n');
	},
	
	/*
	Method: stripslashes
	Description: strips slashes before all ' or " characters
	[Example]  
		> s = 'som\'e dat\'a';
		>
		> // s is now 'som'e dat'a'
		> s.stripslashes();
	[/Example]
	*/
	stripslashes: function() {
		return this.replace(/\\['"]{1,}/g, function(match){
			return (match.charAt(1));
		});
	},
	
	/*
	Method: htmlEntities
	Description: converts all possible characters into HTML entities
	[Example]  
		> var s = '<code><i></i></code>';
		>
		> // returns '&lt;code&gt;&lt;i&gt;&lt;/i&gt;&lt;/code&gt;';
		> s.htmlEntities();
	[/Example]
	*/
	htmlEntities: function () {
		return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
	},
	
	/*
	Method: html_entity_decode
	Description: converts all HTML entities into normal characters
	[Example]  
		> var s = '&lt;code&gt;&lt;i&gt;some data&lt;/i&gt;&lt;/code&gt;';
		>
		> // returns '<code><i>some data</i></code>';
		> s.html_entity_decode();
	[/Example]
	*/
	html_entity_decode: function() {
	  var txt = new Element("textarea");
	  txt.set('html', this.replace(/</g,"&lt;").replace(/>/g,"&gt;"));
	  return txt.get('value');
	},
	
	/*
	Method: trim
	Description: trims a string
	[Example]  
		> var s = '		some data		';
		>
		> // returns 'some data'
		> s.trim();
	[/Example]
	*/
	trim: function() {
		return this.replace(/^\s+|\s+$/g,'');
	},
	
	/*
	Method: ltrim
	Description: deletes all spaces at beginning of the string
	[Example]  
		> var s = '		some data';
		>
		> // returns 'some data'
		> s.trim();
	[/Example]
	*/
	ltrim: function() {
		return this.replace(/^\s+/g,'');
	},
	
	/*
	Method: rtrim
	Description: deletes all spaces at the end of the string
	[Example]  
		> var s = 'some data		';
		>
		> // returns 'some data'
		> s.trim();
	[/Example]
	*/
	rtrim: function() {
		return this.replace(/\s+$/g,'');
	}
});

/*
	Filename: array.js
	
	[Description]
		Contains prototypes which extend the Array constructor
	[/Description]
	
	Contains: Class Array, Function print_r
	
	Requires: type.js
	
	[Summary]
		Array ::: Contains prototypes which extend the Array constructor
		print_r --- prints all array elements like the PHP print_r function
	[/Summary]
*/
/*
	Class: Array
	[Description]
		Extends the native Array object with many methods that aren't contained in the core Javascript language and allows you to
		execute many useful functionalities with the target array or with its items.
		It also contains a function called print_r, that works as the PHP print_r function.  
	[/Description]
	
	Extends: Class Array
	
	[Methods]
		print_r -- prints all array elements and nested like the PHP print_r function
		numSort -- orders the array elements (asc)
		rNumSort -- orders the array elements (desc)
		getFirst -- returns the first item of the array
		getLast -- returns the last item of the array
		asItem -- tests if the array contains the passed in item
		asItems -- tests if the array contains all the passed in items
		stripItem -- removes the passed in item from the array
		stripItems -- removes all the passed in items from the array
		poOf -- returns an array which represents the positions of all the occurences of the passed in item
	[/Methods]
*/
Array.implement({
	
	/*
	Method: print_r
	Description: prints all array elements and nested array like the PHP print_r function
	[Arguments]
		results :: optional. the element to put the results to. If false returns the result string.
	[/Arguments]
	[Example]  
		> var a = ['a', 'b', 'c', ['d', 'e', 10]];
		> a.print_r('box');
		>
		> // returns
		> Array (
		>   [0] => 'a'
		>   [1] => 'b'
		>   [2] => 'c'
		>   [3] => Array (
    	>     [0] => 'd'
    	>     [1] => 'e'
		>     [2] => 10
  		>   ) 
		> )
	[/Example]
	*/
	print_r: function(results) {
		var r = 'Array ( ' + '<br />';
		var spaces = '&nbsp;&nbsp;&nbsp;&nbsp;';
		var tinyspaces = '&nbsp;&nbsp;';
		
		var _obj = function(r, el, index) {
			var r = '';
			var el = el;
			var index = index;
			r += spaces + '[' + index + ']' + ' => ';
			r += 'Object { ' + '<br />';
			for(var p in el) {
				if($string(p))
					r += spaces + tinyspaces + '[' + p + ']' + ' => \'' + el[p] + '\'<br />';
				else if($int(p))
					r += spaces + tinyspaces + '[' + p + ']' + ' => ' + el[p] + '<br />';
			};
			r += spaces + '}' + '<br />';
			return r;
		};
		
		this.each(function(el, index) {
			if($array(el)){ 
				r += tinyspaces + '[' + index + ']' + ' => ';
				r += 'Array ( ' + '<br />';
				el.each(function(e, i) {
					if($string(e))
						r += spaces + '[' + i + ']' + ' => \'' + e + '\'<br />';
					else if($int(e))
						r += spaces + '[' + i + ']' + ' => ' + e + '<br />';
					else if($object(e))
						r += _obj(r, e, i);
				});
				r += tinyspaces + ')' + '<br />';
			}
			else {
				if($string(el))
					r += tinyspaces + '[' + index + ']' + ' => \'' + el + '\'<br />';
				else if($int(el))
					r += tinyspaces + '[' + index + ']' + ' => ' + el + '<br />';
				else if($object(el))
					r += _obj(r, el, index);
			}
		});
		r += ')';
		return (results) ? $(results).set('html', r) : r;
	},
	
	/*
	Method: numSort
	Description: orders the array elements (asc)
	[Example]  
		> var a = [44, 68, 32];
	    > // returns [32, 44, 68]
		> a.numSort();
	[/Example]
	*/
	numSort: function() {
		return this.sort(function(a, b) {return a-b;});
	},
	
	/*
	Method: rNumSort
	Description: orders the array elements (desc)
	[Example]  
		> var a = [44, 68, 32];
		> // returns [68, 44, 32]
		> a.rNumSort();
	[/Example]
	*/
	rNumSort: function() {
		return this.sort(function(a, b) {return b-a;});
	},
	
	/*
	Method: getFirst
	Description: returns the first item of the array
	[Example]  
		>  var a = [44, 68, 32];
		> // returns 44
		> a.getFirst();
	[/Example]
	*/
	getFirst: function() {
		return this[0];
	},
			
	/*
	Method: getLast
	Description: returns the last item of the array
	[Example]  
		>  var a = [44, 68, 32];
		> // returns 32
		> a.getLast();
	[/Example]
	*/
	getLast: function() {
		return this[this.length-1];
	},
	
	/*
	Method: asItem
	Description: tests if the array contains the passed in item
	[Arguments]
		item :: the item to search
	[/Arguments]
	[Example]  
 		> var a = [44, 68, 32];
		> // returns true
		> a.asItem(44);
	[/Example]
	*/
	asItem: function(item) {
		var a = new Array();
		for(var z=0; z<this.length; z++)
			if(this[z] == item) return true;
		return false;
	},
	
	/*
	Method: asItems
	Description: tests if the array contains all the passed in items
	[Arguments]
		items :: the items to search
	[/Arguments]
	[Example]  
		> var a = [44, 68, 32];
		> // returns true
		> a.asItems(44, 32);
	[/Example]
	*/
	asItems: function() {
		var a = new Array();
				
		for(var i=0; i<arguments.length; i++)
			if(this.asItem(arguments[i]))
				a.push(arguments[i]);
				
		return (a.length >= arguments.length);
	},
	
	/*
	Method: stripItem
	Description: removes the passed in item from the array
	[Arguments]
		item :: the item to remove
	[/Arguments]
	[Example]  
		> var a = [44, 68, 32];
		> // returns [68, 32]
		> a.stripItem(44);
	[/Example]
	*/
	stripItem: function() {
		var a = new Array();
		for(var z=0; z<this.length; z++)
			for(var i=0; i<arguments.length; i++)
				if(this[z] != arguments[i])
					a.push(this[z]);
		return a;	
	},
	
	/*
	Method: stripItems
	Description: removes all the passed in items from the array
	[Arguments]
		items :: the items to remove
	[/Arguments]
	[Example]  
		> var a = [44, 68, 32];
		> // returns [32]
		> a.stripItems(44, 68);
	[/Example]
	*/
	stripItems: function() {
		var a = new Array();
		for(var w=0; w<this.length; w++) a.push(this[w]);
				
		for(var z=0; z<this.length; z++) {
			for(var i=0; i<arguments.length; i++)
				if(this[z] == arguments[i])
					a = a.stripItem(arguments[i]);
		}	
		return a;	
	},
	
	/*
	Method: posOf
	Description: returns an array which represents the positions of all the occurences of the passed in item
	[Arguments]
		item :: the item to search
	[/Arguments]
	[Example]  
		> var a = [44, 68, 32, 44];
		> // returns [0, 3]
		> a.posOf(44);
	[/Example]
	*/
	posOf: function(item) {
		var a = new Array();
				
		for(var z=0; z<this.length; z++)
			if(this[z] == item)
				a.push(z);
		return a;
	}
});

/*
	Function: print_r
	Description: prints all array elements like the PHP print_r function
	[Arguments]
		array :: the array to print
		element :: the element where the array will be print
	[/Arguments]
	[Example]  
		> var a = ['a', 'b', 'c', ['d', 'e', 10]];
		> print_r(a, 'box');
		>
		> // returns
		> Array (
		>   [0] => 'a'
		>   [1] => 'b'
		>   [2] => 'c'
		>   [3] => Array (
    	>     [0] => 'd'
    	>     [1] => 'e'
		>     [2] => 10
  		>   ) 
		> )
	[/Example]
*/
function print_r(v, results) {
	if($array(v)) v.print_r(results);
}

/*
	Filename: table_rows.js
	
	[Description]
		Extends the Table Class adding the capability to customize the the table rows
	[/Description]
	
	Contains: Class Table
	
	Requires: constructors.js
	
	[Summary]
		Table ::: Custom Class to customize tables
	[/Summary]
*/
/*
	Class: Table
	
	[Description]  
		Contains methods that allows you to customize table rows.
		You can also set the mouseover and click events for the table rows: the table datas will result more accessible.
	[/Description]
	
	[Note]
 		The strings represent the colors you pass to each Table method MUST BE UPPERCASED.
	[/Note]
	
	Extends: Class Table
	
	Constructor: new Table (element)
	
	[Properties] 
		element - the element. Must be a table element
	[/Properties]
	
	[Methods]
		zebra -- sets two alternate colors to the table rows
		overClickRows -- changes the background-color of the table rows on mouseover and click events
		overRows -- changes the background-color of the table rows on mouseover event
		clickRows -- changes the background-color of the table rows on click event
	[/Methods]
*/
Table.implement({

	/*
	Method: zebra
	Description: sets two alternate colors to the table rows
	[Arguments]
		color1 :: one of the two color of the zebra
		color2 :: one of the two color of the zebra
		firstLine :: optional. if true the first line won't be styled
	[/Arguments]
	[Example]  
		>  var tb = new Table('tb');
		>  tb.zebra('#CCCCCC','#666666');
		>  // also styling the first line
		>  tb.zebra('#CCCCCC','#666666', true);
	[/Example]
	*/
	zebra: function(color1, color2, firstLine) {
		if(this.element.get('tag') != 'table')  return false;
		
		this.cells.each(function(cell, index) {
			if(firstLine && index == 0)	return;		
			(index%2 == 0) ? cell.setStyle('background-color', color1) : cell.setStyle('background-color', color2);
			/*if(index%2 == 0)
				cell.setStyle('background-color', color1);
			else
				cell.setStyle('background-color', color2);*/
		});
	},
	
	/*
	Method: overClickRows
	Description: changes the background-color of the table rows on mouseover and click events
	[Arguments]
		overcolor :: the color that the rows take on mouseover event
		clickcolor :: the color that the rows take on click event
	[/Arguments]
	[Example]  
		>  tb.overClickRows('blue', 'green');
	[/Example]
	*/
	overClickRows: function(overcolor, clickcolor) {
		this.rows.each(function(row, index) {
			row.addEvent('mouseover', function() {
				if(!this.init) this.init = row.getElement('td').getStyle('background-color');
				if(row.getElement('td').getStyle('background-color').toUpperCase() != clickcolor)
					row.getElements('td').setStyle('background-color', overcolor);
			});
			
			row.addEvent('mouseout', function() {
				if(row.getElement('td').getStyle('background-color').toUpperCase() != clickcolor)
					row.getElements('td').setStyle('background-color', this.init);
			});
			
			row.addEvent('click', function() {
				if(row.getElement('td').getStyle('background-color').toUpperCase() != clickcolor)
					row.getElements('td').setStyle('background-color', clickcolor);
				else
					row.getElements('td').setStyle('background-color', this.init);
			});
		});
	},
	
	/*
	Method: overRows
	Description:  changes the background-color of the table rows on mouseover event
	[Arguments]
		overcolor :: the color that the rows take on mouseover event
	[/Arguments]
	[Example]  
		>  tb.overRows('#0066FF');
	[/Example]
	*/
	overRows: function(color) {
		this.rows.each(function(row, index) {
			row.addEvent('mouseover', function() {
				this.init = row.getElement('td').getStyle('background-color');
				row.getElements('td').setStyle('background-color', color);
			});
			
			row.addEvent('mouseout', function() {
				row.getElements('td').setStyle('background-color', this.init);
			});
		});
	},
	
	/*
	Method: clickRows
	Description: changes the background-color of the table rows on click event
	[Arguments]
		clickcolor :: the color that the rows take on click event
	[/Arguments]
	[Example]  
		>  tb.clickRows('#0066FF');
	[/Example]
	*/
	clickRows: function(color) {
		this.rows.each(function(row, index) {
			row.addEvent('click', function() {
				if(!this.initBc) this.initBc = row.getElement('td').getStyle('background-color').toUpperCase();
				if(row.getElement('td').getStyle('background-color').toUpperCase() != this.initBc)
					row.getElements('td').setStyle('background-color', this.initBc);
				else
					row.getElements('td').setStyle('background-color', color);	
			});
		});
	}
});

/*
	Filename: table_cells.js
	
	[Description]
		Extends the Table Class adding the capability to customize the the table cells
	[/Description]
	
	Contains: Class Table
	
	Requires: constructors.js
	
	[Summary]
		Table ::: Custom Class to customize tables
	[/Summary]
*/
/*
	Class: Table
	
	[Description]  
		Contains methods that allows you to customize table cells.
	[/Description]
	
	[Note]
 		The strings represent the colors you pass to each Table method MUST BE UPPERCASED.
	[/Note]
	
	Extends: Class Table
	
	Constructor: new Table (element)
	
	[Properties] 
		element - the element. Must be a table element
	[/Properties]
	
	[Methods]
		zebraCells -- sets two alternate colors to the table cells
		overClickCells -- changes the background-color of the table cells on mouseover and click events
		overCells -- changes the background-color of the table cells on mouseover event
		clickCells -- changes the background-color of the table cells on click event
	[/Methods]
*/
Table.implement({
	
	/*
	Method: zebraCells
	Description: sets two alternate colors to the table cells
	[Arguments]
		color1 :: one of the two color of the zebra
		color2 :: one of the two color of the zebra
		firstLine :: optional. if true the first line won't be styled
	[/Arguments]
	[Example]  
		>  // doesn't style the first line
		>  tb.zebraCells('#C17878', '#7389AE', true);
		>  // styles the first line too
		>  tb.zebraCells('#C17878', '#7389AE');
	[/Example]
	*/
	zebraCells: function(color1, color2, firstLine) {
		this.rows.each(function(row, index) {
			if(firstLine && index==0) return;
			row.getElements('td').each(function(td, i) {
				if(i%2 == 0)
					(index%2 == 0) ? td.setStyle('background-color', color1) : td.setStyle('background-color', color2);
				else
					(index%2 == 0) ? td.setStyle('background-color', color2) : td.setStyle('background-color', color1);
			});
		});
	},
	
	/*
	Method: overClickCells
	Description: changes the background-color of the table cells on mouseover and click events
	[Arguments]
		overcolor :: the color that the cells take on mouseover event
		clickcolor :: the color that the cells take on click event
	[/Arguments]
	[Example]  
		>  tb.overClickCells('blue', 'green');
	[/Example]
	*/
	overClickCells: function(color, clickcolor) {
		this.rows.each(function(row, index) {
			row.getElements('td').each(function(td,index) {
				td.addEvent('mouseover', function() {
					if(!this.init) this.init = td.getStyle('background-color');
					if(td.getStyle('background-color').toUpperCase() != clickcolor)
						td.setStyle('background-color', color);
				});
				
				td.addEvent('mouseout', function() {
					if(td.getStyle('background-color').toUpperCase() != clickcolor)
						td.setStyle('background-color', this.init);
				});
				
				td.addEvent('click', function() {
					if(td.getStyle('background-color').toUpperCase() != clickcolor)
						td.setStyle('background-color', clickcolor);
					else
						td.setStyle('background-color', this.init);
				});
			});
		});
	},
	
	/*
	Method: overCells
	Description:  changes the background-color of the table cells on mouseover event
	[Arguments]
		overcolor :: the color that the cells take on mouseover event
	[/Arguments]
	[Example]  
		>  tb.overCells('#0066FF');
	[/Example]
	*/
	overCells: function(color) {
		this.rows.each(function(row, index) {
			row.getElements('td').each(function(td,index) {
				td.addEvent('mouseover', function() {
					this.init = td.getStyle('background-color');
					td.setStyle('background-color', color);
				});
				
				td.addEvent('mouseout', function() {
					td.setStyle('background-color', this.init);
				});
			});
		});
	},
	
	/*
	Method: clickCells
	Description: changes the background-color of the table cells on click event
	[Arguments]
		clickcolor :: the color that the cells take on click event
	[/Arguments]
	[Example]  
		>  tb.clickCells('#0066FF');
	[/Example]
	*/
	clickCells: function(color) {
		this.rows.each(function(row, index) {
			row.getElements('td').each(function(td,index) {
				td.addEvent('click', function() {
					if(!this.initC) this.initC = row.getElement('td').getStyle('background-color').toUpperCase();
					if(td.getStyle('background-color').toUpperCase() != this.initC)
						td.setStyle('background-color', this.initC);
					else
						td.setStyle('background-color', color);
				});
			});
		});
	}
});

/*
	Filename: table_cols.js
	
	[Description]
		Extends the Table Class adding the capability to customize the the table columns
	[/Description]
	
	Contains: Class Table
	
	Requires: constructors.js
	
	[Summary]
		Table ::: Custom Class to customize tables
	[/Summary]
*/
/*
	Class: Table
	
	[Description]  
		Contains methods that allows you to customize table columns.
	[/Description]
	
	[Note]
 		The strings represent the colors you pass to each Table method MUST BE UPPERCASED.
	[/Note]
	
	Extends: Class Table
	
	Constructor: new Table (element)
	
	[Properties] 
		element - the element. Must be a table element
	[/Properties]
	
	[Methods]
		zebraCols -- sets two alternate colors to the table columns
		overClickCols -- changes the background-color of the table columns on mouseover and click events
		overCols -- changes the background-color of the table columns on mouseover event
		clickCols -- changes the background-color of the table columns on click event
	[/Methods]
*/
Table.implement({	
	
	/*
	Method: zebraCols
	Description: sets two alternate colors to the table columns
	[Arguments]
		color1 :: one of the two color of the zebra
		color2 :: one of the two color of the zebra
		firstLine :: if true the first line won't be styled
	[/Arguments]
	[Example]  
		>  // doesn't style the first line
		>  tb.zebraCols('#C17878', '#7389AE', true);
		>  // styles the first line too
		>  tb.zebraCols('#C17878', '#7389AE');
	[/Example]
	*/
	zebraCols: function(color1, color2, firstLine) {
		this.rows.each(function(row, index) {
			if(firstLine && index==0) return;
			row.getElements('td').each(function(td, i) {
				if(i%2 == 0)
					td.setStyle('background-color', color1);
				else
					td.setStyle('background-color', color2);
			});
		});
	},
				
	/*
	Method: overClickCols
	Description: changes the background-color of the table columns on mouseover and click events
	[Arguments]
		overcolor :: the color that the columns take on mouseover event
		clickcolor :: the color that the columns take on click event
		firstLine :: boolean. If true the first line wont'be styled
	[/Arguments]
	[Example]  
		>  tb.overClickCols('blue', 'green', true);
	[/Example]
	*/
	overClickCols: function(color, clickcolor, firstLine) {
		this.colors = [];
		this.rows.each(function(row, indexRow) {
			
		  row.getElements('td').each(function(td, indexTd) {
			 
			var i = indexTd;
			
			if(!this.colors[indexRow]) { 
				this.colors[indexRow] = []; 
			}
			this.colors[indexRow][indexTd] = td.getStyle('background-color').toUpperCase();
			td.store('color', this.colors[indexRow][indexTd]);
			
			
			td.addEvent('mouseover', function() {
				td.getParent().getParent().getElements('tr').each(function(r, indexR) {
					r.getElements('td').each(function(c, indexC) {
						if(indexC == i)
							if((firstLine) && (indexR==0))
								c.setStyle('background-color', c.retrieve('color'));
							else if(c.getStyle('background-color').toUpperCase() != clickcolor)
								c.setStyle('background-color', color);
							else
								c.setStyle('background-color', clickcolor);
					}, this);
				}, this);
			}.bind(this));
			
			td.addEvent('mouseout', function() {
				td.getParent().getParent().getElements('tr').each(function(r, indexR) {
					r.getElements('td').each(function(c, indexC) {
						if(indexC == i)
							if(c.getStyle('background-color').toUpperCase() == color)
								c.setStyle('background-color', c.retrieve('color'));
					}, this);
				}, this);
			}.bind(this));
				
			td.addEvent('click', function() {
				td.getParent().getParent().getElements('tr').each(function(r, indexR) {
					r.getElements('td').each(function(c, indexC) {
						if(indexC == i)
							if((firstLine) && (indexR!=0))
							  if(c.getStyle('background-color').toUpperCase() != clickcolor)
								  c.setStyle('background-color', clickcolor);
							  else
								  c.setStyle('background-color', c.retrieve('color'));
							else if((!firstLine))
								 if(c.getStyle('background-color').toUpperCase() != clickcolor)
								  c.setStyle('background-color', clickcolor);
							  else
								  c.setStyle('background-color', c.retrieve('color'));
					}, this);
				}, this);
			}.bind(this));
				
		  }, this);		
		}, this);
	},
	
	/*
	Method: overCols
	Description:  changes the background-color of the table columns on mouseover event
	[Arguments]
		overcolor :: the color that the columns take on mouseover event
		firstLine :: boolean. If true the first line wont'be styled
	[/Arguments]
	[Example]  
		>  tb.overCols('#0066FF', true);
	[/Example]
	*/
	overCols: function(color, firstLine) {
		this.colors = [];
		this.rows = this.element.getElements('tr');
		this.rows.each(function(row, indexRow) {
			
			  row.getElements('td').each(function(td, indexTd) {
				 
				var i = indexTd;
				if(!this.colors[indexRow]) { 
					this.colors[indexRow] = []; 
				}
				this.colors[indexRow][indexTd] = td.getStyle('background-color').toUpperCase();
				td.store('color', this.colors[indexRow][indexTd]);
				
				td.addEvent('mouseover', function() {
					td.getParent().getParent().getElements('tr').each(function(r, indexR) {
						r.getElements('td').each(function(c, indexC) {
							if(indexC == i)
								if((firstLine) && (indexR==0))
									c.setStyle('background-color', c.retrieve('color'));
								else if(c.getStyle('background-color').toUpperCase() != color)
									c.setStyle('background-color', color);
								else
									c.setStyle('background-color', c.retrieve('color'));
						}, this);
					}, this);
				}.bind(this));
				
				td.addEvent('mouseout', function() {
					td.getParent().getParent().getElements('tr').each(function(r, indexR) {
						r.getElements('td').each(function(c, indexC) {
							if(indexC == i)
								if(c.getStyle('background-color').toUpperCase() == color)
									c.setStyle('background-color', c.retrieve('color'));
						}, this);
					}, this);
				}.bind(this));
			  
			}, this);		
		}, this);
	},
	
	/*
	Method: clickCols
	Description:  changes the background-color of the table columns on click event
	[Arguments]
		clickcolor :: the color that the columns take on click event
		firstLine :: boolean. If true the first line wont'be styled
	[/Arguments]
	[Example]  
		>  tb.clickCols('#0066FF', true);
	[/Example]
	*/
	clickCols: function(color, firstLine) {
		this.colors = [];
		this.rows = this.element.getElements('tr');
		this.rows.each(function(row, indexRow) {
			
		  row.getElements('td').each(function(td, indexTd) {
			 
			var i = indexTd;
			if(!this.colors[indexRow]) { 
				this.colors[indexRow] = []; 
			}
			this.colors[indexRow][indexTd] = td.getStyle('background-color').toUpperCase();
			td.store('color', this.colors[indexRow][indexTd]);
			
			td.addEvent('click', function() {
				td.getParent().getParent().getElements('tr').each(function(r, indexR) {
					r.getElements('td').each(function(c, indexC) {
						if(indexC == i)
							if((firstLine) && (indexR==0))
								c.setStyle('background-color', c.retrieve('color'));
							else if(c.getStyle('background-color').toUpperCase() != color)
								c.setStyle('background-color', color);
							else
								c.setStyle('background-color', c.retrieve('color'));
					}, this);
				}, this);
			}.bind(this));
		  
		  }, this);		
		}, this);
	}
});

/*
	Filename: make_table.js
	
	[Description]
		Contains the Make.Table Class, the Array.makeTable method and the make_table function to easily create tables from arrays of arrays
	[/Description]
	
	Contains: Class Make.Table, Array.makeTable, Function make_table
	
	Requires: constructors.js
	
	[Summary]
		Make.Table ::: Custom Class to create tables
		Array ::: Contains the makeTable method
		make_table --- Creates tables like Make.Table Class but as a function
	[/Summary]
*/
/*
	Class: Make.Table
	
	[Description]
		Allows you to create tables from arrays of arrays.
	[/Description]
	
	[Note]
		Each item of the external array is a row of the table.
		Each item of inner arrays is a cell of the table. 
		If you want to set the styles and the properties of a row, you can pass an object with 'styles' and 'properties' as properties.
	[/Note]
	
	Extends: Class Make
	
	Constructor: new Make.Table (id, rows, options)
	
	[Properties] 
		id - the table id
		rows - the array that contains table elements. The last item can be an object represents the styles of row
		options - an object. See below
	[/Properties]
	
	[Options]
		content : the cells content type. Can be 'text' (default) or 'html'
	[/Options]
	
	[Methods]
		make -- makes a table from an array of elements. Returns the table
	[/Methods]
*/
Make.Table = new Class({
					   
	Extends: Make,
			
	initialize: function(id, rows, options) {
		this.idKey = id;
		this.setOptions(options);
		this.rows = rows;
	},
	
	/*
	Method: make
	Description: makes a table from an array of elements. Returns the table
	[Example]  
		> // create the rows
		> var items = [
		>   ['a', 'b', 'c'],
		>   ['d', 'e', 'f']
		> ];
		>
		> // returns the table
		> var madetable = new Make.Table('madetable', items).make();
		>
		> // injects the table in the page 
		> madetable.injectInside($('box'));
		>
		> // this is the table created by Make.Table
		> <table id='makedtable'>
		> <tr>
		> <td> a </td>
		> <td> b </td>
		> <td> c </td>
		> </tr>
		> <tr>
		> <td> d </td>
		> <td> e </td>
		> <td> f </td>
		> </tr>
		> </table> 
	[/Example]
	*/
	make: function() {
		if(!$(this.idKey)) {
			this.table = new Element('table', {
				'id': this.idKey
			});
			
			var table = this.table;
			var tbody = new Element('tbody').inject(table);
			var first = this.first;
			var l = this.rows.length-1;
			
			this.rows.each(function(row, index) {
				var tr = new Element('tr').inject(tbody);
				row.each(function(cell) {
					if($object(cell)) {
						if(cell.styles) tr.setStyles(cell.styles);
						if(cell.properties) tr.setProperties(cell.properties);
					}
					else new Element('td').set(this.options.content, cell).inject(tr);	
				}, this);
			}, this);
			
			return this.table;
		}
		else return;
	}
});

/*
	Class: Array
	
	Description:  Contains the makeTable method
	
	Extends: Class Array
	
	[Methods]
		makeTable -- Array method to make table from an array of elements. Returns the table
	[/Methods]
*/
Array.implement({
	/*
	Method: makeTable
	Description: Array method to make table from an array of elements. Returns the table
	[Arguments] 
		id :: the table id
		options :: the Make.Table options
	[/Arguments]
	[Example]  
		> // create the rows
		> var items = [
		>   ['a', 'b', 'c'],
		>   ['d', 'e', 'f']
		> ];
		>
		> // returns the table
		> var madetable = items.makeTable('madetable'); 
	[/Example]
	*/
	makeTable: function(id, options) {
		return new Make.Table(id, this, options).make();
	}
});

/*
	Function: make_table
	Description: Creates tables like Make.Table Class but as a function
	[Arguments]
		id :: the table id
		rows :: the array that contains table elements. The last item can be an object represents the styles of row
		options - the Make.Table options
	[/Arguments]
	[Example]  
		> // create the rows
		> var items = [
		>   ['a', 'b', 'c'],
		>   ['d', 'e', 'f']
		> ];
		>
		> // returns the table
		> var madetable =  make_table('madetable', items); 
	[/Example]
*/
function make_table(id, rows, options) {
	return new Make.Table(id, rows, options).make();
}

/*
	Filename: make_list.js
	
	[Description]
		Contains the Make.List Class, the Array.makeList method and the make_list function to easily create lists from arrays
	[/Description]
	
	Contains: Class Make.List, Array.makeList, Function make_list
	
	Requires: constructors.js, type.js
	
	[Summary]
		Make.List ::: Custom Class to create lists
		Array ::: Contains the makeList method
		make_list --- Creates lists like Make.List Class but as a function
	[/Summary]
*/
/*
	Class: Make.List
	
	[Description]
		Allows you to create either unordered and oreder lists from array. You can also create lists of lists and list of links.
	[/Description]
	
	[Note]
		If the current element of the main array is a string, it will be added at the main list as a nornal list item.
		If it is an array of strings, it will be added as a sub-list.
		If it is an object, you can pass as properties: 'text' (the text of the link), 'href' and linkOptions, which is an object containing the attributes/events/styles of the link. In this way you can create a link item in the list.
	[/Note]
	
	Extends: Class Make
	
	Constructor: new Make.List (id, items, options)
	
	[Properties] 
		id - the list id
		items - the array that contains the list elements
		options - an object. See below
	[/Properties]
	
	[Options]
		type : the type of the list. Can be 'ul' (default) or 'ol'
		content : the items content type. Can be 'text' (default) or 'html'
		listOptions : an object containing the attributes/events/styles of the list
	[/Options]
	
	[Methods]
		make -- makes a list from an array of elements. Returns the list
	[/Methods]
*/
Make.List = new Class({
					  
	Extends: Make,
					  
	options: {
		type: 'ul',
		listOptions: {}
	},
	
	initialize: function(id, items, options) {
		this.idKey = id;
		this.items = items;
		this.setOptions(options);
	},
	
	/*
	Method: make
	Description: makes a list from an array of elements. Returns the list
	[Example]  
		> var items = [
		>  'home',
		>  {text:'download', href:'/download', linkOptions: {'title': 'download', 'target': '_blank'}},
		>  'examples',
		>  {text:'documentation', href:'/documentation/constructors', linkOptions: {'title': 'docs', 'target': '_blank'}}
		> ];
		>
		> var list = new Make.List('list', items, {listOptions: listOptions, content: 'html'}).make();
		> list.inject(element);
	[/Example]
	*/
	make: function() {
		if(!$(this.idKey)) {
			
			if(this.options.type != 'ul' && this.options.type != 'ol') this.options.type = 'ul';
			
			this.ul = new Element(this.options.type, $merge(this.options.listOptions, {'id': this.idKey}));
			
			this.items.each(function(li) {
				if($array(li)) {
					li.each(function(item, i) {
						var mul = new Element('ul');
						if($object(item)) {
							var a = new Element('a', $merge(item.linkOptions, {
								'href': item.href
							})).set(this.options.content, item.text);
							var lis = new Element('li');
							a.inject(lis);
							lis.inject(mul);
							mul.inject(this.ul);
						}			 
						else {
							var mli = new Element('li').set(this.options.content, item).inject(mul);
							mul.inject(this.ul);
						}
					}, this);
				}
				else if($object(li)) {
					var a = new Element('a', $merge(li.linkOptions, {
						'href': li.href
					})).set(this.options.content, li.text);
					var li = new Element('li');
					a.inject(li);
					li.inject(this.ul);
				}
				else {
					var li = new Element('li').set(this.options.content, li);
					li.inject(this.ul);
				}
			}, this);
			
			return this.ul;
		}
		else return;
	}
});

/*
	Class: Array
	
	Description:  Contains the makeList method
	
	Extends: Class Array
	
	[Methods]
		makeList -- Array method to make lists from an array of elements. Returns the list
	[/Methods]
	
	[Properties]
		id - the list id
		options - an object. See above Make.List options
	[/Properties]
*/
Array.implement({
		
		/*
		Method: makeList
		Description: Array method to make lists from an array of elements. Returns the list
		[Arguments]
			id :: the list id
			options :: the Make.List options
		[/Arguments]
		*/
		makeList: function(id, options) {
			return new Make.List(id, this, options).make();
		}
});

/*
	Function: make_list
	Description: Creates lists like Make.List Class but as a function
	[Arguments]
		id :: the list id
		items :: the array that contains the list elements
		options :: the Make.List options
	[/Arguments]
*/
function make_list(id, items, options) {
		return new Make.List(id, items, options).make();
}

/*
	Filename: make_select.js
	
	[Description]
		Contains the Make.Select Class, the Array.makeSelect method and the make_select function to easily create custom Select Elements
	[/Description]
	
	Contains: Class Make.Select, Array.makeSelect, Function make_select
	
	Requires: constructors.js, type.js
	
	[Summary]
		Make.Select ::: Custom Class to create lists of Option Elements nested in a main Select Element
		Array ::: Contains the makeSelect method
		make_select --- Creates Select elements like Make.Select Class but as a function
	[/Summary]
*/
/*
	Class: Make.Select
	
	[Description]
		Allows you to easily create lists of Option Elements nested in a main Select Element.
	[/Description]
	
	Extends: Class Make
	
	Constructor: new Make.Select (id, items, properties)
	
	[Properties] 
		id - the select id
		items - the array that contains the option elements. If an item is an array of strings, the first item will become an Optgroup element, and the others will become normal Option elements nested into this Optgroup.
		options - an object. See below
	[/Properties]
	
	[Options]
		content : the options content type. Can be 'text' (default) or 'html'
		properties : an object containing the select properties
	[/Options]
	
	[Methods]
		make -- makes a Select element from an array of strings. Returns the Select
	[/Methods]
*/
Make.Select = new Class({
						
	Extends: Make,
	
	options: {
		properties: {}
	},
			
	initialize: function(id, items, options) {
		this.idKey = id;
		this.items = items;
		this.setOptions(options);
	},
	
	/*
	Method: make
	Description: makes a Select element from an array of strings. Returns the Select
	[Example]  
		> var items = [
		>  ['Microsoft', 'IE6', 'IE7'],
		>  ['Mozilla', 'Firefox', 'Sunbird'],
		>  ['Mac', 'Safari'],
		>  ['Opera', '9.x', '8.x']
		> ];
		>
		> // creates the select with nested options and custom properties
		> var select = new Make.Select('select', items, {properties: {title:'browsers'}}).make();
	[/Example]
	*/
	make: function() {
		if(!$(this.idKey)) {
			this.select = new Element('select', $extend({'id': this.idKey}, this.options.properties));
			
			this.items.each(function(item) {
				if($array(item)) {
					item.each(function(i, index) {
						if(index == 0) {
							this.group = new Element('optgroup', { 'label': i });
							this.select.adopt(this.group);
						}
						else {
							var opt = new Element('option', {
								'label': i,
								'value': i
							}).set(this.options.content, i);
							opt.inject(this.group);	
						}
					}, this);	
				}					 
				else {
					var option = new Element('option', {
						'label': item,
						'value': item
					}).set(this.options.content, item);
					option.inject(this.select);
				}
			}, this);
			
			return this.select;
		}
		else return;
	}
});

/*
	Class: Array
	
	Description:  Contains the makeSelect method
	
	Extends: Class Array
	
	[Methods]
		makeSelect -- Array method to make Select elements from an array of strings. Returns the Select
	[/Methods]
*/
Array.implement({
	/*
	Method: makeSelect
	Description: Array method to make Select elements from an array of strings. Returns the Select
	[Arguments] 
		id - the select id
		options - the Make.Select options
	[/Arguments]
	*/
	makeSelect: function(id, options) {
		return new Make.Select(id, this, options).make();
	}
});

/*
	Function: make_select
	Description: Creates Select elements like Make.Select Class but as a function
	[Arguments]
		id :: the select id
		items :: the array that contains the option elements. If an item is an array of strings, the first item will become an Optgroup element, and the others will become normal Option elements nested into this Optgroup.
		options :: the Make.Select options
	[/Arguments]
*/
function make_select(id, items, options) {
	return new Make.Select(id, items, options).make();
}

/*
	Filename: custom_base.js
	
	[Description] 
		Contains a powerful wrapper which allows to create modal, draggable and fully-customizable boxes.
		It is used to create the Custom.Alert, Custom.Confirm and Custom.Prompt Classes 
	[/Description]
	
	Contains: Class Custom
	
	Requires: overlay.js
	
	[Summary]
		Custom ::: A powerful wrapper which allows you to create modal boxes
	[/Summary]
*/
/*
	Class: Custom
	
	[Description]  
		The Custom Class is a powerful wrapper which allows you to create modal boxes.
	 	You can completely customize this boxes in all its features: styles, zones, events, texts and many more.
		You can decide which zones must be injected and which mustn't be.
		In addiction, you can decide the overlay light, whether enabling drag or not, the drag opacity, 
		whether enabling fade transitions or not.
	[/Description]
	
	Implements: Overlay
	
	Constructor: new Custom (title, text, options)
	
	[Properties] 
		title - a string represents the title of the box
		text - a string represents the content text of the box
		options - optional. an object which permits to customize the box
	[/Properties]
	
	[Options]
		enable : an object which allows to decide which zones and events must be created
		zones : an object which contains the class names of the box zones
		buttons : an object which contains the buttons css classes
		text : an object which contains the buttons contents
		height : the box height. Default is 'auto'
		width : the box width. Default is '300px'
		opacify : if true the box appears and disappears with an opacity transition. Default is true
		content : 'text' or 'html', the content types of the box title, the box box and the box buttons. Default is 'text'
		draggable : if true the box will be draggable. Default is true
		dragOpacity : if true the box will be affected by a fade effect on drag
		adjustStyles : if true adjusts the position of the box on window resize. Default is true
		promptType : an object which contains the prompt settings
		overlay : the type of the overlay. 'lighten', 'darken', color or false (default)
	[/Options]
	
	>> enable:
		[List]
			[li] closeButton: if true the close button will be added
			[li] confirmButton: if true the confirm button will be added
			[li] cancelButton: if true the cancel button will be added
			[li] textBox: if true the prompt will be displayed (can be an input or a textarea)
	 		[li] onConfirm: if true the onConfirm event will be fired
			[li] onCancel: if true the onCancel event will be fired
		[/List]
	
	>> zones:
		[List]
			[li] box: is the box that contains the other zones
			[li] head: is the header of the box. (contains the title)
			[li] body: is the main content of the box
	 		[li] buttonBox: the zone which contains the confirm and cancel buttons
			[li] promptBox: the zone which contains the prompt (input or textarea) 
		[/List]
	
	>> buttons:
		[List]
			[li] confirmButton: the confirm button class name
			[li] closeButton: the close button class name
			[li] cancelButton: the cancel button class name
		[/List]
		
	>> text:
		[List]
			[li] confirmButtonText: the text of the confirm button. Defaults to 'OK'
			[li] closeButtonText: the text of the close button. Defaults to 'X'
			[li] cancelButtonText: the text of the cancel button. Defaults to 'Cancel'
		[/List]
		
	>> promptType:
		[List]
			[li] box: 'single' or 'multi'. Default is 'single'
			[li] lines: if box is 'multi' represents the number of lines. Default is 4 
			[li] startValue: the start value. Default is ''
			[li] search: where to search your value. Can be 'google', 'yahoo', 'wikipedia' or false (default)
			[li] target: indicates if open another window for the custom search. Can be 'new' (default) or 'same'
		[/List]
		
	[Events]
		onConfirm : function fired when users confirm
		onCancel : function fired when users cancel
	[/Events]
	
	[Methods]
		create -- creates the custom box
		setText -- sets the text of the custom box
		setTitle -- sets the title of the custom box
		setIDs -- sets the id value respectively for the box, the overlay and the fullpage at once
	[/Methods]
*/
var Custom = new Class({
		
	Implements: [Options, Events, Overlay],
		
	options: {
		height: 'auto',
		width: '300px',
		overlay: false,
		opacify: true,
		draggable: true,
		dragOpacity: false,
		adjustStyles: true,
		promptType: {
			box: 'single',
			lines: 1,
			startValue: '',
			search: false,
			target: 'new'
		},
		content: 'text',
		enable: {
			closeButton: true,
			confirmButton: true,
			cancelButton: true,
			onConfirm: true,
			onCancel: true,
			textBox: false
		},
		text: {
			confirmButtonText: 'OK',
			closeButtonText: 'X',
			cancelButtonText: 'Cancel'
		},
		zones: {
			box: null,
			head: null,
			body: null,
			buttonBox: '',
			promptBox: ''
		},
		buttons: {
			closeButton: '',
			confirmButton: '',
			cancelButton: ''
		},
		onConfirm: $empty,
		onCancel: $empty
	},
	
	initialize: function(title, text, options) {
		this.title = title;
		this.text = text;
		this.setOptions(options);
		this.box = new Element('div', {
			'id': 'customBox',
			'styles': {
				'position': (!Browser.Engine.trident4) ? 'fixed' : 'absolute',
				'top': '50%',
				'left': '50%',
				'z-index': 1000,
				'height': this.options.height,
				'width': this.options.width
			}
		});
		this.createOverlay('customBoxOverlay', this.options.overlay);
		this.createFullPage('customBoxfullpage');
		this.mechanize();
		this.box.set('tween', {duration: 1000});
		this.dragOptions = {container: this.fullpage};
		if(this.options.dragOpacity) 
			this.dragOptions = $merge(this.dragOptions, {
				onDrag: function(element) {
					element.set('opacity', 0.6);
				},
				onComplete: function(element) {
					element.set('opacity', 1);
				}
			});
	},
	
	/*
	Method: create
	Description:  creates the custom box
	[Example]  
		> var cc = new Custom.Confirm('custom confirm', 'Do you want to submit?', 
		> {box:'ccbox', head: 'cchead', body: 'ccbody'});
		> 
		> cc.create();
	[/Example]
	*/
	create: function() {
		this.customize();
	},
	
	mechanize: function() {
		if(this.options.zones['box']) this.box.addClass(this.options.zones['box']);
		
		this.head = new Element('div').injectInside(this.box);
		if(this.options.zones.head) this.head.addClass(this.options.zones['head']);
		this.head.set(this.options.content, this.title);
		
		if(this.options.enable.closeButton) {
			this.closebutton = new Element('a', {'id': 'customCloseButton', 'class': this.options.buttons.closeButton}).injectInside(this.head);
			this.closebutton.setProperty('href', '#');
			this.closebutton.set(this.options.content, this.options.text.closeButtonText);
			this.closebutton.addEvent('click', function(event) {
				event.preventDefault();
			});
			this.closebutton.addEvent('click', this.cancelRemove.bind(this));
		}
		
		this.content = new Element('div').injectInside(this.box);
		if(this.options.zones.body) this.content.addClass(this.options.zones['body']);
		this.content.set(this.options.content, this.text);
		
		if(this.options.enable.textBox) {	
			this.promptbox = new Element('div', {
				'id': 'customPromptTextBox', 'class': this.options.zones.promptBox}).inject(this.box);
			this.form = new Element('form', {'id': 'customPromptTextForm', 'action': '#'}).inject(this.promptbox);
			
			switch(this.options.promptType.box) {
				case 'single':  this.input = new Element('input', {'type': 'text', 'value': this.options.promptType.startValue}).inject(this.form);
								break;
				case 'multi':	this.input = new Element('textarea', {'value': this.options.promptType.startValue}).inject(this.form).inject(this.form).setProperty('rows', this.options.promptType.lines);
								break;
			}
			
			switch(this.options.promptType.search) {
				case 'google':
					this.addEvent('onConfirm', function(event) {
						if(this.options.promptType.target == 'same')
							location.href = 'http://www.google.it/search?q=' + this.input.get('value');
						else if(this.options.promptType.target == 'new')
							window.open('http://www.google.it/search?q=' + this.input.get('value'));
					});
					break;
				case 'yahoo':
					this.addEvent('onConfirm', function(event) {
						if(this.options.promptType.target == 'same')
							location.href = 'http://search.yahoo.com/search?p=' + this.input.get('value');
						else if(this.options.promptType.target == 'new')
							window.open('http://search.yahoo.com/search?p=' + this.input.get('value'));
					});
					break;
				case 'wikipedia':
					this.addEvent('onConfirm', function(event) {
						if(this.options.promptType.target == 'same')
							location.href = 'http://en.wikipedia.org/wiki/' + this.input.get('value');
						else if(this.options.promptType.target == 'new')
							window.open('http://en.wikipedia.org/wiki/' + this.input.get('value'));
					});
					break;
			}
		}
	
		this.closebox = new Element('div', {'id': 'customButtonBox', 'class': this.options.zones.buttonBox}).injectInside(this.box);
	
		if(this.options.enable.confirmButton) {
			this.button = new Element('a', {'id': 'customButton', 'class': this.options.buttons.confirmButton}).injectInside(this.closebox);
			this.button.setProperty('href', '#');
			this.button.set(this.options.content, this.options.text.confirmButtonText);
			this.button.addEvent('click', function(event) {
				event.preventDefault();
			});
			
			this.button.addEvent('click', this.confirmRemove.bind(this));
		}
		
		if(this.options.enable.cancelButton) {
			this.cancelButton = new Element('a', {'id': 'customCancelButton', 'class': this.options.buttons.cancelButton}).injectInside(this.closebox);
			this.cancelButton.setProperty('href', '#');
			this.cancelButton.set(this.options.content, this.options.text.cancelButtonText);
			this.cancelButton.addEvent('click', function(event) {
				event.preventDefault();
			});
			
			this.cancelButton.addEvent('click', this.cancelRemove.bind(this));
		}
	},
	
	customize: function() {
		if($(this.box.get('id')))  return;
		
		if(this.options.opacify)	this.box.set('opacity', 0);
		
		this.box.injectInside(this.fullpage);
		this.injectOverlay(true);
		
		var dimensions = this.dimensions = { 
			top: this.box.getSize().y/2,
			left: this.box.getSize().x/2,
			fullTop: this.fullpage.getSize().y.toInt()/2,
			fullLeft: this.fullpage.getSize().x.toInt()/2
		};
		
		this.box.setStyles({
			'margin-left': -dimensions.left,
			'margin-top': -dimensions.top,
			'top': dimensions.fullTop,
			'left': dimensions.fullLeft 
		});
		
		if(this.options.opacify)	this.box.fade('in');
		
		if(this.options.draggable) this.drag = new Drag.Move(this.box, this.dragOptions);
		
		if(this.options.adjustStyles) {
			this.newsizes = function() {
				this.box.setStyles({
					'top': window.getSize().y.toInt()/2,
					'left': window.getSize().x.toInt()/2
				});
				if(this.options.draggable) this.drag = new Drag.Move(this.box, this.dragOptions);
			};
			this.boundsizes = this.newsizes.bind(this);
			window.addEvent('resize', this.boundsizes);
		}
	},
	
	remove: function() {
		this.box.dispose();
		this.fullpage.dispose();
		this.removeOverlay();
		window.removeEvent('resize', this.boundsizes);
	},
	
	checkremove: function() {
		if(this.options.opacify) {
			this.box.fade('out');
			this.remove.delay(this.box.get('tween').options.duration.toInt(), this);
		}
		else {
			this.remove();
		}
	},
	
	confirmRemove: function() {
		if(this.options.enable.onConfirm) (this.input) ? this.fireEvent('onConfirm', this.input.get('value')) : this.fireEvent('onConfirm');
		this.checkremove();
	},
	
	cancelRemove: function() {
		if(this.options.enable.onCancel) this.fireEvent('onCancel');
		this.checkremove();
	},
	
	/*
	Method: setText
	Description:  sets the text of the custom box
	[Arguments]
		text :: the new content value. The content you can set depends on the 'content' options
	[/Arguments]
	[Example]  
		> // change the previous text
		> box.setText('Custom Alert/Confirm with some new text');
	[/Example]
	*/
	setText: function(text) {
		this.text = text;
		this.content.set(this.options.content, this.text);
		return this;
	},
	
	/*
	Method: setTitle
	Description:  sets the title of the custom box
	[Arguments]
		title :: the new title value. The content you can set depends on the 'content' options
	[/Arguments]
	[Example]  
		> // change the previous title
		> box.setTitle('A new Custom Alert/Confirm title');
	[/Example]
	*/
	setTitle: function(title) {
		this.title = title;	
		this.head.set(this.options.content, this.title);
		return this;
	},
	
	/*
	Method: setIDs
	Description:  sets the id value respectively for the box, the overlay and the fullpage at once
	[Arguments]
		box :: the new box id
		overlay :: the new overlay id
		fullpage :: the new fullpage id
	[/Arguments]
	[Example]  
		> box.setIDs('myNewBoxID', 'myNewOverlayID', 'myNewFullPageID');
	[/Example]
	*/
	setIDs: function(box, overlay, fullpage) {
		this.box.set('id', box);
		this.overlay.set('id', overlay);
		this.fullpage.set('id', fullpage);
	}
});

/*
	Filename: custom_windows.js
	
	[Description] 
		Contains three extensions for the Custom Class: Custom.Alert, Custom.Confirm and Custom.Prompt.
		They allow to create powerful, fully-customizable and flexible standard windows without overwriting
		the standard methods.
	[/Description]
	
	Contains: Class Custom.Alert, Class Custom.Confirm, Class Custom.Prompt
	
	Requires: custom_base.js
	
	[Summary]
		Custom.Alert ::: Class for creating customized alert boxes
		Custom.Confirm ::: Class for creating customized confirm boxes
		Custom.Prompt ::: Class for creating customized prompt boxes
	[/Summary]
*/
/*
	Class: Custom.Alert
	
	[Description]  
		Allows to create fully-customized alert, without overwriting the standard window.alert method.
		You can works with all Custom parameters and methods and you can have many different alerts in the
		same page as you want.
	[/Description]
	
	Extends: Custom
	
	Constructor: new Custom.Alert (title, text, options)
	
	[Properties] 
		title - a string represents the title of the alert
		text - a string represents the content text of the alert
		options - optional. an object which permits to customize the alert
	[/Properties]
	
	[Options]
		Custom options : all the Custom Options
	[/Options]
*/
Custom.Alert = new Class({
						   
	Extends: Custom,
						   
	options: {
		enable: {
			closeButton: true,
			confirmButton: true,
			cancelButton: false,
			onConfirm: false,
			onCancel: false
		}
	},
	
	initialize: function(title, text, options) {
		this.parent(title, text, options);
		this.setIDs('customAlertBox', 'customAlertOverlay', 'customAlertFullpage');
	}
});

/*
	Class: Custom.Confirm
	
	[Description]  
		Allows to create fully-customized confirm, without overwriting the standard window.confirm method.
		You can works with all Custom parameters and methods and you can have many different confirms in the
		same page as you want.
	[/Description]
	
	Extends: Custom
	
	Constructor: new Custom.Confirm (title, text, options)
	
	[Properties] 
		title - a string represents the title of the confirm
		text - a string represents the content text of the confirm
		options - optional. an object which permits to customize the confirm
	[/Properties]
	
	[Options]
		Custom options : all the Custom Options
	[/Options]
*/
Custom.Confirm = new Class({
						   
	Extends: Custom,
						   
	options: {
		enable: {
			closeButton: true,
			confirmButton: true,
			cancelButton: true,
			onConfirm: true,
			onCancel: true
		}
	},
	
	initialize: function(title, text, options) {
		this.parent(title, text, options);
		this.setIDs('customConfirmBox', 'customConfirmOverlay', 'customConfirmFullpage');
	}
});

/*
	Class: Custom.Prompt
	
	[Description]  
		Allows to create fully-customized prompt (single or multi), without overwriting the standard window.prompt method.
		You can works with all Custom parameters and methods and you can have many different prompts in the
		same page as you want.
	[/Description]
	
	Extends: Custom
	
	Constructor: new Custom.Prompt (title, text, options)
	
	[Properties] 
		title - a string represents the title of the prompt
		text - a string represents the content text of the prompt
		options - optional. an object which permits to customize the prompt
	[/Properties]
	
	[Options]
		Custom options : all the Custom Options
	[/Options]
*/
Custom.Prompt = new Class({
						   
	Extends: Custom,
						   
	options: {
		enable: {
			closeButton: true,
			confirmButton: true,
			cancelButton: true,
			onConfirm: true,
			onCancel: true,
			textBox: true
		}
	},
	
	initialize: function(title, text, options) {
		this.parent(title, text, options);
		this.setIDs('customPromptBox', 'customPromptOverlay', 'customPromptFullpage');
	}
});

/*
	Filename: smooth_scrolling.js
	
	[Description]
		Allows you to alterate the automatic process that displays the transition of all anchors situated in a page. 
		You can also specify the style options of transitions: this permits to make a lot of different animations!
	[/Description]
	
	Contains: Class SmoothScrolling
	
	[Summary]
		SmoothScrolling ::: smooth scrolls the anchor links
	[/Summary]
*/
/*
	Class: SmoothScrolling
	
	Description: smooth scrolls the anchor links
	
	Extends: Class Fx.Scroll
	
	Constructor: new SmoothScrolling (options)
	
	[Properties] 
		options - the Fx.Scroll options plus some other options
	[/Properties]
	
	[Options]
		links : a string which specify the links to apply the effect to. Default is 'a' (all anchors)
		preventDefault : if true the default will be prevented on click events
		wheelStops : if false the wheel movement doesn't cause the scroll stop. Default is true
	[/Options]
	
	[Methods]
		create -- creates the smooth scrolling for either all anchors of the page or only specified anchors
	[/Methods]
*/

var SmoothScrolling = new Class ({
								 
	Extends: Fx.Scroll,
	
	options: {
		links: 'a',
		preventDefault: false
	},
	   
	initialize: function(options) {
		this.parent(window, options);
		if(this.options.initialize) this.options.intialize.call(this);
	},
    
	/*
	Method: create
	Description:  creates the smooth scrolling for either all anchors of the page or only specified anchors
	[Example]  
		>  new SmoothScrolling({duration:1800, transition:Fx.Transitions.Bounce.easeOut}).create();
	[/Example]
	*/
    create: function() {
	 var targets = new Array();
	 var anchors = new Array();
	
	 $$('a').each(function(lnk, index) {
		if(lnk.name) targets.push(lnk);
	 });
				
	 $$(this.options.links).each(function(lnk, index) {
	 	if(lnk.href.test(/#\w+/)) {
			anchors.push(lnk);
			for(var i=0; i<targets.length; i++) {
				if(lnk.href.split('#')[1] == targets[i].name)
					lnk.targetName = targets[i].name;
					lnk.addEvent('click', this.makeScroll.bind(this, lnk));
					if(this.options.preventDefault) lnk.addEvent('click', function(event) { event.preventDefault(); });
			}
		}
	  }, this);
	},
	
	makeScroll: function(lnk) {
		this.start(0, $(document.body).getElement('a[name=' + lnk.targetName + ']').getTop());
	}
	
});

/*
	Filename: effects_base.js
	
	[Description] 
		Contains a collection of methods and utilities to work with effects based on Fx Classes.
	[/Description]
	
	[Credits]
		[li] some Fx Classes of the moo.rd Fx Repository are slightly inspired on those found in the Script.aculo.us library
	[/Credits]
	
	Contains: Class Fx, Class Element, Function fxToHash
	
	Requires: string.js
	
	[Summary]
		Fx ::: Extends the Fx Class for creating the moo.rd Effects Repository and fully-customizable effects
		Element ::: Adds Fx utility methods to the Element prototypes
		fxToHash --- Extends the Element.Properties Hash for using all the Fx effects as Element's dynamic shortcuts
	[/Summary]
*/
/*
	Class: Fx
	
	Description: Extends the Fx Class for creating the moo.rd Effects Repository and fully-customizable effects. 
	
	Extends: Class Fx
	
	[Methods]
		initStyles -- initializes all the styles you want for later usages
		removeAuto -- removes the 'auto' value from all the styles you want, to obtain a cross-browser feeling
		setPosition -- sets position's value to 'relative' if the element isn't positioned
	[/Methods]
*/
Fx.implement({
	
	/*
	Method: initStyles
	Description:  initializes all the styles you want for later usages
	*/
	initStyles: function() {
		this.init = {};
		$A(arguments).each(function(a) {
			if(a == 'opacity') this.init['opacity'] = this.element.get('opacity');
			else (this.element.getStyle(a).test('px')) ? this.init[a] = this.element.getStyle(a).toInt() : this.init[a] = this.element.getStyle(a);
		}, this);
		return this;
	},
	
	/*
	Method: removeAuto
	Description:  removes the 'auto' value from all the styles you want, to obtain a cross-browser feeling
	*/
	removeAuto: function() {
		if(!this.init) this.init = {};
		$A(arguments).each(function(a) {
			if(this.element.getStyle(a) == 'auto') { 
				this.element.setStyle(a, '0px');
				this.init[a] = 0;
			}
		}, this);
		return this;
	},
	
	/*
	Method: setPosition
	Description:  sets position's value to 'relative' if the element isn't positioned
	*/
	setPosition: function() {
		if(this.element.getStyle('position') == 'static') this.element.setStyle('position', 'relative');	
		return this;
	}
});

/*
	Class: Element
	
	[Description] 
		Adds Fx utility methods to the Element prototypes
	[/Description]
	
	Extends: Class Element
	
	[Methods]
		fx -- returns a determinate Fx instance you can pick out from the moo.rd Effects Repository
		effect -- sets a determinate Fx instance and start the effect immediately. Returns the element instead of fx method which returns an instance
		removeAuto -- removes the 'auto' value from all the styles you want of this element
	[/Methods]
*/	
Element.implement({
	
	/*
	Method: fx
	Description:  returns a determinate Fx instance you can pick out from the moo.rd Effects Repository
	[Arguments]
		eff :: the fx effect
		options :: optional. the effect options. Either if you use this argument or not, the instance will be the same
	[/Arguments]
	[Example]  
		> // use Fx.Fade
		> var fade = element.fx('fade');
		> fade.start('toggle');
		>  
		> // use Fx.Move
		> var move = element.fx('move', {duration:2000});
		> move.start(120, 58);
	[/Example]
	*/
	fx: function(eff, options) {
		if(!this.retrieve(eff)) this.store(eff, new Fx[eff.upperFirst()](this, options));
		return this.retrieve(eff);
	},
	
	/*
	Method: effect
	Description:  sets a determinate Fx instance and start the effect immediately. Returns the element instead of fx method which returns an instance
	[Arguments]
		eff :: the fx effect
		arguments :: the arguments to apply to the start method
	[/Arguments]
	[Example]  
		> // call an effect immediately
		> el.effect('fade');
		>
		> // set the instance options first
		> el.set('fade', {duration: 2000});
		> // call the effect later
		> el.effect('fade');
		> el.effect('fade', 'toggle');
		>
		> // move an element immediately
		> el.effect('move', 40, 440);
	[/Example]
	*/
	effect: function(fx) {
		this.get(fx).start.pass(Array.slice(arguments, 1), this.get(fx))();
		return this;
	},
	
	/*
	Method: removeAuto
	Description:  removes the 'auto' value from all the styles you want of this element.
	*/
	removeAuto: function() {
		$A(arguments).each(function(a) {
			if(this.element.getStyle(a) == 'auto') this.element.setStyle(a, '0px');
		}, this);
		return this;
	}
});

/*
	Function: fxToHash
	Description: Extends the Element.Properties Hash for using all the Fx effects as Element's dynamic shortcuts
	[Example]  
		> var el = $('element');
		>
		> // sets a Fx.Pulsate instance for later usage
		> el.set('pulsate', {times: 24});
		> // pulsate an element 24 times
		> el.effect('pulsate');
		>
		> // sets a Fx.SwitchOff instance an use it immediately
		> el.get('switchOff', {duration: 2000}).start();
	[/Example]
*/
var fxToHash = function(hash, effects) {
	Array.each(effects, function(fx, i) {
		var fx = fx.toString();
		var props = {
			set: function(options) {
				var tween = this.retrieve(fx);
				if (tween) tween.cancel();
				return this.eliminate(fx).store(fx + ':options', options);
			},
			
			get: function(options){
				if (options || !this.retrieve(fx)){
					if (options || !this.retrieve(fx + ':options')) this.set(fx, options);
					this.store(fx, new Fx[fx.upperFirst()](this, this.retrieve(fx + ':options')));
				}
				return this.retrieve(fx);
			}
		};
		hash.set(fx, props);
	});
};

/*
	Filename: effects_morph.js
	
	[Description] 
		Contains a collection of effects based on morph transitions, which alter the element's styles.
	[/Description]
	
	Contains: Class Fx.Fold, Class Fx.Shrink, Class Fx.Grow, Class Fx.Scale, Class Element
	
	Requires: effects_base.js
	
	[Summary]
		Fx.Fold ::: Closes an element like a folder
		Fx.Shrink ::: Shrinks the styles of an element
		Fx.Grow ::: Enlarges the styles of an element
		Fx.Scale ::: Alters the styles you want of an element following a given scale
		Element ::: Extends the Element Class with Fx shortcuts
		Element.Properties ::: Extends the Element.Properties Hash with effects_morph.js Fx effects
	[/Summary]
*/
/*
	Class: Fx.Fold
	
	[Description] 
		Closes an element like a folder
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Fold (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus 'mode'
	[/Properties]
	
	[Options]
		mode : the effect mode. Can be 'vertical' (height transition, default) or 'horizontal' (width transition)
	[/Options]
	
	[Methods]
		start -- starts the Fx.Fold effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Fold effect
	[Arguments]
		mode :: optional. the effect mode
	[/Arguments]
	[Example]  
		> var fx = new Fx.Fold('box');
		> fx.start();
	[/Example]
*/
Fx.Fold = new Class({
					
	Extends: Fx.Morph,
	
	options: {
		mode: 'vertical'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.element.setStyle('overflow', 'hidden');
	},
	
	start: function(mode) {
		var mode = mode || this.options.mode;
		switch(mode) {
			case 'vertical':  var styles = { first: {'height':0}, last: {'width': 0}};
					   break;
			case 'horizontal':  var styles = { first: {'width':0}, last: {'height': 0}};
					   break;
		};
		
		var superMethod = arguments.callee;
		this.parent(styles.first).chain(
			function() { this.parentOf(superMethod, styles.last); }
		);
	}		
});

/*
	Class: Fx.Shrink
	
	[Description] 
		Shrinks the styles of an element
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Shrink (element, options)
	
	[Properties] 
		element - the element
		options - the Fx options
	[/Properties]
	
	[Methods]
		start -- starts the Fx.Shrink effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Shrink effect
	[Example]  
		> var fx = new Fx.Shrink('box');
		> fx.start();
	[/Example]
*/
Fx.Shrink = new Class({
					  
	Extends: Fx.Morph,
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.initStyles('fontSize');
		this.element.setStyles({overflow: 'hidden'});
	},
	
	start: function() {
		this.parent({
			'height': 0,
			'width': 0,
			'font-size': [this.init.fontSize, 0]
		});
	}		
});

/*
	Class: Fx.Grow
	
	[Description] 
		Enlarges the styles of an element
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Grow (element, options, values)
	
	[Properties] 
		element - the element
		options - the Fx options
		values - an object with 'height', 'width' and 'fontsize' keys as final values
	[/Properties]
	
	[Methods]
		start -- starts the Fx.Grow effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Grow effect
	[Arguments]
		values :: optional. the same as the values option. You can use the properties you want, with no obligation to use all of them
	[/Arguments]
	[Example]  
		> var fx = new Fx.Grow('box');
		> fx.start();
	[/Example]
*/
Fx.Grow = new Class({
					
	Extends: Fx.Morph,
	
	initialize: function(element, options, values) {
		this.parent(element, options);
		this.values = values || {height: 200, width: 200, fontsize: 10};
		this.element.setStyle('overflow', 'hidden');
	},
	
	start: function(values) {
		var values = values || this.values;
		this.parent({
			'height': [0, values.height || this.values.height],
			'width': [0, values.width || this.values.width],
			'font-size': [0, values.fontsize || this.values.fontsize]
		});
	}	
});

/*
	Class: Fx.Scale
	
	[Description] 
		Alters the styles you want of an element following a given scale
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Scale (element, options)
	
	[Properties] 
		element - the element
		options - the Fx options plus 'scale'
	[/Properties]
	
	[Options]
		scale : the scale. Default is 1.3
	[/Options]
	
	[Methods]
		start -- starts the Fx.Scale effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Scale effect
	[Arguments]
		properties :: an array which represents the properties to apply the scale to
		scale :: optional. The scale value
	[/Arguments]
	[Example]  
		> var fx = new Fx.Scale('box');
		> fx.start(['width', 'height'], 1.4);
	[/Example]
*/
Fx.Scale = new Class({
					
	Extends: Fx.Morph,
	
	options: {
		scale: 1.3
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.element.setStyle('overflow', 'hidden');
	},
	
	start: function(properties, scale) {
		var scale = scale || this.options.scale;
		if($type(properties)=='array') {
			var obj = {};
			properties.each(function(p, i) {
				obj[p] = [this.element.getStyle(p).toInt(), this.element.getStyle(p).toInt()*scale];
			}, this);
			this.parent(obj);
		}
	}	
});

/*
	Class: Element
	
	[Description] 
		Extends the Element Class with Fx shortcuts. 
		All these methods accept the same arguments of the relative Fx effect (obviously without the element)
	[/Description]
	
	Extends: Class Element
	
	[Methods]
		fold -- returns an Fx.Fold instance
		shrink -- returns an Fx.Shrink instance
		grow -- returns an Fx.Grow instance
		scale -- returns an Fx.Scale instance
	[/Methods]
*/	
Element.implement({
	
	/*
	Method: fold
	Description:  returns an Fx.Fold instance
	*/
	fold: function(options) {
		return new Fx.Fold(this, options);	
	},
	
	/*
	Method: shrink
	Description:  returns an Fx.Shrink instance
	*/
	shrink: function(options) {
		return new Fx.Shrink(this, options);	
	},
	
	/*
	Method: grow
	Description:  returns an Fx.Grow instance
	*/
	grow: function(options, values) {
		return new Fx.Grow(this, options, values);	
	},
	
	/*
	Method: scale
	Description:  returns an Fx.Scale instance
	*/
	scale: function(options) {
		return new Fx.Scale(this, options);	
	}
});

/*
	Hash: Element.Properties
	Description: Extends the Element.Properties Hash for using the effects_morph.js Fx Classes as Element's dynamic shortcuts with the Element.effect method
*/
fxToHash(Element.Properties, ['fold', 'shrink', 'grow', 'scale']);

/*
	Filename: effects_fade.js
	
	[Description] 
		Contains a collection of effects based on fade transitions, for all fade needs.
	[/Description]
	
	Contains: Class Fx.Bubble, Class Fx.Fade, Class Fx.DropOut, Class Fx.Squish, Class Fx.Puff, Class Element
	
	Requires: effects_base.js
	
	[Summary]
		Fx.Bubble ::: Smoothly fades and close an element horizontally or vertically
		Fx.Fade ::: Smoothly fades the element in, out or toggle. Provides a similar functionality to Element.fade but as Class
		Fx.DropOut ::: Smoothly drops an element out, either down or up
		Fx.Squish ::: Smoothly resizes an element with a 'squish' transition
		Fx.Puff ::: Smoothly fades an element with a 'puff' transition
		Element ::: Extends the Element Class with Fx shortcuts
		Element.Properties ::: Extends the Element.Properties Hash with effects_fade.js Fx effects
	[/Summary]
*/
/*
	Class: Fx.Bubble
	
	[Description] 
		Smoothly fades and close an element horizontally or vertically
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Bubble (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus 'mode'
	[/Properties]
	
	[Options]
		mode : the effect mode. Can be 'vertical' (height transition, default) or 'horizontal' (width transition)
	[/Options]
	
	[Methods]
		start -- starts the Fx.Bubble effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Bubble effect
	[Arguments]
		mode :: optional. the effect mode
	[/Arguments]
	[Example]  
		> var fx = new Fx.Bubble('box');
		> fx.start();
	[/Example]
*/
Fx.Bubble = new Class({
					   
	Extends: Fx.Morph,
	
	options: {
		mode: 'vertical',
		duration: 3000
	},
					   
	initialize: function(element, options) {
		this.parent(element, $merge(this.options, options));
		this.element.setStyle('overflow', 'hidden');
	},
	
	start: function(mode) {
		var mode = mode || this.options.mode;
		var styles = {'font-size': 0, 'opacity': 0};
		switch(mode) {
			case 'vertical':
				this.parent($merge({'height': 0}, styles));
				break;
			case 'horizontal':
				this.parent($merge({'width': 0}, styles));
				break;
		}
	}
});

/*
	Class: Fx.Fade
	
	[Description] 
		Smoothly fades the element in, out or toggle. Provides a similar functionality of Element.fade but as Class
	[/Description]
	
	Extends: Fx.Tween
	
	Constructor: new Fx.Fade (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options
	[/Properties]
	
	[Methods]
		start -- starts the Fx.Fade effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Fade effect
	[Arguments]
		where :: a string which can be 'in', 'out' or 'toggle' (default)
	[/Arguments]
	[Example]  
		> var fx = new Fx.Fade('box');
		> // fade in
		> fx.start('in');
		> // fade out
		> fx.start('out');
		> // fade toggle
		> fx.start('toggle');
	[/Example]
*/
Fx.Fade = new Class({
					
	Extends: Fx.Tween,
	
	initialize: function(element, options) {
		this.parent(element, options);
	},
	
	start: function(where) {
		switch(where) {
			case 'in': this.parent('opacity', 1); 
					   break;
			case 'out': this.parent('opacity', 0); 
					   break;
			case 'toggle': 
			default: this.parent('opacity', (this.element.get('opacity') == 0) ? 1 : 0); 
					   break;
		}
	}
});

/*
	Class: Fx.DropOut
	
	[Description] 
		Smoothly drops an element out, either down or up
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.DropOut (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus some others
	[/Properties]
	
	[Options]
		size : how far the element will be dropped. Default is 40
		where : the direction of the effect. Can be 'down' (default) or 'up'
	[/Options]
	
	[Methods]
		start -- starts the Fx.DropOut effect
	[/Methods]

	Method: start
	Description:  starts the Fx.DropOut effect
	[Arguments]
		where :: optional. Identical to the where option
	[/Arguments]
	[Example]  
		>  var fx = new Fx.DropOut('box', {where:'up', size:140});
		>  fx.start();
	[/Example]
*/
Fx.DropOut = new Class({
					   
	Extends: Fx.Morph,
	
	options: {
		size: 40,
		where: 'down'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.setPosition().initStyles('top').removeAuto('top');
	},
	
	start: function(where) {
		var where = where || this.options.where;
		switch(where) {
			case 'down':
				var fullTop = this.init.top + this.options.size;
				break;
			case 'up':
				var fullTop = this.init.top - this.options.size;
				break;
		}
		this.parent({
			'top': fullTop,
			'opacity': 0
		});
	}
});

/*
	Class: Fx.Squish
	
	[Description] 
		Smoothly resizes an element with a 'squish' transition
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Squish (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options
	[/Properties]
	
	[Methods]
		start -- starts the Fx.Squish effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Squish effect
	[Example]  
		>  var fx = new Fx.Squish('box', {duration:2000});
		>  fx.start();
	[/Example]
*/
Fx.Squish = new Class({
					  
	Extends: Fx.Morph,
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.initStyles('fontSize').setPosition();
		this.element.setStyles({overflow: 'hidden'});
	},
	
	start: function() {
		this.parent({
			'height': 0,
			'width': 0,
			'opacity': 0,
			'font-size': [this.init.fontSize, 0]
		});
	}		
});

/*
	Class: Fx.Puff
	
	[Description] 
		Smoothly fades an element with a 'puff' transition
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Puff (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus 'increase'
	[/Properties]
	
	[Options]
		increase : The amount for increasing css properties. Default is 1.3
	[/Options]
	
	[Methods]
		start -- starts the Fx.Puff effect
	[/Methods]

	Method: start
	Description:  starts the Fx.Puff effect
	[Arguments]
		increase :: optional. The amount for increasing css properties
	[/Arguments]
	[Example]  
		>  var fx = new Fx.Puff('box', {increase: 1.6});
		>  fx.start();
	[/Example]
*/
Fx.Puff = new Class({
					
	Extends: Fx.Morph,
	
	options: {
		increase: 1.3
	},
					
	initialize: function(element, options) {
		this.parent(element, options);
		this.initStyles('height', 'width', 'fontSize').setPosition();
		this.element.setStyles({overflow: 'hidden'});
	},
	
	start: function(increase) {
		var increase = increase || this.options.increase;
		this.parent({
			'height': [this.init.height*increase],
			'width': [this.init.width*increase],
			'font-size': [this.init.fontSize*increase],
			'opacity': 0
		}).chain(function() { this.element.setStyle('display', 'none'); });
	}			
});

/*
	Class: Element
	
	[Description] 
		Extends the Element Class with Fx shortcuts. 
		All these methods accept the same arguments of the relative Fx effect (obviously without the element)
	[/Description]
	
	Extends: Class Element
	
	[Methods]
		bubble -- returns an Fx.Bubble instance
		fading -- returns an Fx.Fade instance
		dropOut -- returns an Fx.DropOut instance
		squish -- returns an Fx.Squish instance
		puff -- return an Fx.Puff instance
	[/Methods]
*/	
Element.implement({
	
	/*
	Method: bubble
	Description:  returns an Fx.Bubble instance
	*/
	bubble: function(options) {
		return new Fx.Bubble(this, options);	
	},
	
	/*
	Method: fading
	Description:  returns an Fx.Fade instance (note that this method is called 'fading' and doesn't overwrite the 'fade' method)
	*/
	fading: function(options) {
		return new Fx.Fade(this, options);	
	},
	
	/*
	Method: dropOut
	Description:  returns an Fx.DropOut instance
	*/
	dropOut: function(options) {
		return new Fx.DropOut(this, options);	
	},
	
	/*
	Method: squish
	Description:  returns an Fx.Squish instance
	*/
	squish: function(options) {
		return new Fx.Squish(this, options);	
	},
	
	/*
	Method: puff
	Description:  returns an Fx.Puff instance
	*/
	puff: function(options) {
		return new Fx.Puff(this, options);	
	}
});

/*
	Hash: Element.Properties
	Description: Extends the Element.Properties Hash for using the effects_fade.js Fx Classes as Element's dynamic shortcuts with the Element.effect method
*/
fxToHash(Element.Properties, ['bubble', 'fading', 'dropOut', 'squish', 'puff']);

/*
	Filename: effects_move.js
	
	[Description] 
		Contains a collection of effects based on the elements movement.
	[/Description]
	
	Contains: Class Fx.Shake, Class Fx.Move, Class Fx.Rumble, Class Fx.ScrollOut, Class Element
	
	Requires: effects_base.js
	
	[Summary]
		Fx.Shake ::: Shakes the element for a determinate number of times horizontally or vertically
		Fx.Move ::: Moves the element wherever you want
		Fx.Rumble ::: Enables a particular drag mode on the element
		Fx.ScrollOut ::: Scrolls an element out of his viewport
		Element ::: Extends the Element Class with Fx shortcuts
		Element.Properties ::: Extends the Element.Properties Hash with effects_move.js Fx effects
	[/Summary]
*/
/*
	Class: Fx.Shake
	
	[Description] 
		Shakes the element for a determinate number of times horizontally or vertically
	[/Description]
	
	Extends: Fx.Tween
	
	Constructor: new Fx.Shake (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus the following
	[/Properties]
	
	[Options]
		mode : the effect mode. Can be 'vertical' (height/top transition, default) or 'horizontal' (width/left transition)
		size : how far the element will be shaken in each direction. Default is 10
		times : how many tmes the element will be shaken. Default is 14  
	[/Options]
	
	[Methods]
		start -- starts the Fx.Shake effect
	[/Methods]

	Method: start
	Description: starts the Fx.Shake effect
	[Arguments]
		mode :: optional. the effect mode
	[/Arguments]
	[Example]  
		> var fx = new Fx.Shake('box');
		> fx.start();
	[/Example]
*/
Fx.Shake = new Class({
					 
	Extends: Fx.Tween,
	
	options: {
		mode: 'vertical',
		size: 10,
		link: 'chain',
		times: 14
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		switch(this.options.mode) {
			case 'horizontal': this.prop = 'left';
					  break;
			case 'vertical': this.prop = 'top';
					  break;
		};
		this.setPosition();
		this.element.setStyles({'overflow': 'hidden'});
		this.initStyles('top', 'left').removeAuto('top', 'left');
	},
	
	start: function(mode) {
		if(!mode) (this.options.mode == 'horizontal') ? this.prop = 'left' : this.prop = 'top';
		if(mode == 'vertical') this.prop = 'top';
		if(mode == 'horizontal') this.prop = 'left';
		for(var i=0; i<this.options.times; i++) {
			this.parent(this.prop, (i%2 == 0) ? this.options.size : -this.options.size);
		}
		this.parent(this.prop, 0);
	}
});

/*
	Class: Fx.Move
	
	[Description] 
		Moves the element wherever you want
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Move (element, options)
	
	[Properties] 
		options - the Fx Options
	[/Properties]
	
	[Methods]
		start -- starts the Fx.Move effect
	[/Methods]

	Method: start
	Description: starts the Fx.Move effect
	[Arguments]
		top :: the value of the top direction
		left :: the value of the left direction
	[/Arguments]
	[Example]  
		> var fx = new Fx.Move('box');
		> fx.start(20, 400);
	[/Example]
*/
Fx.Move = new Class({
					
	Extends: Fx.Morph,				
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.setPosition().initStyles('top', 'left').removeAuto('top', 'left');
	},
	
	start: function(top, left) {
		if(!this.check(arguments.callee, top, left)) return this;
		return this.parent({
			'top': top,
			'left': left
		});
	}
});

/*
	Class: Fx.Rumble
	
	[Description] 
		Enables a particular drag mode on the element. When it will be released, an elastic transition will be fired
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Rumble (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options
	[/Properties]
	
	[Methods]
		start -- starts the Fx.Rumble effect
	[/Methods]

	Method: start
	Description: starts the Fx.Rumble effect
	[Example]  
		>  var fx = new Fx.Rumble('box');
		>  fx.start();
	[/Example]
	
	Method: detach
	Description: detaches the drag instance
	[Example]  
		>  fx.detach();
	[/Example]
*/
Fx.Rumble = new Class({
					  
	Extends: Fx.Morph,
	
	options: {
		duration: 800,
		transition: 'elastic:out'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.setPosition();
		this.initStyles('top', 'left', 'cursor').removeAuto('top', 'left');
		this.obj = {'top': this.init.top, 
					'left': this.init.left
		};
	},

	start: function() {
		this.element.setStyle('cursor', 'move');
		var top = this.init.top; var left = this.init.left;
		var superMethod = arguments.callee;
		
		(!this.drag) ?
		this.drag = new Drag.Move(this.element, {
				onComplete: function() { 
					this.parentOf(superMethod, this.obj); 
				}.bind(this)
		}) : this.drag.attach();	
	},
	
	detach: function() {
		if(this.drag) this.drag.detach();	
		this.element.setStyle('cursor', this.init.cursor);
	}	
});

/*
	Class: Fx.ScollOut
	
	[Description] 
		Scrolls an element out of his viewport
	[/Description]
	
	Extends: Fx.Tween
	
	Constructor: new Fx.ScrollOut (element, options)
	
	[Properties] 
		options - the Fx Options
	[/Properties]
	
	[Methods]
		start -- starts the Fx.ScrollOut effect
	[/Methods]

	Method: start
	Description: starts the Fx.ScrollOut effect
	[Arguments]
		where :: The direction. Can be 'up' (default), 'down', 'left' or 'right'. If you pass 'reset' the position will be resetted
	[/Arguments]
	[Example]  
		> var fx = new Fx.ScrollOut('box');
		> // scroll up
		> fx.start('up');
		> // scroll left
		> fx.start('left');
	[/Example]
*/
Fx.ScrollOut = new Class({
					
	Extends: Fx.Tween,		
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.setPosition();
		this.initStyles('top', 'left').removeAuto('top', 'left');
		this.wrapper = new Element('div', {
		'styles': {'overflow': 'hidden', 'width': this.element.getWidth(), 'position': 'relative'}}).wraps(this.element);
	},
	
	start: function(where) {
		if (!this.check(arguments.callee, where)) return this;
		if(where == 'up' || !where) return this.parent('top', -this.element.getHeight());
		if(where == 'down') return this.parent('top', this.element.getHeight());
		if(where == 'left') return this.parent('left', -this.element.getWidth());
		if(where == 'right') return this.parent('left', this.element.getWidth());
		if(where == 'reset') {
			if(this.element.getStyle('top').toInt() != this.init.top) return this.parent('top', this.init.top);
			if(this.element.getStyle('left').toInt() != this.init.left) return this.parent('left', this.init.left);	
		}
	}
});

/*
	Class: Element
	
	[Description] 
		Extends the Element Class with Fx shortcuts. 
		All these methods accept the same arguments of the relative Fx effect (obviously without the element)
	[/Description]
	
	Extends: Class Element
	
	[Methods]
		shake -- returns an Fx.Shake instance
		move -- returns an Fx.Move instance
		rumble -- returns an Fx.Rumble instance
		scrollOut -- returns an Fx.ScrollOut instance
	[/Methods]
*/	
Element.implement({
	
	/*
	Method: shake
	Description:  returns an Fx.Shake instance
	*/
	shake: function(options) {
		return new Fx.Shake(this, options);	
	},
	
	/*
	Method: move
	Description:  returns an Fx.Move instance
	*/
	move: function(options) {
		return new Fx.Move(this, options);	
	},
	
	/*
	Method: rumble
	Description:  returns an Fx.Rumble instance
	*/
	rumble: function(options) {
		return new Fx.Rumble(this, options);	
	},
	
	/*
	Method: scrollOut
	Description:  returns an Fx.ScrollOut instance
	*/
	scrollOut: function(options) {
		return new Fx.ScrollOut(this, options);	
	}
});

/*
	Hash: Element.Properties
	Description: Extends the Element.Properties Hash for using the effects_move.js Fx Classes as Element's dynamic shortcuts with the Element.effect method
*/
fxToHash(Element.Properties, ['shake', 'move', 'rumble', 'scrollOut']);

/*
	Filename: effects_extra.js
	
	[Description] 
		Contains a collection of miscellanous effects.
	[/Description]
	
	Contains: Class Fx.Pulsate, Class Fx.SwitchOff, Class Fx.Gradient, Class Element
	
	Requires: effects_base.js
	
	[Summary]
		Fx.Pulsate ::: Pulsates the element for a determinate number of times
		Fx.SwitchOff ::: Switch an element off vertically or horizontally
		Fx.Gradient ::: Transition the background-color or the color of an element how many times you want
		Element ::: Extends the Element Class with Fx shortcuts
		Element.Properties ::: Extends the Element.Properties Hash with effects_extra.js Fx effects
	[/Summary]
*/
/*
	Class: Fx.Pulsate
	
	[Description] 
		Pulsates the element for a determinate number of times
	[/Description]
	
	Extends: Fx.Tween
	
	Constructor: new Fx.Pulsate (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus the following
	[/Properties]
	
	[Options]
		times : how many tmes the element will be pulsated. Default is 14  
	[/Options]
	
	[Methods]
		start -- starts the Fx.Pulsate effect
	[/Methods]

	Method: start
	Description: starts the Fx.Pulsate effect
	[Arguments]
		last :: optional. the last value of the opacity. Default is 1.
	[/Arguments]
	[Example]  
		> var fx = new Fx.Pulsate('box');
		> fx.start();
	[/Example]
*/
Fx.Pulsate = new Class({
					 
	Extends: Fx.Tween,
	
	options: {
		duration: 200,
		link: 'chain',
		times: 14
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
	},
	
	start: function(last) {
		var last = ($type(last) == 'number') ? last : 1;
		for(var i=0; i<this.options.times; i++) {
			this.parent('opacity', (i%2 == 0) ? 0 : 1);
		}
		this.parent('opacity', last);
	}
});

/*
	Class: Fx.SwitchOff
	
	[Description] 
		Switch an element off vertically or horizontally
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.SwitchOff (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus the following
	[/Properties]
	
	[Options]
		mode : the effect mode. Can be 'vertical' (height transition, default) or 'horizontal' (width transition)
		switchDuration : the duration of the switch. Default is 100
	[/Options]
	
	[Methods]
		start -- starts the Fx.SwitchOff effect
	[/Methods]

	Method: start
	Description:  starts the Fx.SwitchOff effect
	[Arguments]
		mode :: optional. the effect mode
	[/Arguments]
	[Example]  
		> var fx = new Fx.SwitchOff('box');
		> fx.start();
	[/Example]
*/
Fx.SwitchOff = new Class({
					
	Extends: Fx.Morph,
	
	options: {
		mode: 'vertical',
		switchDuration: 100
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.element.setStyle('overflow', 'hidden');
	},
	
	start: function(mode) {
		var mode = mode || this.options.mode;
		switch(mode) {
			case 'vertical':  var last = {'height': 0};
					   break;
			case 'horizontal':  var last = {'width': 0};
					   break;
		};
		this.duration = this.options.duration;
		this.options.duration = this.options.switchDuration;
		
		var superMethod = arguments.callee;
		this.parent({'opacity': 0}).chain(
			function() { this.parentOf(superMethod, {'opacity': 1}); },
			function() { this.options.duration = this.duration; this.parentOf(superMethod, last); }
		);
	}		
});

/*
	Class: Fx.Gradient
	
	[Description] 
		Transition the background-color or the color of an element how many times you want
	[/Description]
	
	Extends: Fx.Tween
	
	Constructor: new Fx.Gradient (element, options)
	
	[Properties] 
		element - the element
		options - the Fx Options plus the following
	[/Properties]
	
	[Options]
		end : if true will be added a final transition which set the background-color to its original value
		gradient : the property to alter, can be 'background-color' (default) or 'color'
	[/Options]
	
	[Methods]
		start -- starts the Fx.Gradient effect
	[/Methods]

	Method: start
	Description: starts the Fx.Gradient effect
	[Arguments]
		colors :: an array of colors
		gradient :: optional. The property to alter, can be 'background-color' or 'color'
	[/Arguments]
	[Example]  
		> var fx = new Fx.Gradient('box');
		> // two transitions
		> fx.start(['#56617D', '#78ba91']);
		> // six transitions
		> fx.start(['#56617D', '#78ba91', '#8eaeaf', '#9a6f1b', '#a87aad', '#eeaba8']);
	[/Example]
*/
Fx.Gradient = new Class({
					 
	Extends: Fx.Tween,
	
	options: {
		duration: 1000,
		link: 'chain',
		end: true,
		gradient: 'background-color'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.initStyles('backgroundColor', 'color');
	},
	
	start: function(colors, gradient) {
		if(!gradient) var gradient = this.options.gradient;
		else if(gradient != 'background-color' && gradient != 'color') var gradient = 'background-color';
		var superMethod = arguments.callee;
		var length = colors.length-1;
		colors.each(function(color, i) {
			this.parentOf(superMethod, [gradient, color]);
			if(i == length && this.options.end)
				this.parentOf(superMethod, [gradient, (gradient == 'background-color') ? this.init.backgroundColor : this.init.color]);
		}, this);
	}
});

/*
	Class: Element
	
	[Description] 
		Extends the Element Class with Fx shortcuts. 
		All these methods accept the same arguments of the relative Fx effect (obviously without the element)
	[/Description]
	
	Extends: Class Element
	
	[Methods]
		pulsate -- returns an Fx.Pulsate instance
		switchOff -- returns an Fx.SwitchOff instance
		gradient -- returns an Fx.Gradient instance
	[/Methods]
*/	
Element.implement({
	
	/*
	Method: pulsate
	Description:  returns an Fx.Pulsate instance
	*/
	pulsate: function(options) {
		return new Fx.Pulsate(this, options);	
	},
	
	/*
	Method: switchOff
	Description:  returns an Fx.SwitchOff instance
	*/
	switchOff: function(options) {
		return new Fx.SwitchOff(this, options);	
	},
	
	/*
	Method: gradient
	Description:  returns an Fx.Gradient instance
	*/
	gradient: function(options) {
		return new Fx.Gradient(this, options);	
	}
});

/*
	Hash: Element.Properties
	Description: Extends the Element.Properties Hash for using the effects_extra.js Fx Classes as Element's dynamic shortcuts with the Element.effect method
*/
fxToHash(Element.Properties, ['pulsate', 'switchOff', 'gradient']);

/*
	Filename: effects_toggle.js
	
	[Description]
		Contains the Fx.Toggle Class and the Element toggle method
	[/Description]
	
	Contains: Class Fx.Toggle, Class Element
	
	Requires: constructors.js, type.js, effects_base.js
	
	[Summary]
		Fx.Toggle ::: allows you to toggle everything
		Element ::: contains the Element.toggle method
	[/Summary]
*/
/*
	Class: Fx.Toggle
	
	[Description]
		Allows to toggle all the properties you want, either integers or strings.
	[/Description]
	
	Extends: Fx.Tween
	
	Constructor: new Fx.Toggle (element, options)
	
	[Properties] 
		element - the $(element) to apply the toggle to
		options - optional. the Fx options
	[/Properties]
	
	[Methods]
		toggleHeight -- toggles the height property
		toggleWidth -- toggles the width property
		toggleOpacity -- toggles the opacity property
		toggleProperty -- toggles a specified CSS property, string or integer, from one value to another
		toggle -- shortcut to toggle some togglables properties
	[/Methods]
*/

Fx.Toggle = new Class({
					  
	Extends: Fx.Tween,
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.initStyles('height', 'width', 'opacity');
		this.element.setStyle('overflow', 'hidden');
	},
	
	/*
	Method: toggleHeight
	Description: toggles the height property
	[Example]  
		> var fx = new Fx.Toggle('element'); 
		> fx.toggleHeight();
	[/Example]
	*/
	toggleHeight: function() {
		(this.element.getStyle('height').toInt() > 0) ? this.start('height', 0) : this.start('height', this.init.height);
		return this;
	},
	
	/*
	Method: toggleWidth
	Description: toggles the width property
	[Example]  
		> var fx = new Fx.Toggle('element'); 
		> fx.toggleWidth();
	[/Example]
	*/
	toggleWidth: function() {
		(this.element.getStyle('width').toInt() > 0) ? this.start('width', 0) : this.start('width', this.init.width);
		return this;
	},
	
	/*
	Method: toggleOpacity
	Description: toggles the opacity property
	[Example]  
		> var fx = new Fx.Toggle('element'); 
		> fx.toggleOpacity();
	[/Example]
	*/
	toggleOpacity: function() {
		(this.element.getStyle('opacity').toInt() > 0) ? this.start('opacity', 0) : this.start('opacity', this.init.opacity);
		return this;
	},
	
	/*
	Method: toggleDisplay
	Description: toggles the display property
	[Example]  
		> var fx = new Fx.Toggle('element'); 
		> fx.toggleDisplay();
	[/Example]
	*/
	toggleDisplay: function() {
		this.toggleProperty('display', 'none', 'block');
		return this;
	},
	
	/*
	Method: toggleVisibility
	Description: toggles the visibility property
	[Example]  
		> var fx = new Fx.Toggle('element'); 
		> fx.toggleVisibility();
	[/Example]
	*/
	toggleVisibility: function() {
		this.toggleProperty('visibility', 'hidden', 'visible');
		return this;
	},
	
	/*
	Method: toggleProperty
	Description: toggles a specified CSS property, string or integer, from one value to another
	[Arguments]
		property :: the property to toggle
		from :: the start value of the property. It can be different from it real start value
		to :: the final value of the property
		fx :: optional. if true the property changes with a transition
	[/Arguments]
	[Example]  
		> var fx = new Fx.Toggle('element'); 
		> fx.toggleProperty('color', 'blue', 'green');
		> fx.toggleProperty('color', 'blue', 'green', true);
	[/Example]
	*/
	toggleProperty: function(property, from, to, fx) {
		if($string(from) && $string(to)) {
			if(!fx)
				(this.element.getStyle(property) == from.toLowerCase()) ? this.element.setStyle(property, to) : this.element.setStyle(property, from);
			else
				(this.element.getStyle(property) == from.toLowerCase()) ? this.start(property, to) : this.start(property, from);
		}
		else if($int(from) && $int(to)) {
			if(!fx)
				(this.element.getStyle(property).toInt() == from) ? this.set(property, to) : this.set(property, from);
			else
				(this.element.getStyle(property).toInt() == from) ? this.start(property, to) : this.start(property, from);
		}
		return this;
	},
	
	/*
	Method: toggle
	Description: shortcut to toggle some togglables properties
	[Arguments]
		property :: the property to toggle
	[/Arguments]
	[Example]  
		> var fx = new Fx.Toggle('fx');
		>
		> // toggle height
		> fx.toggle('height');
		> // toggle width
		> fx.toggle('width');
		> // toggle opacity
		> fx.toggle('opacity');
		> // toggle display
		> fx.toggle('display');
		> // toggle visibility
		> fx.toggle('visibility');
	[/Example]
	*/
	toggle: function(property) {
		switch(property) {
			case 'height': this.toggleHeight();
						break;
			case 'width': this.toggleWidth();
						break;
			case 'opacity': this.toggleOpacity();
						break;
			case 'display': this.toggleDisplay();
						break;
			case 'visibility': this.toggleVisibility();
						break;
		}
		return this;
	}
});
			
/*
	Class: Element
	
	Description: Contains the Element.toggle method
	
	Extends: Class Element
	
	[Methods]
		toggle -- returns an Fx.Toggle instance
	[/Methods]
*/
Element.extend({
	/*
	Method: toggle
	Description: returns an Fx.Toggle instance
	[Example]  
		> $('element').toggle({duration:2000}).toggleProperty('color', '#6666FF', '#000000', true);
	[/Example]
	*/
	toggle: function(options) {
		return new Fx.Toggle(this, options);
	}
});

/*
	Filename: effects_cycle.js
	
	[Description] 
		Contains the Fx.Cycle Class and the Fx.Cycle extensions for creating powerful cycle effects, based on different 
		style transitions.
	[/Description]
	
	Contains: Class Fx.Cycle and its extensions, Class Element
	
	[Summary]
		Fx.Cycle ::: A wrapper which allows you to create powerful cycle effects
		Element ::: Contains the cycle method which returns a determinate Fx.Cycle instance
	[/Summary]
*/
/*
	Class: Fx.Cycle
	
	[Description]  
		With the Fx.Cycle extensions, you can create the "cycle effect" which means a slideshow based on a particular
		style transition. This file contains 14 Fx.Cycle extensions, like Fx.Cycle.zoom and Fx.Cycle.fade.
		In addiction, you can create your own cycle effect, either customizing an existing one or creating a new one.
		Below you can find all the Fx.Cycle extensions.
	[/Description]
	
	Extends: Fx.Morph
	
	Constructor: new Fx.Cycle.cycleType (element, options)
	
	[Properties] 
		element - the wrapper which contains your slides
		options - optional. The Fx options plus those described below
	[/Properties]
	
	[Options]
		animeOut : an object whose properties are the styles to alter when the slide gets out.
		animeIn : an object whose properties are the styles to alter when the slide comes in.
		cssBefore : an object whose properties are the styles to alter immediately before the slide comes in.
		animeInType : indicates the method to use with the animeIn object. It can be 'set' (default) or 'start' 
		overflow : the overflow of the wrapper. Depends on the type of cycle effect.
		steps : the timer used by autostart to change periodically the slides. Default is 2000 ms
		handles : an object which attaches events to elements passed in as values. The keywords represent the Fx.Cycle's methods
		autostart : if true the slides will be changed automatically. Deafult is true
		enable : an object containing some keywords to enable extra features. See below.
	[/Options]
	
	>> enable:
	[List]
		[li] keyboard: if true you can navigate with the keyboard too. In addition to the arrows, you can use the following keys. 'a' for autostart, 's' for stop, 'f' to go to the first slide and 'l' to go to the last slide. 
	[/List]
	
	[Events]
		onAnimeIn : function fired immediately before the element is animed in. The current and the next slide will be passed in
		onAnimeOut : function fired immediately before the element is animed out. The current and the next slide will be passed in
	[/Events]
	
	[Methods]
		next -- switches to the next slide
		prev -- switches to the previous slide
		goTo -- swicthes to the given slide
		toFirst -- switches to the first slide
		toLast -- switches to the last slide
		autostart -- enables the cycle slideshow
		stop -- stops the slideshow either if start method has been called or autostart option has been enabled
		animeIn -- sets the animeIn properties
		animeOut -- sets the animeOut properties
		cssBefore -- sets the cssBefore properties
	[/Methods]
	
	[Note]
		You can use the keywords 'this.height' and 'this.width' into the animeIn, animeOut and cssBefore methods,
		to refer respectively to the images' height and width. Using the keyword 'this.parentHeight' and 'this.parentWidth'
		you can refer to the parent element dimensions.
		In addiction, you can use the keywords 'this.currSlide' and 'this.nextSlide' to refer respectively to the current and
		the next slide.
	[/Note]
	
	Method: next
	Description:  switches to the next slide
	[Example]  
		> fx.next();
	[/Example]
	
	Method: prev
	Description:  switches to the previous slide
	[Example]  
		> fx.prev();
	[/Example]
	
	Method: goTo
	Description:  swicthes to the given slide
	[Arguments]
		num :: the position of the needed slide
	[/Arguments]
	[Example]  
		> fx.goTo(2);
	[/Example]
	
	Method: toFirst
	Description:  switches to the first slide
	[Example]  
		> fx.toFirst();
	[/Example]
	
	Method: toLast
	Description:  switches to the last slide
	[Example]  
		> fx.toLast();
	[/Example]
	
	Method: autostart
	Description:  enables the cycle slideshow
	[Example]  
		> fx.autostart();
	[/Example]
	
	Method: stop
	Description:  stops the slideshow either if start method has been called or autostart option has been enabled
	[Example]  
		> fx.stop();
	[/Example]
	
	Method: animeIn
	Description:  sets the animeIn properties
	[Arguments]
		styles :: an object which contains the animeIn css styles
	[/Arguments]
	[Example]  
		> fx.animeIn({top: 200, left: 200});
	[/Example]
	
	Method: animeOut
	Description:  sets the animeOut properties
	[Arguments]
		styles :: an object which contains the animeOut css styles
	[/Arguments]
	[Example]  
		> fx.animeOut({top: -200, opacity: 0});
	[/Example]
	
	Method: cssBefore
	Description:  sets the cssBefore properties
	[Arguments]
		styles :: an object which contains the cssBefore css styles
	[/Arguments]
	[Example]  
		> fx.cssBefore({left: 200, opacity: 1, height: 0, width: 0});
	[/Example]
*/
Fx.Cycle = new Class({
	
	Extends: Fx.Morph,
	
	options: {
		animeOut: {},
		animeIn: {},
		cssBefore: {},
		//cssAfter: {},
		animeInType: 'set',
		overflow: 'visible',
		autostart: true,
		steps: 2000,
		handles: {
			next: false,
			prev: false,
			toFirst: false,
			toLast: false,
			autostart: false,
			stop: false
		},
		enable: {
			keyboard: false	
		},
		onAnimeIn: $empty,
		onAnimeOut: $empty
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.imgs = this.element.getChildren();
		this.uimgs = this.element.getChildren().reverse();
		this.element.setStyles({'position': 'relative', 'overflow': this.options.overflow});
		this.first = this.element.getFirst();
		
		this.height = this.first.getStyle('height').toInt();
		this.width = this.first.getStyle('width').toInt();
		this.parentHeight = this.element.getStyle('height').toInt();
		this.parentWidth = this.element.getStyle('width').toInt();
		
		this.uimgs.each(function(img, i) {
			img.setStyles({'position': 'absolute', 'top': '0px', 'left': '0px', 'z-index': i});
		}, this);
		this.count = 0;
		this.length = this.imgs.length-1;
		this.fullLength = this.imgs.length;
		if(this.options.autostart) this._autostart = this.next.periodical(this.options.steps, this);
		this.attachHandles();
		if(this.options.enable.keyboard) this.attachKeys.bindWithEvent(this)();
	},
	
	next: function() {
		if(!this.timer) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			(this.count != this.length) ? this.count++ : this.count = 0;
			this.main();
		}
	},
	
	prev: function() {
		if(!this.timer) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			(this.count == 0) ? this.count = this.length : this.count--;
			this.main();
		}
	},
	
	goTo: function(to) {
		if(!this.timer && to != this.count) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			this.count = to;
			this.main();
		}
	},
	
	toFirst: function() {
		if(!this.timer && this.count != 0) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			this.count = 0;
			this.main();
		}
	},
	
	toLast: function() {
		if(!this.timer && this.count != this.length) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			this.count = this.length;
			this.main();
		}
	},
	
	autostart: function() {
		this._autostart = this.next.periodical(this.options.steps, this);
	},
	
	stop: function() {
		this._autostart = $clear(this._autostart);	
	},
	
	checkAutostart: function() {
		if(this._autostart) {
			this._autostart = $clear(this._autostart);
			this._autostart = this.next.periodical(this.options.steps, this);
		}
	},
	
	attachHandles: function() {
		for(var mtd in this.options.handles) {
			var method = mtd.toString();
			if(this.options.handles[mtd] && $function(this[method])) {
				$(this.options.handles[mtd]).addEvent('click', function(event, method) {
					event.preventDefault();	
					this[method]();
				}.bindWithEvent(this, method));	
			}
		}
	},
	
	attachKeys: function(event) {
		$(document).addEvent('keydown', function(event) {
			switch(event.key) {
				case 'left': this.prev();
					break;
				case 'right': this.next();
					break;
				case 'a': this.autostart();
					break;
				case 's': this.stop();
					break;
				case 'f': this.toFirst();
					break;
				case 'l': this.toLast();
					break;
			}
		}.bind(this));
	},
	
	main: function() {
		this.element.setStyle('z-index', this.fullLength);
		this.imgs[this.count].setStyle('z-index', 1);
		
		this.currSlide = this.element;
		this.nextSlide = this.imgs[this.count];
		
		this.fireEvent('onAnimeOut', [this.currSlide, this.nextSlide]);
		this.start(this.options.animeOut).chain(
			function() {
				var type = this.options.animeInType;
				if(type == 'set') this.fireEvent('onAnimeIn', [this.currSlide, this.nextSlide]);
				this.element.setStyle('z-index', 0);
				this.imgs.each(function(img, i) {
					if(i != this.count) img.setStyle('z-index', 0).setStyles(this.options.cssBefore);
				}, this);
				if(type == 'set') this[type](this.options.animeIn); // set instead of start
				if(type == 'start') this[type](this.options.animeIn).chain(function() { this.fireEvent('onAnimeIn', [this.currSlide, this.nextSlide]); });
			}
		);
	}
					 
});

(function() {
var methods = {};

['animeOut', 'animeIn', 'cssBefore'].each(function(method) {
	methods[method] = function(styles) {
		for(var style in styles)
			if($defined(styles[style])) this.options[method][style] = styles[style]; 
	}					
});

Fx.Cycle.implement(methods);
})();

/* 
Class: Fx.Cycle.shuffle 
*/
Fx.Cycle.shuffle = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeInType: 'start',
		animeIn: {
			top: 0,
			left: 0
		},
		sizes: [20, -110]
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({top: this.options.sizes[0], left: this.options.sizes[1]});
	}
});

/* 
Class: Fx.Cycle.fade 
*/
Fx.Cycle.fade = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeOut: {
			opacity: 0
		},
		cssBefore: {
			opacity: 1	
		}
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
	}
});

/* 
Class: Fx.Cycle.slideUp 
*/
Fx.Cycle.slideUp = new Class({

	Extends: Fx.Cycle,
	
	options: {
		cssBefore: {
			top: 0, left:0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({top: -this.parentHeight});
	}
});

/* 
Class: Fx.Cycle.slideDown 
*/
Fx.Cycle.slideDown = new Class({

	Extends: Fx.Cycle,
	
	options: {
		cssBefore: {
			top: 0, left:0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({top: this.parentHeight});
	}
});

/* 
Class: Fx.Cycle.slideRight 
*/
Fx.Cycle.slideRight = new Class({

	Extends: Fx.Cycle,
	
	options: {
		cssBefore: {
			top: 0, left:0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({left: this.parentWidth});
	}
});

/* 
Class: Fx.Cycle.slideLeft 
*/
Fx.Cycle.slideLeft = new Class({

	Extends: Fx.Cycle,
	
	options: {
		cssBefore: {
			top: 0, left:0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({left: -this.parentWidth});
	}
});

/* 
Class: Fx.Cycle.foldUp 
*/
Fx.Cycle.foldUp = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeOut: {
			height: 0
		},
		animeIn: {
			left: 0, top: 0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.cssBefore({top: 0, height: this.height});
	}
});

/* 
Class: Fx.Cycle.foldDown 
*/
Fx.Cycle.foldDown = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeIn: {
			left: 0, top: 0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({height: 0, top: this.height});
		this.cssBefore({top: 0, height: this.height});
	}
});

/* 
Class: Fx.Cycle.foldRight 
*/
Fx.Cycle.foldRight = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeOut: {
			width: 0
		},
		animeIn: {
			left: 0, top: 0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.cssBefore({top: 0, width: this.width});
	}
});

/* 
Class: Fx.Cycle.foldLeft 
*/
Fx.Cycle.foldLeft = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeIn: {
			left: 0, top: 0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({width: 0, left: this.width});
		this.cssBefore({top: 0, width: this.width});
	}
});

/* 
Class: Fx.Cycle.zoom 
*/
Fx.Cycle.zoom = new Class({

	Extends: Fx.Cycle,
	
	options: {
		cssBefore: {
			top: 0, left: 0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({width: 0, height: 0, top: this.height/2, left: this.width/2});
		this.animeIn({top: 0, left: 0, width: this.height, height: this.width});
	}
});

/* 
Class: Fx.Cycle.diagonalUp
*/
Fx.Cycle.diagonalUp = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeIn: {
			top: 0, left: 0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({top: -this.parentHeight, left: -this.parentWidth});
	}
});

/* 
Class: Fx.Cycle.diagonalDown
*/
Fx.Cycle.diagonalDown = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeIn: {
			top: 0, left: 0
		},
		overflow: 'hidden'
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
		this.animeOut({top: this.parentHeight, left: this.parentWidth});
	}
});

/* 
Class: Fx.Cycle.linear 
*/
Fx.Cycle.linear = new Class({

	Extends: Fx.Cycle,
	
	options: {
		animeOut: {
			display: 'none'
		},
		cssBefore: {
			display: 'block'
		}
	},
	
	initialize: function(element, options) {
		this.parent(element, options);
	}
});

/*
	Class: Element
	
	[Description] 
		Contains the cycle method which returns a determinate Fx.Cycle instance
	[/Description]
	
	Extends: Class Element
	
	[Methods]
		cycle -- returns an Fx.Cycle instance of the given type
	[/Methods]
*/	
Element.implement({
	
	/*
	Method: cycle
	Description:  returns an Fx.Cycle instance of the given type
	[Arguments]
		type :: the Fx.Cycle transition
		options :: the Fx.Cycle options
	[/Arguments]
	[Example]  
		> // slideUp instance
		> var slideUp = $('myElement').cycle('slideUp');
		> // diagonalUp instance
		> var diagonalUp = $('myElement').cycle('diagonalUp', {duration: 4000, steps: 4000});
	[/Example]
	*/
	cycle: function(type, options) {
		return new Fx.Cycle[type](this, options);
	}				  

});

/*
	Filename: effects_cycles.js
	
	[Description] 
		Contains the Fx.Cycles Class and the Fx.Cycles extensions to create powerful cycle slideshows which alter 
		two slides at once
	[/Description]
	
	Contains: Class Fx.Cycles and its extensions, Class Element
	
	[Summary]
		Fx.Cycles ::: A wrapper which allows you to create powerful cycle effects
		Element ::: Contains the cycles method which returns a determinate Fx.Cycles instance
	[/Summary]
*/
/*
	Class: Fx.Cycles
	
	[Description]  
		The Fx.Cycles Class provides a similar functionality to the Fx.Cycle Class. With the Fx.Cycles Class however,
		you can "cycle" two slides at once, to create more complex transitions. There are 13 transitions created by default,
		but you can create your own as with the Fx.Cycle Class.
	[/Description]
	
	Extends: Fx.Elements
	
	Constructor: new Fx.Cycles.cycleType (element, options)
	
	[Properties] 
		element - the wrapper which contains your slides
		options - optional. The Fx options
	[/Properties]
	
	[Options]
		animeOut : an object whose properties are the styles to alter when the slide gets out.
		animeIn : an object whose properties are the styles to alter when the slide comes in.
		cssBefore : an object whose properties are the styles to alter immediately before the slide comes in.
		cssAfter : an object whose properties are the styles to alter immediately after the slide has come in.
		reset : an object whose properties are the styles to reset to the next slide.
		overflow : the overflow of the wrapper. Depends on the type of cycle effect.
		steps : the timer used by autostart to change periodically the slides. Default is 2000 ms
		handles : an object which attaches events to elements passed in as values. The keywords represent the Fx.Cycles's methods
		autostart : if true the slides will be changed automatically. Deafult is true
		enable : an object containing some keywords to enable extra features. See below.
	[/Options]
	
	>> enable:
	[List]
		[li] keyboard: if true you can navigate with the keyboard too. In addition to the arrows, you can use the following keys. 'a' for autostart, 's' for stop, 'f' to go to the first slide and 'l' to go to the last slide. 
	[/List]
	
	[Events]
		onAnimeIn : function fired immediately before the element is animed in. The current and the next slide will be passed in
		onAnimeOut : function fired immediately before the element is animed out. The current and the next slide will be passed in
	[/Events]
	
	[Methods]
		next -- switches to the next slide
		prev -- switches to the previous slide
		goTo -- swicthes to the given slide
		toFirst -- switches to the first slide
		toLast -- switches to the last slide
		autostart -- enables the cycle slideshow
		stop -- stops the slideshow either if start method has been called or autostart option has been enabled
		animeIn -- sets the animeIn properties
		animeOut -- sets the animeOut properties
		cssBefore -- sets the cssBefore properties
		cssAfter -- sets the cssAfter properties
		reset -- sets the reset properties
	[/Methods]
	
	[Note]
		You can use the keywords 'this.height' and 'this.width' into the animeIn, animeOut, cssBefore, cssAfter and reset methods,
		to refer respectively to the images' height and width. Using the keyword 'this.parentHeight' and 'this.parentWidth'
		you can refer to the parent element dimensions.
		In addiction, you can use the keywords 'this.currSlide' and 'this.nextSlide' to refer respectively to the current and
		the next slide.
	[/Note]
	
	Method: next
	Description:  switches to the next slide
	[Example]  
		> fx.next();
	[/Example]
	
	Method: prev
	Description:  switches to the previous slide
	[Example]  
		> fx.prev();
	[/Example]
	
	Method: goTo
	Description:  swicthes to the given slide
	[Arguments]
		num :: the position of the needed slide
	[/Arguments]
	[Example]  
		> fx.goTo(2);
	[/Example]
	
	Method: toFirst
	Description:  switches to the first slide
	[Example]  
		> fx.toFirst();
	[/Example]
	
	Method: toLast
	Description:  switches to the last slide
	[Example]  
		> fx.toLast();
	[/Example]
	
	Method: autostart
	Description:  enables the cycle slideshow
	[Example]  
		> fx.autostart();
	[/Example]
	
	Method: stop
	Description:  stops the slideshow either if start method has been called or autostart option has been enabled
	[Example]  
		> fx.stop();
	[/Example]
	
	Method: animeIn
	Description:  sets the animeIn properties
	[Arguments]
		styles :: an object which contains the animeIn css styles
	[/Arguments]
	[Example]  
		> fx.animeIn({top: 200, left: 200});
	[/Example]
	
	Method: animeOut
	Description:  sets the animeOut properties
	[Arguments]
		styles :: an object which contains the animeOut css styles
	[/Arguments]
	[Example]  
		> fx.animeOut({top: -200, opacity: 0});
	[/Example]
	
	Method: cssBefore
	Description:  sets the cssBefore properties
	[Arguments]
		styles :: an object which contains the cssBefore css styles
	[/Arguments]
	[Example]  
		> fx.cssBefore({left: 200, opacity: 1, height: 0, width: 0});
	[/Example]
	
	Method: cssAfter
	Description:  sets the cssAfter properties
	[Arguments]
		styles :: an object which contains the cssAfter css styles
	[/Arguments]
	[Example]  
		> fx.cssAfter({left: 0, opacity: 0, height: 200});
	[/Example]
	
	Method: reset
	Description:  sets the reset properties
	[Arguments]
		styles :: an object which contains the reset css styles
	[/Arguments]
	[Example]  
		> fx.reset({top: 200, opacity: 1, width: 0});
	[/Example]
*/
Fx.Cycles = new Class({
	
	Extends: Fx.Elements,
	
	options: {
		animeOut: {},
		animeIn: {},
		cssBefore: {},
		cssAfter: {},
		reset: {},
		overflow: 'visible',
		autostart: true,
		steps: 2000,
		duration: 3000,
		handles: {
			next: false,
			prev: false,
			toFirst: false,
			toLast: false,
			autostart: false,
			stop: false
		},
		enable: {
			keyboard: false	
		},
		onAnimeIn: $empty,
		onAnimeOut: $empty
	},
	
	initialize: function(element, options) {
		this.element = $(element);
		this.elements = this.element.getChildren();
		this.parent($$(this.elements), options);
		this.imgs = this.element.getChildren();
		this.uimgs = this.element.getChildren().reverse();
		this.element.setStyles({'position': 'relative', 'overflow': this.options.overflow});
		this.first = this.element.getFirst();
		
		this.height = this.first.getStyle('height').toInt();
		this.width = this.first.getStyle('width').toInt();
		this.parentHeight = this.element.getStyle('height').toInt();
		this.parentWidth = this.element.getStyle('width').toInt();
		
		this.uimgs.each(function(img, i) {
			img.setStyles({'position': 'absolute', 'top': '0px', 'left': '0px', 'z-index': i});
		}, this);
		this.count = 0;
		this.where = -1;
		this.length = this.imgs.length-1;
		this.fullLength = this.imgs.length;
		if(this.options.autostart) this._autostart = this.next.periodical(this.options.steps, this);
		this.attachHandles();
		if(!this.options.enable.keyboard) this.attachKeys.bindWithEvent(this)();
	},
	
	next: function() {
		if(!this.timer) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			(this.count != this.length) ? this.count++ : this.count = 0;
			(this.where == -1) ? this.where = 0 : (this.count == 0) ? this.where = this.length : this.where = this.count-1;
			this.main();
		}
	},
	
	prev: function() {
		if(!this.timer) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			(this.count == 0) ? this.count = this.length : this.count--;
			(this.where == -1) ? this.where = 0 : (this.count == this.length) ? this.where = 0 : this.where = this.count+1;
			this.main();
		}
	},
	
	goTo: function(to) {
		if(!this.timer && to != this.count) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			this.where = this.count;
			this.count = to;
			this.main();
		}
	},
	
	toFirst: function() {
		if(!this.timer && this.count != 0) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			this.where = this.count;
			this.count = 0;
			this.main();
		}
	},
	
	toLast: function() {
		if(!this.timer && this.count != this.length) {
			this.checkAutostart();
			this.element = this.imgs[this.count];
			this.where = this.count;
			this.count = this.length;
			this.main();
		}
	},
	
	autostart: function() {
		this._autostart = this.next.periodical(this.options.steps, this);
	},
	
	stop: function() {
		this._autostart = $clear(this._autostart);	
	},
	
	checkAutostart: function() {
		if(this._autostart) {
			this._autostart = $clear(this._autostart);
			this._autostart = this.next.periodical(this.options.steps, this);
		}
	},
	
	attachHandles: function() {
		for(var mtd in this.options.handles) {
			var method = mtd.toString();
			if(this.options.handles[mtd] && $function(this[method])) {
				$(this.options.handles[mtd]).addEvent('click', function(event, method) {
					event.preventDefault();	
					this[method]();
				}.bindWithEvent(this, method));	
			}
		}
	},
	
	attachKeys: function(event) {
		$(document).addEvent('keydown', function(event) {
			switch(event.key) {
				case 'left': this.prev();
					break;
				case 'right': this.next();
					break;
				case 'a': this.autostart();
					break;
				case 's': this.stop();
					break;
				case 'f': this.toFirst();
					break;
				case 'l': this.toLast();
					break;
			}
		}.bind(this));
	},
	
	main: function() {
		this.element.setStyle('z-index', this.fullLength);
		this.imgs[this.count].setStyle('z-index', 1).setStyles(this.options.current);
		
		this.imgs.each(function(img, i) {
				if(i!=this.where)
					img.setStyles(this.options.cssBefore);
		}, this);
		
		var o = {};

		var curr = this.where;
		var next = this.count;
		
		this.currSlide = this.imgs[curr];
		this.nextSlide = this.imgs[next];
			
		o[curr] = this.options.animeOut;
		o[next] = this.options.animeIn;
		
		this.fireEvent('onAnimeOut', [this.currSlide, this.nextSlide]);
		this.imgs[next].setStyles(this.options.reset);
		this.start(o).chain(function() {
			this.imgs[curr].setStyles(this.options.cssAfter); 
			this.fireEvent('onAnimeIn', [this.currSlide, this.nextSlide]);	
		});
	}
					 
});

(function() {
var methods = {};

['animeOut', 'animeIn', 'cssBefore', 'cssAfter', 'reset'].each(function(method) {
	methods[method] = function(styles) {
		for(var style in styles)
			if($defined(styles[style])) this.options[method][style] = styles[style]; 
	}					
});

Fx.Cycles.implement(methods);
})();

/* 
Class: Fx.Cycles.scrollUp 
*/
Fx.Cycles.scrollUp = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({top: [0, -this.parentHeight]});
		this.animeIn({top: [this.parentHeight, 0]});
	}
});

/* 
Class: Fx.Cycles.scrollDown 
*/
Fx.Cycles.scrollDown = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({top: [0, this.parentHeight]});
		this.animeIn({top: [-this.parentHeight, 0]});
	}
});

/* 
Class: Fx.Cycles.scrollLeft
*/
Fx.Cycles.scrollLeft = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({left: [0, -this.parentWidth]});
		this.animeIn({left: [this.parentWidth, 0]});
	}
});

/* 
Class: Fx.Cycles.scrollRight
*/
Fx.Cycles.scrollRight = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({left: [0, this.parentWidth]});
		this.animeIn({left: [-this.parentWidth, 0]});
	}
});

/* 
Class: Fx.Cycles.fadeZoom
*/
Fx.Cycles.fadeZoom = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({opacity: [1, 0], display: 'block'});
		this.animeIn({left: [this.width/2, 0], top: [this.height/2, 0], width: [0, this.width], height: [0, this.height], display: 'block'});
		this.cssBefore({height: 0, width: 0, display: 'none'});
		this.reset({height: this.height, width: this.width, opacity: 1, top: this.height/2, left: this.width/2, display: 'none'});
	}
});

/* 
Class: Fx.Cycles.turnDown
*/
Fx.Cycles.turnDown = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({height: [this.height, 0], top: [0, this.height]});
		this.animeIn({height: [0, this.height]});
		this.reset({display: 'block', height: this.height, width: this.width, top: 0, left: 0});
		this.cssAfter({display: 'none', width: 0});
	}
});

/* 
Class: Fx.Cycles.turnUp
*/
Fx.Cycles.turnUp = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({height: [this.height, 0], top: 0});
		this.animeIn({height: [0, this.height], top: 0});
		this.reset({display: 'block', top: this.height, width: this.width});
		this.cssAfter({display: 'none', width: 0});
	}
});

/* 
Class: Fx.Cycles.turnLeft
*/
Fx.Cycles.turnLeft = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({width: [this.width, 0], left: 0});
		this.animeIn({width: [0, this.width], left: [this.width, 0]});
		this.reset({display: 'block', left: this.width, width: this.width});
		this.cssAfter({display: 'none', width: 0});
	}
});

/* 
Class: Fx.Cycles.turnRight
*/
Fx.Cycles.turnRight = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({width: [this.width, 0], left: [0, this.width]});
		this.animeIn({width: [0, this.width], left: 0});
		this.reset({display: 'block', left: 0, width: this.width});
		this.cssAfter({display: 'none', width: 0});
	}
});

/* 
Class: Fx.Cycles.inOutLeft
*/
Fx.Cycles.inOutLeft = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({top: this.parentHeight, left: this.parentWidth});
		this.animeIn({top:0, left: 0});
		this.cssBefore({display: 'none'});
		this.reset({top: -this.parentHeight, left: this.parentWidth, display: 'block'});
	}
});

/* 
Class: Fx.Cycles.inOutRight
*/
Fx.Cycles.inOutRight = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({top: -this.parentHeight, left: -this.parentWidth});
		this.animeIn({top:0, left: 0});
		this.cssBefore({display: 'none'});
		this.reset({top: this.parentHeight, left: -this.parentWidth, display: 'block'});
	}
});

/* 
Class: Fx.Cycles.inOutUp
*/
Fx.Cycles.inOutUp = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({top: -this.parentHeight});
		this.animeIn({left: 0});
		this.cssBefore({display: 'none'});
		this.reset({top: 0, left: this.parentWidth, display: 'block'});
	}
});

/* 
Class: Fx.Cycles.inOutDown
*/
Fx.Cycles.inOutDown = new Class({

	Extends: Fx.Cycles,
	
	options: {
		overflow: 'hidden'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.animeOut({top: this.parentHeight});
		this.animeIn({left: 0});
		this.cssBefore({display: 'none'});
		this.reset({top: 0, left: this.parentWidth, display: 'block'});
	}
});

/*
	Class: Element
	
	[Description] 
		Contains the cycles method which returns a determinate Fx.Cycles instance
	[/Description]
	
	Extends: Class Element
	
	[Methods]
		cycles -- returns an Fx.Cycles instance of the given type
	[/Methods]
*/	
Element.implement({
	
	/*
	Method: cycles
	Description:  returns an Fx.Cycles instance of the given type
	[Arguments]
		type :: the Fx.Cycles transition
		options :: the Fx.Cycles options
	[/Arguments]
	[Example]  
		> // scrollUp instance
		> var scrollUp = $('myElement').cycles('scrollUp');
		> // turnUp instance
		> var turnUp = $('myElement').cycles('turnUp', {duration: 2000, steps: 4000});
	[/Example]
	*/
	cycles: function(type, options) {
		return new Fx.Cycles[type](this, options);
	}				  

});

/*
	Filename: virtual_base.js
	
	[Description]
		Contains the Virtual Class which is a wrapper for creating complex virtual modal boxes
	[/Description]
	
	Contains: Class Virtual, Class Virtual.single
	
	Requires: overlay.js, browser.js, type.js
	
	[Summary]
		Virtual ::: A wrapper for creating virtual contents like Virtual.Box and Virtual.Ajax Classes
		Virtual.single ::: Utility Wrapper to create single virtual boxes. Implemented by the other virtual single Classes
	[/Summary]
*/
/*
	Class: Virtual
	
	Description: A wrapper for creating virtual contents like Virtual.Box and Virtual.Ajax Classes
	
	Implements: Overlay, Options, Events
	
	Constructor: new Virtual (options)
	
	[Options]
		enable : an object which allows you to decide which features must be enabled
		effect : the effect type. Can be 'open' (default), 'slide:vertical' (or 'slide'), 'slide:horizontal', 'fold' or 'fix'
		effectOptions : the main Fx effect options
		style : if true the boxes will be styled with the custom styles
		adjustStyles : if true the virtual box will be placed in the middle when user resize the window. Default is true.
		zones : an object which allows to set the class names for some zones of the virtual box
		arrowsBoxText : the text of the arrows box
		leftArrowText : the text of the left arrow. Default is 'prev'
		rightArrowText : the text of the right arrow. Default is 'next'
		closeButtonText : the text of the close button. Default is 'close'
		captionOpacity : the caption's opacity. Default is 0.4
	[/Options]
	
	>> enable:
		[List]
			[li] arrows: if true the arrows will be enabled
			[li] closeButton: if true the closeButton will be enabled. Otherwise you can close the box clicking on the overlay
			[li] arrowsKeyboard: if true you can change the virtual box with the arrows of the keyboard
			[li] closeKeyboard: if true you can remove the virtual box by pressing the 'esc' key
			[li] caption: if true the caption will be enabled, and it will have a title an a content catched by the title property of the respective link
		[/List]
	
	[Events]
		onShow : function fired when a new virtual box comes in
		onClose : function fired when the virtual box is closed
		onNext : function fired when the next virtual box comes in
		onPrev : function fired when the previous virtual box comes in
	[/Events]
	
	[Methods]
		setEffect -- sets the type of the entry effect
		virtualStyle -- injects a css file dedicated to virtual box / virtual ajax
		setIDs -- sets the id property to the specified zones
	[/Methods]
	
	Method: setEffect
	Description:  sets the type of the entry effect
	[Arguments]
		effect :: the effect
	[/Arguments]
	[Example]
		> // open effect
		> virtual.setEffect('open');
		> // fix effect
		> virtual.setEffect('fix');
	[/Example]
	
	Method: virtualStyle
	Description:  injects a css file dedicated to virtual box / virtual ajax
	[Arguments]
		path :: the file path
	[/Arguments]
	[Example]
		> virtual.virtualStyle('myPath/virtual_style.css');
	[/Example]

	Method: setIDs
	Description:  sets the id property to the specified zones
	[Arguments]
		zones :: an object with keywords as zones and values as id values
	[/Arguments]
*/
var Virtual = new Class({
		
	Implements: [Overlay, Options, Events],
	
	options: {
		enable: {
			arrows: true,
			closeButton: true,
			arrowsKeyboard: true,
			closeKeyboard: true,
			caption: true
		},
		effect: 'open',
		effectOptions: {
			duration: 1000	
		},
		style: true,
		adjustStyles: true,
		zones: {
			main: '',
			wrapper: '',
			caption: '',
			captionText: '',
			captionTextTitle: '',
			captionTextContent: '',
			arrowsBox: '',
			arrowsBoxText: '',
			leftArrow: '',
			rightArrow: ''
		},
		arrowsBoxText: false,
		leftArrowText: 'prev',
		rightArrowText: 'next',
		closeButtonText: 'close',
		captionOpacity: 0.4,
		imageText: false,
		onShow: $empty,
		onClose: $empty,
		onNext: $empty,
		onPrev: $empty
	},	
	
	initialize: function(options) {
		this.setOptions(options);
		this.effects = {
			main: new Fx.Elements(null, $merge(this.options.effectOptions, {link: 'ignore'})),
			caption: new Fx.Elements(null, {duration: 1000, link: 'ignore'})	
		};
		this.fullWidth = [];
		this.fullHeight = [];
		this.captionHeight = [];
	},
	
	mechanize: function() {
		this.createOverlay('virtualBoxOverlay', 'darken');
		this.createFullPage('virtualBoxFullPage');
		
		this.main = new Element('div', {
			'id': 'virtualMain',
			'class': this.options.zones.main
		});
		
		if(this.options.style)
			this.main.setStyles({
				'background-color': '#FFFFFF',
				'padding': '8px'
			});
		
		this.wrapper = new Element('div', {
			'id': 'virtualBox',
			'class': this.options.zones.wrapper,
			'styles': {
				'position': 'relative',
				'overflow': 'hidden'
			}
		}).inject(this.main);
		
		if(this.options.enable.caption) {
			this.caption = new Element('div', {
				'id': 'virtualCaption',	
				'class': this.options.zones.caption,
				'styles': {
					'position': 'absolute',
					'bottom': '0px',
					'opacity': this.options.captionOpacity,
					'z-index': 1,
					'overflow': 'hidden',
					'visibility': 'hidden'
				}
			}).inject(this.wrapper);
			
			if(this.options.style) this.caption.setStyles({'background-color': '#CCCCCC'});
			
			this.captionText = new Element('div', {
				'id': 'virtualCaptionText',	
				'class': this.options.zones.captionText,
				'styles': {
					'position': 'absolute',
					'bottom': '0px',
					'opacity': 1,
					'z-index': 2,
					'overflow': 'hidden',
					'visibility': 'hidden'
				}
			}).inject(this.wrapper);
			
			this.captionTextTitle = new Element('p', {
				'id': 'virtualCaptionTitle',
				'class': this.options.zones.captionTextTitle
			}).inject(this.captionText);
			
			this.captionTextContent = new Element('p', {
				'id': 'virtualCaptionContent',
				'class': this.options.zones.captionTextContent
			}).inject(this.captionText);
		}
		
		if(this.options.enable.arrows) {
			this.arrowsBox = new Element('div', {
				'id': 'virtualArrowsBox',	
				'class': this.options.zones.arrowsBox,
				 'styles': {
					 'position': 'absolute',
					 'bottom': '0px',
					 'visibility': 'hidden' 
				 }
			});
			
			this.arrowsBoxText = new Element('div', {
				'id': 'virtualArrowsBoxText', 
				'class': this.options.zones.arrowsBoxText,
				'styles': {
					'display': 'block',
					'visibility': 'hidden'
				}
			}).inject(this.arrowsBox);
			
			this.leftArrow = new Element('a', {
				'id': 'virtualLeftArrow',
				'class': this.options.zones.leftArrow,
				'href': '#'
			}).set('html', this.options.leftArrowText);
			
			this.rightArrow = new Element('a', {
				'id': 'virtualRightArrow',
				'class': this.options.zones.rightArrow,
				'href': '#'
			}).set('html', this.options.rightArrowText);
			
			this.leftArrow.addEvent('click', function(event) {
				event.preventDefault();
				this.prev();
			}.bind(this));
			
			this.rightArrow.addEvent('click', function(event) {
				event.preventDefault();
				this.next();
			}.bind(this));
			
			$$(this.leftArrow, this.rightArrow).inject(this.arrowsBox);
			
			if(this.options.enable.closeButton) {
				this.closeButton = new Element('a', {
					'id': 'virtualCloseButton',
					'class': this.options.zones.closeButton,
					'href': '#'
				}).set('html', this.options.closeButtonText).addEvent('click', function(event) {
					event.preventDefault();
					this.closeBox();
				}.bind(this));
				this.closeButton.inject(this.arrowsBox);
			}
			else {
				this.attachCloseEvent();
			}
		}
		
		if(this.options.enable.closeKeyboard) document.addEvent('keydown', this.keyboardClose.bind(this));
		if(!this.options.enable.arrows || !this.options.enable.closeButton) this.attachCloseEvent();
		if(this.options.enable.arrowsKeyboard) document.addEvent('keydown', this.keyboard.bindWithEvent(this));
		
		if(this.options.adjustStyles) {
			this.newsizes = function() {
				$$(this.main).setStyles({
					'top': window.getSize().y.toInt()/2,
					'left': window.getSize().x.toInt()/2
				});
			};
			window.addEvent('resize', this.newsizes.bind(this));
		}
	},
	
	createArrowsBox: function() {
		this.arrowsBox.inject(this.main);
		this.main.inject(this.fullpage);
		this.arrowsBoxHeight = this.arrowsBox.getSize().y + this.arrowsBoxText.getSize().y;
		this.arrowsBoxHalfHeight = this.arrowsBox.getHeight().toInt();
		this.main.setStyles({
			'position': 'absolute',
			'top': window.getSize().y.toInt()/2,
			'left': window.getSize().x.toInt()/2,
			'height': this.sizes.height+this.arrowsBoxHeight,
			'margin-top': -((this.sizes.height+this.arrowsBoxHeight)/2),
			'margin-left': -((this.sizes.width+this.arrowsBoxHeight)/2)
		});
	},
	
	setArrowsBoxText: function(text) {
		if(this.options.enable.arrows) { 
			var arrowsBoxText = this.options.arrowsBoxText || text;
			this.arrowsBoxText.set('html', arrowsBoxText).inject(this.main);
		}
	},
	
	reset: function() {
		$$(this.caption, this.captionText, this.arrowsBox, this.arrowsBoxText).setStyle('visibility', 'hidden');
		if(this.options.enable.caption) {
			this.captionText.dispose().setStyle('height', '0px');
			$$(this.captionTextTitle, this.captionTextContent).empty();
		}
	},
	
	makeCaptionEffect: function(i) {
		if(this.options.enable.caption) {
			this.captionText.inject(this.caption, 'after');
			if(!this.captionPadding) this.captionPadding = (this.captionText.getStyle('padding-top').toInt() + this.captionText.getStyle('padding-bottom').toInt());
			
			this.captionText.setStyle('height', 'auto');
			this.captionTextTitle.set('html', this.sizes.title).inject(this.captionText);
			this.captionTextContent.set('html', this.sizes.text).inject(this.captionText);
			
			if(!this.captionHeight[i]) this.captionHeight[i] = this.captionText.getSize().y - this.captionPadding;
			
			$$(this.caption, this.captionText).setStyles({'height': '0px', 'visibility': 'visible'});
			
			switch(this.options.effect) {
				case 'open':
				case 'slide:vertical':
				case 'slide:horizontal':
				case 'slide': this.captionDelay = this.effects.main.options.duration.toInt();
								break;
				case 'fix': this.captionDelay = 0;
							break;
				case 'fold': this.captionDelay = this.effects.main.options.duration.toInt()*2;
								break;
			}
			
			this.effects.caption.elements = $$(this.caption, this.captionText);
			this.effects.caption.start.delay(this.captionDelay, this.effects.caption, {
				'0': { height: [0, this.captionHeight[i]]},	
				'1': { height: [0, this.captionHeight[i]]}
			});
		}
	},
	
	next: function() {
		if(this.effects.main.timer || this.effects.caption.timer) return;
		(this.count != this.length) ? this.count++ : this.count = 0;
		this.attach(this.count);
		this.fireEvent('onNext', [this.count, this.fullLength]);
	},
	
	prev: function() {
		if(this.effects.main.timer || this.effects.caption.timer) return;
		(this.count == 0) ? this.count = this.length : this.count--;
		this.attach(this.count);
		this.fireEvent('onPrev', [this.count, this.fullLength]);
	},
	
	keyboard: function(event) {
		if(this.overlayActive) {
			if(event.key == 'right') {
				this.next();
			}
			else if(event.key == 'left') {
				this.prev();
			}
		}
	},
	
	keyboardClose: function(event) {
		if(this.overlayActive) {
			if(event.key == 'esc') this.closeBoxWithKeyboard();
		}
	},
	
	setEffect: function(mode) {
		this.options.effect = mode;
	},
	
	remove: function() {
		this.main.dispose();
		this.removeOverlay();
	},
	
	attachCloseEvent: function() {
		if(Browser.firefox) {
			this.overlay.addEvent('click', this.closeBox.bindWithEvent(this, 'overlay'));
			this.fullpage.addEvent('click', this.closeBox.bindWithEvent(this, 'fullpage'));
		}
		else {
			this.fullpage.addEvent('click', this.closeBox.bindWithEvent(this, 'fullpage'));
		}
	},
	
	closeBox: function(event, zone) {
		if(this.effects.main.timer || this.effects.caption.timer) return;
		if((!this.options.enable.arrows || !this.options.enable.closeButton) && event.target != this[zone]) return;
		this.fireEvent('onClose', [this.count, this.length]);
		this.count = 0;
		this.remove();
	},
	
	closeBoxWithKeyboard: function() {
		if(this.effects.main.timer || this.effects.caption.timer) return;
		this.fireEvent('onClose', [this.count, this.length]);
		this.count = 0;
		this.remove();
	},
	
	makeEffect: function(i) {
		if(this.options.effect == 'open') {
			if(Browser.firefox) this.fullpage.setStyle('height', 'auto');
			if(this.options.enable.arrows) this.createArrowsBox();
			else this.main.inject(this.fullpage);
			
			if(!this.fullWidth[i]) this.fullWidth[i] = this.main.getStyle('width').toInt();
			if(!this.fullHeight[i]) this.fullHeight[i] = (!this.arrowsBoxHeight) ? this.sizes.height : this.sizes.height+this.arrowsBoxHeight;
			
			$$(this.main, this.wrapper).setStyles({'visibility': 'visible', 'height': '0px', 'width': '0px'});
			$$(this.arrowsBox).setStyle('width', this.fullWidth[i]);
			
			this.effects.main.elements = $$(this.main, this.wrapper);
			this.effects.main.start({
				'0': {
					'width': this.fullWidth[i],	
					'height': this.fullHeight[i]
				},
				'1': {
					'width': this.fullWidth[i],	
					'height': this.sizes.height
				}
			}).chain(function() {
				if(this.options.enable.arrows) $$(this.arrowsBox, this.arrowsBoxText).setStyle('visibility', 'visible');	
			}.bind(this));
		}
		else if(this.options.effect == 'fix') {
			if(Browser.firefox) this.fullpage.setStyle('height', 'auto');
			if(this.options.enable.arrows) { 
				this.createArrowsBox();
				if(!this.fullWidth[i]) this.fullWidth[i] = this.main.getStyle('width').toInt();
				if(!this.fullHeight[i]) this.fullHeight[i] = (!this.arrowsBoxHeight) ? this.sizes.height : this.sizes.height+this.arrowsBoxHeight;
				$$(this.arrowsBox, this.arrowsBoxText).setStyle('visibility', 'visible');
				$$(this.arrowsBox).setStyle('width', this.fullWidth[i]);
			}
			else this.main.inject(this.fullpage);
		}
		else if(this.options.effect == 'fold') {
			if(Browser.firefox) this.fullpage.setStyle('height', 'auto');
			if(this.options.enable.arrows) this.createArrowsBox();
			else this.main.inject(this.fullpage);
			
			$$(this.main).setStyle('overflow', 'hidden');
			
			if(!this.fullWidth[i]) this.fullWidth[i] = this.main.getStyle('width').toInt();
			if(!this.fullHeight[i]) this.fullHeight[i] = (!this.arrowsBoxHeight) ? this.sizes.height : this.sizes.height+this.arrowsBoxHeight;
			
			$$(this.main, this.wrapper).setStyles({'visibility': 'visible', 'height': '0px', 'width': '0px'});
			$$(this.arrowsBox).setStyles({'height': '0px', 'width': '0px'});
			//$$(this.arrowsBox).setStyle('width', this.fullWidth[i]);
			
			this.effects.main.elements = (this.options.enable.arrows) ? $$(this.main, this.wrapper, this.arrowsBox) : $$(this.main, this.wrapper);
			
			var width = {
				'0': { 'width': [this.main.getStyle('width').toInt(), this.fullWidth[i]] },
				'1': { 'width': [this.main.getStyle('width').toInt(), this.fullWidth[i]] }
			};
			
			var height = {
				'0': { 'height': [this.main.getStyle('height').toInt(), this.fullHeight[i]] },
				'1': { 'height': [this.main.getStyle('height').toInt(), this.sizes.height] }
			};
			
			if(this.options.enable.arrows) {
				var arrwidth = { '2': { 'width': this.fullWidth[i] } };
				var arrheight = { '2': { 'height': [0, this.arrowsBoxHalfHeight] } };
			}
			
			this.effects.main.start((arrwidth) ? $merge(width, arrwidth) : width).chain(function() {
				this.effects.main.start((arrheight) ? $merge(height, arrheight) : height);
			}.bind(this)).chain(function() {
				if(this.options.enable.arrows) $$(this.arrowsBox, this.arrowsBoxText).setStyle('visibility', 'visible');	
			}.bind(this));
		}
		else if(this.options.effect == 'slide:vertical' || this.options.effect == 'slide:horizontal' || this.options.effect == 'slide') {
			if(Browser.firefox) this.fullpage.setStyle('height', 'auto');
			if(this.options.enable.arrows) this.createArrowsBox();
			else this.main.inject(this.fullpage);
			
			if(!this.fullWidth[i]) this.fullWidth[i] = this.main.getStyle('width').toInt();
			if(!this.fullHeight[i]) this.fullHeight[i] = (!this.arrowsBoxHeight) ? this.sizes.height : this.sizes.height+this.arrowsBoxHeight;
			
			var direction = this.options.effect.split(':')[1] || 'vertical';
			
			if(direction == 'vertical')
				$$(this.main).setStyles({'visibility': 'visible', 'height': this.fullHeight[i], 'width': this.fullWidth[i], 'top': -1000});
			else if(direction == 'horizontal')
				$$(this.main).setStyles({'visibility': 'visible', 'height': this.fullHeight[i], 'width': this.fullWidth[i], 'left': -1000});
			
			$$(this.arrowsBox).setStyle('width', this.fullWidth[i]);
			
			switch(direction) {
				case 'vertical': var styles = {'top': window.getSize().y.toInt()/2 };
								break;
				case 'horizontal': var styles = {'left': window.getSize().x.toInt()/2 };
								break;
			}
	
			this.effects.main.elements = $$(this.main);
			this.effects.main.start({
				'0': styles
			}).chain(function() {
				if(this.options.enable.arrows) $$(this.arrowsBox, this.arrowsBoxText).setStyle('visibility', 'visible');	
			}.bind(this));
			
		}
	},
	
	virtualStyle: function(path) {
		new Asset.css(path, {id: 'virtualStyle'});
		return this;
	},
	
	setIDs: function(names) {
		if($object(names)) {
			for(var name in names) {
				if(this[name]) this[name].set('id', names[name]);
			}	
		}
		return this;
	}
});

/*
	Class: Virtual.single
	
	[Description] 
		Utility Wrapper to create single virtual boxes. Implemented by the other virtual single Classes.
	[/Description]
	
	[Methods]
		create -- calls the virtual box
	[/Methods]
	
	Method: create
	Description:  calls the virtual box
*/
Virtual.single = new Class({
						   
	attachElement: function() {
		this.element.addEvent('click', function(event) {
			event.preventDefault();
			this.attach(0);	
		}.bind(this));
	},
	
	create: function() {
		this.attach(0);	
	}
});

/*
	Filename: virtual_box.js
	
	[Description]
		Contains the Virtual.Box and Virtual.Box.single Classes to create customizable and flexible light boxes of images
	[/Description]
	
	Contains: Class Virtual.Box, Class Virtual.Box.single
	
	Requires: virtual_base.js, overlay.js, browser.js, type.js
	
	[Summary]
		Virtual.Box ::: Custom Class to create virtual boxes
		Virtual.Box.single ::: Custom Class to create single virtual boxes
	[/Summary]
*/
/*
	Class: Virtual.Box
	
	[Description] 
		Custom Class to create virtual boxes.
		Applies the virtual box effect to each link which has 'virtualbox' as value of the classname property.
	[/Description]
	
	Extends: Virtual
	
	Constructor: new Virtual.Box (options)
	
	[Properties] 
		options - optional. an object which permits to customize the virtual boxes
	[/Properties]
	
	[Options]
		Virtual Options : the options of the Virtual Class
	[/Options]
	
	[Note]
		You can set the contents of the caption by setting the title property of each link in this way: 
		'title :: content', where the separator is the ' :: ' string
	[/Note]
	
	[Example]
		> // applies the virtual box effect to each link which has 'virtualbox' as value of the classname property 
		> var virtual = new Virtual.Box({
		>	enable: {
		>		arrows: true,
		>		closeButton: true
		>	},
		>	effect: 'open',
		>	leftArrowText: '',
		>	rightArrowText: '',
		>	closeButtonText: '',
		>	captionOpacity: 0.6
		>	}
		> });
		>
		> // the HTML
		> <a href="flowers.jpg" class="virtualbox" title="My flowers">image 1</a>
	[/Example]
*/
Virtual.Box = new Class({
						
	Extends: Virtual,
	
	initialize: function(options, single) {
		this.links = $$('a[class=virtualbox]');
		this.preload = [];
		this.parent(options);
		
		this.mechanize();
		
		if(!single) {
			this.links.each(function(el, i) {
									 
				this.preload[i] = new Element('img');
				this.preload[i].src = el.getProperty('href');
		
				var fullText = el.getProperty('title').split(' :: ');
				
				this.preload[i].store('title', fullText[0]);
				this.preload[i].store('text', fullText[1]);
				
				el.addEvent('click', function(event) {
					event.preventDefault();
					this.attach(i);	
				}.bind(this));
				
			}, this);
		}
		
		this.count = 0;
		this.length = this.preload.length-1;
		this.fullLength = this.preload.length;
	},
	
	attach: function(i) {
		this.img = this.preload[i];
		this.count = i;
		
		if(!this.overlayActive) { 
			this.injectOverlay(true);
		}
		
		this.reset();
		
		this.prepareImage(i);
		this.makeCaptionEffect(i);
	},
	
	prepareImage: function(i) {
		this.sizes = {
			width: this.preload[i].width,
			height: this.preload[i].height,
			title: this.preload[i].retrieve('title'),
			text: this.preload[i].retrieve('text')
		};
		
		this.main.setStyles({
			'position': 'absolute',
			'width': this.sizes.width,
			'height': this.sizes.height,
			'top': window.getSize().y.toInt()/2,
			'left': window.getSize().x.toInt()/2,
			'margin-top': -(this.sizes.height/2),
			'margin-left': -(this.sizes.width/2)
		});
		
		this.wrapper.setStyles({
			'background-color': '#FFFFFF',
			'background-repeat': 'no-repeat',
			'background-image': 'url(' + this.preload[i].src + ')',
			'overflow': 'hidden',
			'width': this.sizes.width,
			'height': this.sizes.height			   
		});
		
		$$(this.caption, this.captionText).setStyles({'width': this.sizes.width});
		
		this.setArrowsBoxText('image ' + (i+1) + '/' + this.preload.length);
		this.fireEvent('onShow');
		this.makeEffect(i);
	}
});

/*
	Class: Virtual.Box.single
	
	[Description] 
		Custom Class to create single virtual boxes. Applies the virtual box effect to the given link.
	[/Description]
	
	Extends: Virtual.Box
	
	Implements: Virtual.single
	
	Constructor: new Virtual.Box.single (element, options)
	
	[Properties] 
		element - the element to apply the effect to
		options - optional. the options
	[/Properties]
	
	[Options]
		Virtual Options : the options of the Virtual Class
	[/Options]
	
	[Example]
		> // applies the virtual box effect to the 'myElement' link
		> var virtual = new Virtual.Box.single('myElement', {
		>	captionOpacity: 0.4,
		>	effect: 'fix'
		> });
		>
		> // the HTML
		> <a id="myElement" href="/my_imge.jpg" title="My Image :: One of the my collection of images">static content</a>
	[/Example]
*/
Virtual.Box.single = new Class({
								
	Extends: Virtual.Box,
	
	Implements: Virtual.single,
	
	initialize: function(element, options) {
		this.element = $(element);
		this.parent($merge(options, {enable: {arrows: false, arrowsKeyboard: false}}), true);
		this.preload[0] = new Element('img');
		var fullText = this.element.getProperty('title').split(' :: ');
	
		this.preload[0].src = this.element.getProperty('href');
		this.preload[0].store('title', fullText[0]);
		this.preload[0].store('text', fullText[1]);
			
		this.attachElement();
	}
});

/*
	Filename: virtual_ajax.js
	
	[Description]
		Contains the Virtual.Ajax and Virtual.Ajax.single Classes to create customizable and flexible light boxes of content loaded from the server
	[/Description]
	
	Contains: Class Virtual.Ajax, Class Virtual.Ajax.single
	
	Requires: virtual_base.js, overlay.js, browser.js, type.js
	
	[Summary]
		Virtual.Ajax ::: Custom Class to create ajax virtual boxes
		Virtual.Ajax.single ::: Custom Class to create single ajax virtual boxes
	[/Summary]
*/
/*
	Class: Virtual.Ajax
	
	[Description] 
		Custom Class to create ajax virtual boxes.
		Applies the virtual ajax effect to each link which has 'virtualajax' as value of the classname property.
	[/Description]
	
	Extends: Virtual
	
	Constructor: new Virtual.Ajax (options)
	
	[Properties] 
		options - optional. an object which permits to customize the virtual boxes
	[/Properties]
	
	[Options]
		Virtual Options : the options of the Virtual Class
	[/Options]
	
	[Note]
		You can set the dimensions of the virtual box and the contents of the caption by setting the title property of each link in this way: 
		'width :: height :: title :: content', where the separator is the ' :: ' string
	[/Note]
	
	[Example]
		> // applies the virtual ajax effect to each link which has 'virtualajax' as value of the classname property 
		> var virtual = new Virtual.Ajax({
		>	enable: {
		>		arrows: true,
		>		caption: false
		>	},
		>	effect: 'fix'
		> });
		>
		> // the HTML
		> <a href="my_page.php" class="virtualajax" title="460 :: 340">load my page</a>
	[/Example]
*/
Virtual.Ajax = new Class({
						
	Extends: Virtual,
	
	options: {
		width: 400,
		height: 300,
		requestOptions: {}
	},
	
	initialize: function(options, single) {
		this.links = $$('a[class=virtualajax]');
		this.preload = [];
		this.parent(options);
		this.request = new Request.HTML($merge(this.options.requestOptions, {update: this.wrapper}));
		
		this.mechanize();
		this.wrapreq = new Element('div').inject(this.wrapper, 'top');
		
		if(!single) {
			this.links.each(function(el, i) {				 
				this.preload[i] = new Hash();
				var fullText = el.getProperty('title').split(' :: ');
				
				this.preload[i].set('src',  el.get('href'));
				this.preload[i].set('width',  fullText[0].toInt() || this.options.width);
				this.preload[i].set('height',  fullText[1].toInt() || this.options.height);
				this.preload[i].set('title',  fullText[2]);
				this.preload[i].set('text', fullText[3]);
				
				el.addEvent('click', function(event) {
					event.preventDefault();
					this.attach(i);	
				}.bind(this));
			}, this);
		}
		
		this.count = 0;
		this.length = this.preload.length-1;
		this.fullLength = this.preload.length;
	},
	
	attach: function(i) {
		this.img = this.preload[i];
		this.count = i;
		
		if(!this.overlayActive) { 
			this.injectOverlay(true);
		}
		
		if(Browser.opera) this.main.dispose();
		this.reset();
		this.prepareRequest(i);
		this.makeCaptionEffect(i);
	},
	
	prepareRequest: function(i) {
		this.sizes = {
			width: this.preload[i].get('width'),
			height: this.preload[i].get('height'),
			title: this.preload[i].get('title'),
			text: this.preload[i].get('text')
		};
		
		this.main.setStyles({
			'position': 'absolute',
			'width': this.sizes.width,
			'height': this.sizes.height,
			'top': window.getSize().y.toInt()/2,
			'left': window.getSize().x.toInt()/2,
			'margin-top': -(this.sizes.height/2),
			'margin-left': -(this.sizes.width/2)
		});
		
		this.wrapper.setStyles({
			'width': this.sizes.width,
			'height': this.sizes.height
		});
		
		$$(this.caption, this.captionText).setStyles({'width': this.sizes.width});
		
		this.request.setOptions({url: this.preload[i].src, update: this.wrapreq,
			onSuccess: function() {
				if(this.options.enable.caption) {
					$$(this.caption, this.captionText).setStyles({
						'width': this.sizes.width				   
					}).inject(this.wrapper);
					this.captionTextTitle.set('html', this.sizes.title).inject(this.captionText);
					this.captionTextContent.set('html', this.sizes.text).inject(this.captionText);
				}		
			}.bind(this, i)
		}).post();
		
		this.setArrowsBoxText('Virtual Ajax ' + (i+1) + '/' + this.preload.length);
		this.fireEvent('onShow');
		this.makeEffect(i);
	}
});

/*
	Class: Virtual.Ajax.single
	
	[Description] 
		Custom Class to create single ajax virtual boxes. Applies the virtual ajax effect to the given link.
	[/Description]
	
	Extends: Virtual.Ajax
	
	Implements: Virtual.single
	
	Constructor: new Virtual.Ajax.single (element, options)
	
	[Properties] 
		element - the element to apply the effect to
		options - optional. the options
	[/Properties]
	
	[Options]
		Virtual Options : the options of the Virtual Class
	[/Options]
	
	[Example]
		> // applies the virtual ajax effect to the 'myElement' link
		> var virtual = new Virtual.Ajax.single('myElement', {
		>	style: false
		>	effect: 'open'
		> });
		>
		> // the HTML
		> <a id="myElement" href="/my_page.php" title="460 :: 340">static content</a>
	[/Example]
*/
Virtual.Ajax.single = new Class({
								
	Extends: Virtual.Ajax,
	
	Implements: Virtual.single,
	
	initialize: function(element, options) {
		this.element = $(element);
		this.parent($merge(options, {enable: {arrows: false, arrowsKeyboard: false}}), true);
		this.preload[0] = new Hash();
		var fullText = this.element.getProperty('title').split(' :: ');
		this.preload[0].set('src',  this.element.get('href'));
		this.preload[0].set('width',  fullText[0].toInt() || this.options.width);
		this.preload[0].set('height',  fullText[1].toInt() || this.options.height);
		this.preload[0].set('title',  fullText[2]);
		this.preload[0].set('text', fullText[3]);
			
		this.attachElement();
	}
});

/*
	Filename: virtual_html.js
	
	[Description]
		Contains the Virtual.HTML and Virtual.HTML.single Classes to create customizable and flexible light boxes of static HTML content
	[/Description]
	
	Contains: Class Virtual.HTML, Class Virtual.HTML.single
	
	Requires: virtual_base.js, overlay.js, browser.js, type.js
	
	[Summary]
		Virtual.HTML ::: Custom Class to create ajax virtual boxes
		Virtual.HTML.single ::: Custom Class to create single virtual html boxes
	[/Summary]
*/
/*
	Class: Virtual.HTML
	
	[Description] 
		Custom Class to create html virtual boxes.
		Applies the virtual html effect to each link which has 'virtualhtml' as value of the classname property.
	[/Description]
	
	Extends: Virtual
	
	Constructor: new Virtual.HTML (options)
	
	[Properties] 
		options - optional. an object which permits to customize the virtual boxes
	[/Properties]
	
	[Options]
		Virtual Options : the options of the Virtual Class
	[/Options]
	
	[Note]
		You can set the dimensions of the virtual box and the contents of the caption by setting the title property of each link in this way: 
		'width :: height :: title :: content', where the separator is the ' :: ' string
	[/Note]
	
	[Example]
		> // applies the virtual html effect to each link which has 'virtualajax' as value of the classname property 
		> var virtual = new Virtual.HTML({
		>	enable: {
		>		arrows: false,
		>		caption: false
		>	},
		>	effect: 'open',
		>	style: false,
		>	contents: ['<p>Simple Vitual.HTML</p>', '<div><b>More Complex <i>Virtual.HTML</i></b></div>']
		> });
		>
		> // the HTML
		> <a href="#" class="virtualhtml" title="460 :: 340">static content</a>
	[/Example]
*/
Virtual.HTML = new Class({
						
	Extends: Virtual,
	
	options: {
		width: 400,
		height: 300,
		contents: []
	},
	
	initialize: function(options, single) {
		this.links = $$('a[class=virtualhtml]');
		this.preload = [];
		this.parent(options);
		
		this.mechanize();
		this.content = new Element('div', {'id': 'virtualHTMLContent'});
		
		if(!single) {
			this.links.each(function(el, i) {
									 
				this.preload[i] = new Hash();
				var fullText = el.getProperty('title').split(' :: ');
				
				this.preload[i].set('width',  fullText[0].toInt() || this.options.width);
				this.preload[i].set('height',  fullText[1].toInt() || this.options.height);
				this.preload[i].set('title',  fullText[2]);
				this.preload[i].set('text', fullText[3]);
				
				el.addEvent('click', function(event) {
					event.preventDefault();
					this.attach(i);	
				}.bind(this));
				
			}, this);
		}
		
		this.count = 0;
		this.length = this.preload.length-1;
		this.fullLength = this.preload.length;
	},
	
	attach: function(i) {
		this.img = this.preload[i];
		this.count = i;
		
		if(!this.overlayActive) { 
			this.injectOverlay(true);
		}
		
		if(Browser.opera) this.main.dispose();
		this.reset();
		this.prepareContent(i);
		this.makeCaptionEffect(i);
	},
	
	prepareContent: function(i) {
		this.sizes = {
			width: this.preload[i].get('width'),
			height: this.preload[i].get('height'),
			title: this.preload[i].get('title'),
			text: this.preload[i].get('text')
		};
		
		this.main.setStyles({
			'position': 'absolute',
			'width': this.sizes.width,
			'height': this.sizes.height,
			'top': window.getSize().y.toInt()/2,
			'left': window.getSize().x.toInt()/2,
			'margin-top': -(this.sizes.height/2),
			'margin-left': -(this.sizes.width/2)
		});
		
		this.wrapper.setStyles({
			'width': this.sizes.width,
			'height': this.sizes.height
		});
		
		$$(this.caption, this.captionText).setStyles({'width': this.sizes.width});
		
		this.content.set('html', this.options.contents[i]).inject(this.wrapper, 'top');
		this.setArrowsBoxText('Virtual HTML ' + (i+1) + '/' + this.preload.length);
		this.fireEvent('onShow');
		this.makeEffect(i);
	}
});

/*
	Class: Virtual.HTML.single
	
	[Description] 
		Custom Class to create single virtual html boxes. Applies the virtual html effect to the given link.
	[/Description]
	
	Extends: Virtual.HTML
	
	Implements: Virtual.single
	
	Constructor: new Virtual.HTML.single (element, options)
	
	[Properties] 
		element - the element to apply the effect to
		options - optional. the options
	[/Properties]
	
	[Options]
		Virtual Options : the options of the Virtual Class
		content : the HTML content of the virtual box
	[/Options]
	
	[Example]
		> // applies the virtual html effect to the 'myElement' link
		> var virtual = new Virtual.HTML.single('myElement', {
		>	style: false
		>	effect: 'open',
		>	content: '<div><b>More Complex <i>Virtual.HTML</i></b></div>'
		> });
		>
		> // the HTML
		> <a id="myElement" href="#" title="460 :: 340">static content</a>
	[/Example]
*/
Virtual.HTML.single = new Class({
								
	Extends: Virtual.HTML,
	
	Implements: Virtual.single,
	
	options: {
		content: ''
	},
	
	initialize: function(element, options) {
		this.element = $(element);
		this.parent($merge(options, {enable: {arrows: false, arrowsKeyboard: false}}), true);
		this.preload[0] = new Hash();
		var fullText = this.element.getProperty('title').split(' :: ');
		this.preload[0].set('width',  fullText[0].toInt() || this.options.width);
		this.preload[0].set('height',  fullText[1].toInt() || this.options.height);
		this.preload[0].set('title',  fullText[2]);
		this.preload[0].set('text', fullText[3]);
		
		this.options.contents[0] = this.options.content;
		this.attachElement();
	}
});

/*
	Filename: kwick_menu.js
	
	[Description]  
		Allows you to create customized kwick menu for every needs, horizontal or vertical.
		In addiction contains the Kwick.All Class which allows you to kwick each property you want.
	[/Description]
	
	Contains: Class Kwick.Base, Kwick.Menu, Kwick.All
	
	[Summary]
		Kwick.Base ::: Base Class, internal. A wrapper for the Kwick.Menu Class
		Kwick.Menu ::: Custom Class to create customized kwick menu, horizontal or vertical
		Kwick.All ::: Custom Class to kwick each property you want
	[/Summary]
*/
/*
	Class: Kwick.Base
	
	Description: Base Class, internal. A wrapper for the Kwick.Menu Class
	
	Extends: Fx.Elements
	
	Constructor: new Kwick.Base (elements, options)
	
	[Properties] 
		element - the $$(elements) to apply the kwick to
		options - optional. The Fx.Element options plus some other options
	[/Properties]
	
	[Options]
		large : int. the large size
		normal : int. the normal size
		small : int. the small size
	[/Options]
*/
var Kwick = {};

Kwick.Base = new Class({
					   
	Extends: Fx.Elements,
	
	options: {
		large: 200,
		normal: 100,
		small: 50,
		link: 'cancel',
		duration:300,
		transition: 'back:out'
	},	
	
	initialize: function(elements, options) {
		this.parent(elements, options);
	},
	
	enter: function(prop, el, i) {
		var o = {};
		o[i] = {};
		o[i][prop] = [el.getStyle(prop), this.options.large];
		this.elements.each(function(other, j) {
			if(i != j) {
				var p = other.getStyle(prop);
				if(p != this.options.small) { 
					o[j] = {};
					o[j][prop] = [p, this.options.small];
				}
			}
		}, this);
		this.start(o);
	},
	
	out: function(prop) {
		var o = {};
		this.elements.each(function(el, i) {
			o[i] = {};
			o[i][prop] = [el.getStyle(prop), this.options.normal];
		}, this);
		this.start(o);
	},
	
	build: function(prop, el, i) {
		el.addEvent("mouseenter", this.enter.bind(this, [prop, el, i]));
	}
});

/*
	Class: Kwick.Menu
	Description:  Custom Class to create customized kwick menu, horizontal or vertical
	
	Extends: Class Kwick.Base
	
	Constructor: new Kwick.Menu (elements, options)
	
	[Properties] 
		element - the $$(elements) to apply the kwick to
		options - optional. The Kwick.Base options plus the following
	[/Properties]
	
	[Options]
		mode : 'vertical' (height transition, vertical) or 'horizontal' (width transition, horizontal, default)
	[/Options]
	
	[Example]
		> var kwick = new new Kwick.Menu($$("#kwick kwick"), {
		> 	mode: 'vertical'
		> });
	[/Example]
*/
Kwick.Menu = new Class({
					   
	Extends: Kwick.Base,
	
	options: {
		mode: 'horizontal'
	},
	
	initialize: function(elements, options) {
		this.parent(elements, options);
		this.ul = this.elements.getParent();
		switch(this.options.mode) {
			case 'vertical': this.elements.each(function(el, i) { this.build('height', el, i); }, this);
					  this.elements.each(function(el) { el.addEvent('mouseleave', this.out.bind(this, 'height')); }, this);
					  break;
					  
			case 'horizontal': this.elements.each(function(el, i) { this.build('width', el, i); }, this);
					  this.elements.each(function(el) { el.addEvent('mouseleave', this.out.bind(this, 'width')); }, this);
					  break;
		}; 
	}
});

/*
	Class: Kwick.All
	Description:  Custom Class to kwick each property you want for creating complex kwick transitions
	
	Extends: Class Kwick.Base
	
	Constructor: new Kwick.All (elements, property, options)
	
	[Properties] 
		element - the $$(elements) to apply the kwick to
		property - the property to kwick
		options - optional. The Fx.Element options plus the Kwick.Base options (see above)
	[/Properties]
	
	[Example]
		> var kwick = new new Kwick.All($$("#kwick kwick"), 'color', {
		> 	large:'#424F6F',
		>	normal: '#009966',
		>	small: '#F5F5F5'
		> });
	[/Example]
*/
Kwick.All = new Class({
					   
	Extends: Kwick.Base,
	
	initialize: function(elements, property, options) {
		this.parent(elements, options);
		this.property = property;
		this.elements.each(function(el, i) { this.build(this.property, el, i); }, this);
		this.elements.each(function(el) { el.addEvent('mouseleave', this.out.bind(this, this.property)); }, this);
	}
});

/*
	Filename: glider.js
	
	[Description] 
		Contains the Glider Class for making fully-customizable slidewshows based on scroll effects
	[/Description]
	
	Contains: Class Glider
	
	Requires: overlay.js, browser.js
	
	[Summary]
		Glider ::: A powerful Class which allows you to create modal fully-customizable slidewshows
	[/Summary]
*/
/*
	Class: Glider
	
	[Description]  
		The Glider Class allows you to create powerful and fully-customizable slideshows.
		You can set whatever you want: captions, thumbnails, arrows, keyboard arrows listeners,
		effects (fade and height transitions) scroll and morph options, whether enable the autostart or not,
		whether enable the autoresize (height and/or with) or not and many, many more.
		In addiction you can enable the full-screen mode, which is perfect for presentations.
	[/Description]
	
	Implements: Overlay, Options, Events
	
	Constructor: new Glider (element, options)
	
	[Properties] 
		element - the element which contains the glider (an 'ul' element)
		options - optional. an object which permits to customize the glider
	[/Properties]
	
	[Options]
		enable : an object which allows to decide which parameters and features the glider must have (see below)
		steps : the timer used by autostart to change periodically the slides. Default is 3000 ms
		mode : the mode of the glider. Can be 'scroll' or 'fix'
		captions : an array of captions contents
		captionWrapper : the id of the caption wrapper
		captionFadeEffect : if true the fade effect of the captions will be enabled
		captionHeightEffect : if true the height effect of the captions will be enabled
		scrollOptions : an object which represents the scroll options applied when mode is set to 'scroll'
		morphOptions : an object which represents the morph options for the caption effect
		thumbnailsWrapper : the id of the thumbnails wrapper
		thumbTexts : an array of thumbnails contents
		toNormalButtonClass : the class name of the button which closes the full-screen mode
		toNormalButtonText : the html content of the which closes the full-screen mode
		toNormalButtonType : the tag name of this button. Can be 'a' (default) or 'li'.
		toFullScreenButtonClass : the class name of the button which enables the full-screen mode
		toFullScreenButtonText : the html content of the which enables the full-screen mode
		toFullScreenButtonType : the tag name of this button. Can be 'a' (default) or 'li'.
	[/Options]
	
	>> enable:
		[List]
			[li] resizeHeight: if true the glider will auto-resize the element height 
			[li] resizeWidth: if true the glider will auto-resize the element width . Default is false
			[li] preloader: if true the preloader will be started 
	 		[li] captions: if true the captions will be enabled 
			[li] thumbnails: if true the thumbnails will be enabled. Default is false
			[li] arrows: if true the arrows will be enabled. Default is false
			[li] arrowsLimits: if true the left and right limit arrows will be enable. Default is false.
			[li] arrowsKeyboard: if true you can change the slide with the keyboard arrows. Default is false
			[li] autostart: if true the slides will be changed automatically. Deafult is false
			[li] fullscreen: if true if you press shift+f the glider will enter into 'full-screen mode'
			[li] toNormalButton: if true a button to come back to the normal mode will be added into full-screen mode
		[/List]
		
	[Note]
		If the tag name of the normal button or the full-screen button is set to 'a', the button
		will be placed into the thumbnails wrapper as link. Otherwise if it's set to 'li' it will be placed
		as a list item (always the last) into the list which contains thumbnails and/or arrows.
	[/Note]
		
	[Events]
		onFullScreen : function fired when the full-screen mode is enabled
		onNormalScreen : function fired when the normal-screen mode is enabled
		onNext : function fired when the next slide comes in. The silde number and the total length will be passed as arguments.
		onPrev : function fired when the previous slide comes in. The slide number and the total length will be passed as arguments.
		onGoTo : function fired when a specified silde comes in. The slide number and the total length will be passed as arguments.
		onFirst : function fired when the first silde comes in. The slide number and the total length will be passed as arguments.
		onLast : function fired when the last silde comes in. The slide number and the total length will be passed as arguments.
	[/Events]
	
	[Methods]
		next -- switchs to the next slide
		prev -- switchs to the previous slide
		goTo -- switchs to the given slide
		toFirst -- switchs to the first slide
		toLast -- switchs to the last slide
		start -- enables the autostart and starts the slideshow
		stop -- stops the slideshow
		toFullScreenMode -- makes the glider enter into the full-screen mode (also available by pressing shift+f)
		toNormalScreenMode -- disables the full-screen mode and comes back to the normal mode
		setMode -- sets the mode of the glider which means how slides come in. Can be 'scroll' (default) or 'fix'
		setIDs -- sets the id property for each section passed in
	[/Methods]
	
	Method: next
	Description:  switches to the next slide
	[Example]  
		> // go to the next slide
		> glider.next();
	[/Example]
	
	Method: prev
	Description:  switches to the previous slide
	[Example]  
		> // go to the previous slide
		> glider.prev();
	[/Example]
	
	Method: goTo
	Description:  switches to the given slide
	[Arguments]
		where :: the number of the slide
	[/Arguments]
	[Example]  
		> // go to the second slide
		> glider.goTo(2);
	[/Example]
	
	Method: toFirst
	Description:  switches to the first slide
	[Example]  
		> // go to the first slide
		> glider.toFirst();
	[/Example]
	
	Method: toLast
	Description:  switches to the last slide
	[Example]  
		> // go to the last slide
		> glider.toLast();
	[/Example]
	
	Method: start
	Description:  enables the autostart and starts the slideshow
	[Example]  
		> glider.start();
	[/Example]
	
	Method: stop
	Description:  stops the slideshow
	[Example]  
		> glider.stop();
	[/Example]
	
	Method: toFullScreenMode
	Description:  makes the glider enter into the full-screen mode (also available by pressing shift+f)
	[Example]  
		> // enter into the full-screen mode
		> glider.toFullScreenMode();
	[/Example]
	
	Method: toNormalScreenMode
	Description:  disables the full-screen mode and comes back to the normal mode
	[Example]  
		> // come back to the normal mode
		> glider.toNormalScreenMode();
	[/Example]
	
	Method: setIDs
	Description:  sets the id property for each section passed in
	[Arguments]
		names :: an object with key/value pairs which represents the glider zones and their new values
	[/Arguments]
	[Example]  
		> glider.setIDs({
		> 	leftArrow: 'newLeftArrow',
		>	rightArrow: 'newRightArrow'
		> });
	[/Example]
	
	Method: setMode
	Description:  sets the mode of the glider which means how slides come in. Can be 'scroll' (default) or 'fix'
	[Arguments]
		mode :: the mode of the glider. Can be 'scroll' or 'fix'
	[/Arguments]
	[Example]  
		> // set the 'fix' mode
		> glider.setMode('fix');
		> // now set the 'scroll' mode
		> glider.setMode('scroll');
	[/Example]
*/
var Glider = new Class({
					   
	Implements: [Overlay, Options, Events],
	
	options: {
		enable: {
			resizeHeight: true,
			resizeWidth: false,
			preloader: true,
			captions: true,
			thumbnails: false,
			arrows: false,
			arrowsLimits: false,
			arrowsKeyboard: false,
			autostart: false,
			fullscreen: false,
			toNormalButton: true,
			toFullScreenButton: false
		},
		steps: 3000,
		mode: 'scroll',
		captions: [],
		captionWrapper: 'captionWrapper',
		captionFadeEffect: true,
		captionHeightEffect: true,
		scrollOptions: {},
		morphOptions: {},
		thumbnailWrapper: 'thumbsWrapper',
		thumbTexts: [],
		toNormalButtonClass: '',
		toNormalButtonText: 'normal mode',
		toNormalButtonType: 'a',
		toFullScreenButtonClass: '',
		toFullScreenButtonText: 'full screen',
		toFullScreenButtonType: 'a',
		onFullScreen: $empty,
		onNormalScreen: $empty,
		onNext: $empty,
		onPrev: $empty,
		onGoTo: $empty,
		onFirst: $empty,
		onLast: $empty
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.fx = new Fx.Scroll(this.element, $merge(this.options.scrollOptions, {link:'chain', wheelStops:false}));
		this.count = 0;
		this.matter = 0;
		this.length = this.element.getChildren().length.toInt()-1;
		this.fullLength = this.element.getChildren().length.toInt();
		this.wrapper = this.element.getParent();
		this.main = this.wrapper.getParent();
		this.main.setStyle('position', 'relative');
		this.caption = new Element('div', { 'id': this.options.captionWrapper}).inject(this.element.getParent(), 'after').setStyle('display', (this.options.enable.captions) ? 'block' : 'none');
		if(this.options.enable.captions && this.options.captions[0]) this.caption.set('html', this.options.captions[0]);
		this.fxcapt = new Fx.Morph(this.caption, this.options.morphOptions);
		this.activizeFullscreen = false;
		
		this.checkResize();
		
		if(this.options.enable.preloader) {
			this.images = [];
			this.element.getChildren().each(function(li, i) {
				this.images[i] = li.getFirst().getProperty('src');
			}, this);
			new Asset.images(this.images);
		}
		
		if(this.options.enable.arrows) {
			this.leftArrow = new Element('li', {'id': 'leftArrow'}).addEvent('click', this.prev.bind(this));
			this.rightArrow = new Element('li', {'id': 'rightArrow'}).addEvent('click', this.next.bind(this));
			
			if(this.options.enable.arrowsLimits) {
				this.leftArrowLimit = new Element('li', {'id': 'leftArrowLimit'}).addEvent('click', this.toFirst.bind(this));
				this.rightArrowLimit = new Element('li', {'id': 'rightArrowLimit'}).addEvent('click', this.toLast.bind(this));
			}
			
			if(!this.options.enable.thumbnails) {
				this.thumbsWrapper = new Element('div', {'id': this.options.thumbnailWrapper}).inject(this.caption, 'after');
				this.thumbs = new Element('ul').injectInside(this.thumbsWrapper);
				this.leftArrow.inject(this.thumbs, 'top');
				this.rightArrow.inject(this.thumbs);
				
				if(this.options.enable.arrowsLimits) {
					this.leftArrowLimit.inject(this.thumbs, 'top');
					this.rightArrowLimit.inject(this.thumbs);
				}
			}
		}
		
		if(this.options.enable.arrowsKeyboard) {
			this.boundKeyboard = this.keyboard.bindWithEvent(this);
			document.addEvent('keydown', this.boundKeyboard);
		}
		
		if(this.options.enable.thumbnails) {
			this.thumbsWrapper = new Element('div', {'id': this.options.thumbnailWrapper}).inject(this.caption, 'after');
			this.thumbs = new Element('ul').injectInside(this.thumbsWrapper);
			this.items = [];
			this.element.getChildren().each(function(li, i) {
				(this.options.thumbTexts[i]) ? this.text = this.options.thumbTexts[i] : this.text = 'item ' + i;
				this.items[i] = new Element('li').set('html', this.text).addEvent('click', function(event) {
					event.stop();
					this.items.each(function(item) { item.removeClass('activeThumb')});
					this.items[i].addClass('activeThumb');
					this.goTo(i);
				}.bind(this)).injectInside(this.thumbs);
			}, this);
			this.activize(0);
			if(this.options.enable.arrows) {
				this.leftArrow.inject(this.thumbs, 'top');
				this.rightArrow.inject(this.thumbs);
			}
			if(this.options.enable.arrowsLimits) {
				this.leftArrowLimit.inject(this.thumbs, 'top');
				this.rightArrowLimit.inject(this.thumbs);
			}
		}
		
		this.createFullScreenButton();
		
		if(this.options.enable.autostart) { 
			if(this.options.enable.thumbnails) this.activize(0);
			this.start();
		}
		
		if(this.options.enable.fullscreen) {
			this.wrapperStyles = this.wrapper.getStyles();
			if(this.main.getParent()) this.mainParent = this.main.getParent();
			this.boundFullScreen = this.fullscreen.bindWithEvent(this);
			document.addEvent('keydown', this.boundFullScreen);
		}
	},
	
	next: function() {
		(this.count != this.length) ? this.count++ : this.count = 0;
		this.checkResize();
		this.setFullScreenSizes();
		this.makeScroll(this.count, false, 'next');
		this.addCaption(this.options.captionFadeEffect, this.options.captionHeightEffect);
		this.fireEvent('onNext', [this.count, this.fullLength]);
		if(this.options.enable.thumbnails) this.activize(this.count);
	},
	
	prev: function() {
		(this.count == 0) ? this.count = this.length : this.count--;
		this.checkResize();
		this.setFullScreenSizes();
		this.makeScroll(this.count, false, 'prev');
		this.addCaption(this.options.captionFadeEffect, this.options.captionHeightEffect);
		this.fireEvent('onPrev', [this.count, this.fullLength]);
		if(this.options.enable.thumbnails) this.activize(this.count);
	},
	
	goTo: function(where, fix, from) {
		var where = where;
		this.count = where;
		this.checkResize();
		this.setFullScreenSizes();
		if(this.autostart) {
			this.steps = $clear(this.steps);
			this.steps = this.next.periodical(this.options.steps, this);
		}
		this.makeScroll(this.count, fix || false, from);
		this.addCaption(this.options.captionFadeEffect, this.options.captionHeightEffect);
		this.fireEvent('onGoTo', [this.count, this.fullLength]);
		if(this.options.enable.thumbnails) this.activize(this.count);
	},
	
	start: function() {
		this.steps = this.next.periodical(this.options.steps, this);
		this.autostart = true;
	},
	
	stop: function() {
		this.steps = $clear(this.steps);	
		this.autostart = false;
	},
	
	toFirst: function() {
		this.goTo(0, false, 'first');
		this.fireEvent('onFirst', [this.count, this.fullLength]);
	},
	
	toLast: function() {
		this.goTo(this.length, false, 'last');
		this.fireEvent('onLast', [this.count, this.fullLength]);
	},
	
	makeScroll: function(where, fix, from) {
		if(fix)
			this.element.scrollTop = this.element.getChildren()[where].getPosition(this.element).y.toInt();
		else {
			switch(this.options.mode) {
				case 'scroll':
					this.fx.start(0, this.element.getChildren()[this.count].getPosition(this.element).y.toInt());
					break;
				
				case 'fix':
					this.element.scrollTop = this.element.getChildren()[where].getPosition(this.element).y.toInt();
					break;
			}
		}
	},
	
	setMode: function(mode) {
		if(mode == 'fix' || mode == 'scroll') this.options.mode = mode;
	},
	
	checkResize: function() {
		if(this.options.enable.resizeHeight) {
			this.style = this.element.getChildren()[this.count].getFirst().getStyle('height').toInt();
			$$(this.wrapper, this.element, this.element.getChildren()[this.count]).setStyle('height', this.style);
		}
		if(this.options.enable.resizeWidth) {
			this.width = this.element.getChildren()[this.count].getFirst().getStyle('width').toInt();
			$$(this.wrapper, this.element, this.element.getChildren()[this.count], this.caption).setStyle('width', this.width);
			if(this.thumbsWrapper) this.thumbsWrapper.setStyle('width', this.width);
		}
	},
	
	addCaption: function(fade, height) {
		if(this.options.enable.captions && this.options.captions.length !=0) {
			if(this.options.captions[this.count]) this.caption.set('html', this.options.captions[this.count]);
			this.fxcaption = {};
			if(fade) 
				this.fxcaption['opacity'] = [0, 1];
			if(height)
				this.fxcaption['height'] = (this.options.captionHeightEffect) ? [0, this.caption.getStyle('height')] : [this.caption.getStyle('height')];			
			this.fxcapt.start(this.fxcaption);
		}
	},
	
	keyboard: function(event) {
		if(event.key == 'right') this.next();
		else if(event.key == 'left') this.prev();	
	},
	
	fullscreen: function(event) {
		if(event.shift && event.key == 'f') this.toFullScreenMode();			
	},
	
	setFullScreenSizes: function() {
		if(this.activizeFullscreen) {
			this.sizes = { 
				width: this.wrapper.getStyle('width').toInt() + this.caption.getStyle('width').toInt() + this.thumbsWrapper.getStyle('width').toInt(),
				height: this.wrapper.getStyle('height').toInt() + this.caption.getStyle('height').toInt() + this.thumbsWrapper.getStyle('height').toInt(),
				top: this.wrapper.getSize().y/2 + this.caption.getSize().y/2 + this.thumbsWrapper.getSize().y/2,
				left: this.wrapper.getSize().x/2
			};
			
			this.full.setStyles({
				'width': this.sizes.width,
				'height': this.sizes.height,
				'top': '50%', 
				'left': '50%', 
				'position': (!Browser.ie6) ? 'fixed' : 'absolute', 
				'margin-top': -this.sizes.top, 
				'margin-left': -this.sizes.left
			});
		}
	},
	
	toFullScreenMode: function(event) {
		if(this.activizeFullscreen) return;
			this.full = new Element('div').wraps(this.wrapper).wraps(this.caption);
			this.activizeFullscreen = true;
			
			if(this.thumbsWrapper) { 
				this.createNormalButton();
				this.full.wraps(this.thumbsWrapper);
			}
			this.createOverlay('gliderOverlay', 'darken');
			this.createFullPage('gliderFullPage');
			this.overlay.inject(document.body);
			
			this.fixOverlay();
			
			(this.options.enable.toNormalButton) ? this.toNormal.addEvent('click', this.toNormalMode.bindWithEvent(this)) : this.fullpage.addEvent('click', this.toNormalMode.bindWithEvent(this));
			this.fullpage.inject(document.body);
			
			this.setFullScreenSizes();
			this.full.inject(this.fullpage);
			
			this.goTo(this.count, true);
			this.fireEvent('onFullScreen', [this.count, this.fullLength]);
	},
	
	toNormalMode: function(event) {
		event.preventDefault();
		if(!this.options.enable.toNormalButton && event.target != this.fullpage) return;
		
		this.activizeFullscreen = false;
		if(this.mainParent) {
			if(this.options.enable.toNormalButton) this.toNormal.dispose();
			if(this.options.enable.toFullScreenButton) this.createFullScreenButton();
			this.wrapper.inject(this.main);
			this.caption.inject(this.wrapper, 'after');
			if(this.thumbsWrapper) this.thumbsWrapper.inject(this.caption, 'after');
			this.goTo(this.count, true);
			this.fireEvent('onNormalScreen', [this.count, this.fullLength]);
		}
		
		this.removeOverlay();
		this.fullpage.dispose();
	},
	
	createNormalButton: function() {
		if(this.options.enable.toNormalButton) {
			if(this.options.toNormalButtonType == 'a') {
				this.toNormal = new Element('a', {
				'class': this.options.toNormalButtonClass, 'href': '#'});
				this.toNormal.set('html', this.options.toNormalButtonText).inject(this.thumbsWrapper);
				if(this.toFull) this.toFull.dispose();
			}
			else if(this.options.toNormalButtonType == 'li') {
				this.toNormal = new Element('li', {
				'class': this.options.toNormalButtonClass});
				this.toNormal.set('html', this.options.toNormalButtonText).inject(this.thumbs);
				if(this.toFull) this.toFull.dispose();
			}
		}
	},
	
	createFullScreenButton: function() {
		if(this.options.enable.toFullScreenButton && (this.options.enable.arrows || this.options.enable.thumbnails)) {
			if(this.options.toFullScreenButtonType == 'a') {
				this.toFull = new Element('a', {
				'class': this.options.toFullScreenButtonClass, 'href': '#'});
				this.toFull.set('html', this.options.toFullScreenButtonText).inject(this.thumbsWrapper);
			}
			else if(this.options.toFullScreenButtonType == 'li') {
				this.toFull = new Element('li', {
				'class': this.options.toFullScreenButtonClass});
				this.toFull.set('html', this.options.toFullScreenButtonText).inject(this.thumbs);
			}
			this.toFull.addEvent('click', this.toFullScreenMode.bindWithEvent(this))
		}
	},
	
	setIDs: function(names) {
		if(!names) return;
		if(names.captionWrapper) this.caption.set('id', names.captionWrapper);
		if(names.thumbnailWrapper) this.thumbsWrapper.set('id', names.thumbnailWrapper);
		if(names.leftArrow) this.leftArrow.set('id', names.leftArrow);
		if(names.rightArrow) this.rightArrow.set('id', names.rightArrow);
		if(names.leftArrowLimit) this.leftArrowLimit.set('id', names.leftArrowLimit);
		if(names.rightArrowLimit) this.rightArrowLimit.set('id', names.rightArrowLimit);
		if(names.toFullScreenButton) this.toFull.set('id', names.toFullScreenButton);
		if(names.toNormalButton) this.toNormal.set('id', names.toNormalButton);
	},
	
	activize: function(i) {
		if(this.options.enable.thumbnails) {
			this.items.each(function(item) { item.removeClass('activeThumb')});
			this.items[i].addClass('activeThumb');
		}
	}
					   
});

/*
	Filename: tutorial.js
	
	[Description]
		Contains the Tutorial Class which allows to create professional tutorials and step by step presentations.
	[/Description]
	
	Contains: Class Tutorial
	
	[Summary]
		Tutorial ::: Class for creating tutorials and step by step presentations
	[/Summary]
*/
/*
	Class: Tutorial
	
	[Description] 
		Class for creating tutorials and step by step presentations.
	[/Description]
	
	Extends: Fx.Elements
	
	Constructor: new Tutorial (element, options)
	
	[Properties] 
		element - the main wrapper that contains the single steps
		options - the options. See below
	[/Properties]
	
	[Options]
		arrowsKeyboard : if true you can change the step by using the keyboard's arrows. Default is true.
		names : an object which contains the class names of the Tutorial section. You can pass as keywords: step, next and prev.
		cycle : if true you can change the steps as a cycle (from last to first for example). Default is false.
		autostart : if true the presentation will be automated.
		steps : if the autostart option is true this option indicates the time delay of each step call. Default is 4000 ms.
	[/Options]
	
	>> names:
		[List]
			[li] step: the class name of the nested elements which represent the single steps
			[li] prev: the class name of the link which changes to the previous step
			[li] next: the class name of the link which changes to the next step
		[/List]
	
	[Methods]
		prev -- goes to the previous step
		next -- goes to the next step
		autostart -- autostarts the presentation. If the cycle option is true the presentation doesn't stop until an user stop it
		stop -- stops the presentation
	[/Methods]
	
	[Example]
		> var tutorial = new Tutorial('main', {cycle: true});
	[/Example]
	
	Method: prev
	Description: goes to the previous step  
	[Example]
		> turorial.prev();
	[/Example]
	
	Method: next
	Description: goes to the next step  
	[Example]
		> turorial.next();
	[/Example]
	
	Method: autostart
	Description:  autostarts the presentation. If the cycle option is true the presentation doesn't stop until an user stop it
	[Example]
		> turorial.autostart();
	[/Example]
	
	Method: stop
	Description: stops the presentation  
	[Example]
		> turorial.stop();
	[/Example]
*/
var Tutorial = new Class({
						 
	Extends: Fx.Elements,
						 
	options: {
		arrowsKeyboard: true,
		names: {
			step: 'step',
			next: 'next',
			prev: 'prev'
		},
		cycle: false,
		autostart: false,
		steps: 4000
	},
	
	initialize: function(element, options) {
		this.element = $(element);
		this.parent(null, $merge(options, {link:''}));
		this.steps = this.element.getElements('div.' + this.options.names.step);
		this.length = this.steps.length-1;
		this.padding = this.element.getStyle('padding-top').toInt() + this.element.getStyle('padding-bottom').toInt();
		this.element.setStyle('height', this.steps[0].getHeight().toInt()+this.padding);
		this.count = 0;
		
		this.steps.each(function(step, i) {
			if(step.getElement('a.' + this.options.names.next)) { 
				step.store('next', step.getElement('a.' + this.options.names.next));
				step.retrieve('next').addEvent('click', function(event) {
					event.stop();
					this.next();
				}.bind(this));
			}
			
			if(step.getElement('a.' + this.options.names.prev)) {
				step.store('prev', step.getElement('a.' + this.options.names.prev));
				step.retrieve('prev').addEvent('click', function(event) {
					event.stop();
					this.prev();
				}.bind(this));
			}
	
			step.store('height', step.getHeight().toInt()+this.padding).store('position', i);
			
			if(i!=0) step.setStyle('height', 0);
			
		}, this);	
		
		if(this.options.arrowsKeyboard) document.addEvent('keydown', this.arrows.bindWithEvent(this));
		if(this.options.autostart) this.autostart();
	},
	
	next: function() {
		var obj = {};
		
		if(this._autostart && this.count == this.length) $clear(this._autostart);
		
		if(!this.timer) {
			if(this.options.cycle || this.count < this.length) this.setNext(obj);
		}
	},
	
	setNext: function(obj) {
		this.first = this.steps[this.count];
		(this.count != this.length) ? this.count++ : this.count = 0;
		this.second = this.steps[this.count];
			
		this.main(obj);
	},

	prev: function() {
		var obj = {};
		
		if(!this.timer) {
			if(this.options.cycle || this.count > 0) this.setPrev(obj);
		}
	},
	
	setPrev: function(obj) {
		this.first = this.steps[this.count];
		(this.count == 0) ? this.count = this.length : this.count--;
		this.second = this.steps[this.count];
		
		this.main(obj);
	},
	
	main: function(obj) {
		this.elements = $$(this.first, this.second, this.element);
		
		obj['0'] = {'height': 0};
		obj['1'] = {'height': this.second.retrieve('height')};
		obj['2'] = {'height': this.second.retrieve('height')};
		
		this.start(obj);
	},
	
	autostart: function() {
		this._autostart = this.next.periodical(this.options.steps || 4000, this);
	},
	
	stop: function() {
		$clear(this._autostart);
	},
	
	arrows: function(event) {
		if(event.key == 'left') this.prev();	
		if(event.key == 'right') this.next();
	}
});

/*
	Filename: tabs.js
	
	[Description]
		Contains the Tabs Class to create professional tab-based interfaces.
	[/Description]
	
	Contains: Class Tabs
	
	[Summary]
		Tabs ::: Custom Class for creating tab-based interfaces 
	[/Summary]
*/
/*
	Class: Tabs
	
	[Description] 
		Allows to create professional tab-based interfaces with many additional controls, like the scrolling effect,
		the autoresizing, the opening tab and more. Note that in the Tabs namespacing, the 'tabs' represent
		the contents while the 'sections' represent the handlers (the list items).
	[/Description]
	
	Extends: 
	
	Constructor: new Tabs(element, options)
	
	[Properties] 
		element - the container element
		options - the Tabs options. See below
	[/Properties]
	
	[Options]
		effect : the transition effect used to change the tabs. Can be 'scroll' or 'fix'
		autoresize : if true the tabs will be autoresized. Default is true.
		scrollOptions : the additional Fx.Scroll options
		opening : the tab which will be activated at first. Default is 0.
		openingEffect : the opening effect, 'scroll' or 'fix' (default). Can be different from the 'effect' option.
		names : an object containing the class names of the sections represent the Tabs interface. See below.
	[/Options]
	
	>> names:
	[List]
		[li] wrapper: the class name of the wrapper which contains the tabs. Default is 'tabs'
		[li] sections: the class name of the list element that contains the sections. Deafukt is 'sections'
		[li] tab: the class name of the elements represent the tabs. Default is 'tab'
	[/List]

    [Events]
		onOpen : function fired if the 'opening' option is a number represents a tab. The tab element and its position will be passed as arguments.
		onChange : function fired when an user changes to another tab. The tab element, the section and the tab position will be passed as arguments.
	[/Events]
	
	[Example]
		> var tabs = new Tabs('main', {
		>	autoresize: false,
		>	opening: 2,
		>	openingEffect: 'scroll',
		>	effect: 'fix',
		>	onChange: function(tab, section, i) {
		>		this.sections.removeClass('active');
		>		section.addClass('active');
		>	}
		> });
	[/Example]
*/
var Tabs = new Class({
	
	Implements: [Events, Options],
	
	options: {
		effect: 'scroll',
		autoresize: true,
		names: {
			wrapper: 'tabs',
			sections: 'sections',
			tab: 'tab'
		},
		scrollOptions: {},
		onChange: $empty,
		onOpen: $empty,
		opening: 0,
		openingEffect: 'fix'
	},
	
	initialize: function(element, options) {
		this.main = $(element);
		this.setOptions(options);
		this.wrapper = this.main.getElement('.' + this.options.names.wrapper);
		this.sections = this.main.getElement('ul.' + this.options.names.sections).getElements('li');
		this.tabs = this.wrapper.getElements('.' + this.options.names.tab);
		
		this.wrapper.setStyles({'overflow': 'hidden'});
		
		this.tabs.each(function(tab, i) {
			tab.store('height', tab.getHeight());
		}, this);
		
		this.fx = new Fx.Scroll(this.wrapper, this.options.scrollOptions);
		
		if($int(this.options.opening) && this.sections[this.options.opening]) { 
			this.goTo(this.sections[this.options.opening], this.options.opening, this.options.openingEffect);
			this.fireEvent('onOpen', [this.sections[this.options.opening], this.options.opening]);	
		}
		
		this.sections.each(function(section, i) {
			section.addEvent('click', this.goTo.bind(this, [section, i]));
		}, this);
	},
	
	goTo: function(section, i, effect) {
		var tab = this.tabs[i], height = tab.retrieve('height'), count = i, method = false, eff = this.options.effect;
		
		if(effect) this.options.effect = effect;
		
		if(eff == 'scroll' && !this.fx.timer)
			method = 'start';
		else if(eff == 'fix')
			method = 'set';
		
		if(method) {
			this.fireEvent('onChange', [tab, section, count]);
			if(this.options.autoresize) $$(this.wrapper, tab).setStyle('height', height);
			this.fx[method](0, tab.getPosition(this.wrapper).y.toInt());
		}
		
		if(effect)	this.options.effect = eff;
	}

});
