PageSourceSearch

https://peder.sk/sk/templates/at_minerva/at_menu/at_menu/mootools.v1.1.js

js peder.sk collected 2026-10-03 18:11:11 UTC 187,492 bytes, 6,964 lines download raw bytes

1/*
2Script: Core.js
3	Mootools - My Object Oriented javascript.
4
5License:
6	MIT-style license.
7
8MooTools Copyright:
9	copyright (c) 2007 Valerio Proietti, <http://mad4milk.net>
10
11MooTools Credits:
12	- Class is slightly based on Base.js <http://dean.edwards.name/weblog/2006/03/base/> (c) 2006 Dean Edwards, License <http://creativecommons.org/licenses/LGPL/2.1/>
13	- Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
14	- Documentation by Aaron Newton (aaron.newton [at] cnet [dot] com) and Valerio Proietti.
15*/
16
17var MooTools = {
18	'version': 1.1
19};
20
21/*
22Function: $defined
23	Returns true if the passed in value/object is defined, that means is not null or undefined.
24
25Arguments:
26	obj - object to inspect
27*/
28
29function $defined(obj){
30	return (obj != undefined);
31};
32
33/*
34Function: $type
35	Returns the type of object that matches the element passed in.
36
37Arguments:
38	obj - the object to inspect.
39
40Example:
41	>var myString = 'hello';
42	>$type(myString); //returns "string"
43
44Returns:
45	'element' - if obj is a DOM element node
46	'textnode' - if obj is a DOM text node
47	'whitespace' - if obj is a DOM whitespace node
48	'arguments' - if obj is an arguments object
49	'object' - if obj is an object
50	'string' - if obj is a string
51	'number' - if obj is a number
52	'boolean' - if obj is a boolean
53	'function' - if obj is a function
54	'regexp' - if obj is a regular expression
55	'class' - if obj is a Class. (created with new Class, or the extend of another class).
56	'arguments' - if obj is the arguments object.
57	'collection' - if obj is a native htmlelements collection, such as childNodes, getElementsByTagName .. etc.
58	false - (boolean) if the object is not defined or none of the above.
59*/
60
61function $type(obj){
62	if (!$defined(obj)) return false;
63	if (obj.htmlElement) return 'element';
64	var type = typeof obj;
65	if (type == 'object' && obj.nodeName){
66		switch(obj.nodeType){
67			case 1: return 'element';
68			case 3: return /\S/.test(obj.nodeValue) ? 'textnode' : 'whitespace';
69		}
70	}
71	if (type == 'object' || type == 'function'){
72		switch(obj.constructor){
73			case Array: return 'array';
74			case RegExp: return 'regexp';
75			case Class: return 'class';
76		}
77		if (typeof obj.length == 'number'){
78			if (obj.item) return 'collection';
79			if (obj.callee) return 'arguments';
80		}
81	}
82	return type;
83};
84
85/*
86Function: $merge
87	merges a number of objects recursively without referencing them or their sub-objects.
88
89Arguments:
90	any number of objects.
91
92Example:
93	>var mergedObj = $merge(obj1, obj2, obj3);
94	>//obj1, obj2, and obj3 are unaltered
95*/
96
97function $merge(){
98	var mix = {};
99	for (var i = 0; i < arguments.length; i++){
100		for (var property in arguments[i]){
101			var ap = arguments[i][property];
102			var mp = mix[property];
103			if (mp && $type(ap) == 'object' && $type(mp) == 'object') mix[property] = $merge(mp, ap);
104			else mix[property] = ap;
105		}
106	}
107	return mix;
108};
109
110/*
111Function: $extend
112	Copies all the properties from the second passed object to the first passed Object.
113	If you do myWhatever.extend = $extend the first parameter will become myWhatever, and your extend function will only need one parameter.
114
115Example:
116	(start code)
117	var firstOb = {
118		'name': 'John',
119		'lastName': 'Doe'
120	};
121	var secondOb = {
122		'age': '20',
123		'sex': 'male',
124		'lastName': 'Dorian'
125	};
126	$extend(firstOb, secondOb);
127	//firstOb will become:
128	{
129		'name': 'John',
130		'lastName': 'Dorian',
131		'age': '20',
132		'sex': 'male'
133	};
134	(end)
135
136Returns:
137	The first object, extended.
138*/
139
140var $extend = Object.extend = function(){
141	var args = arguments;
142	if (!args[1]) args = [this, args[0]];
143	for (var property in args[1]) args[0][property] = args[1][property];
144	return args[0];
145};
146
147/*
148Function: $native
149	Will add a .extend method to the objects passed as a parameter, but the property passed in will be copied to the object's prototype only if non previously existent.
150	Its handy if you dont want the .extend method of an object to overwrite existing methods.
151	Used automatically in mootools to implement Array/String/Function/Number methods to browser that dont support them whitout manual checking.
152
153Arguments:
154	a number of classes/native javascript objects
155
156*/
157
158var $native = Object.Native = function(){
159	for (var i = 0, l = arguments.length; i < l; i++){
160		arguments[i].extend = function(props){
161			for (var prop in props){
162				if (!this.prototype[prop]) this.prototype[prop] = props[prop];
163				if (!this[prop]) this[prop] = $native.generic(prop);
164			}
165		};
166	}
167};
168
169$native.generic = function(prop){
170	return function(bind){
171		return this.prototype[prop].apply(bind, Array.prototype.slice.call(arguments, 1));
172	};
173};
174
175$native(Function, Array, String, Number);
176
177/*
178Class: Abstract
179	Abstract class, to be used as singleton. Will add .extend to any object
180
181Arguments:
182	an object
183
184Returns:
185	the object with an .extend property, equivalent to <$extend>.
186*/
187
188var Abstract = function(obj){
189	obj = obj || {};
190	obj.extend = $extend;
191	return obj;
192};
193
194//window, document
195
196var Window = new Abstract(window);
197var Document = new Abstract(document);
198document.head = document.getElementsByTagName('head')[0];
199
200/* Section: Utility Functions */
201
202/*
203Function: $chk
204	Returns true if the passed in value/object exists or is 0, otherwise returns false.
205	Useful to accept zeroes.
206
207Arguments:
208	obj - object to inspect
209*/
210
211function $chk(obj){
212	return !!(obj || obj === 0);
213};
214
215/*
216Function: $pick
217	Returns the first object if defined, otherwise returns the second.
218
219Arguments:
220	obj - object to test
221	picked - the default to return
222
223Example:
224	(start code)
225		function say(msg){
226			alert($pick(msg, 'no meessage supplied'));
227		}
228	(end)
229*/
230
231function $pick(obj, picked){
232	return $defined(obj) ? obj : picked;
233};
234
235/*
236Function: $random
237	Returns a random integer number between the two passed in values.
238
239Arguments:
240	min - integer, the minimum value (inclusive).
241	max - integer, the maximum value (inclusive).
242
243Returns:
244	a random integer between min and max.
245*/
246
247function $random(min, max){
248	return Math.floor(Math.random() * (max - min + 1) + min);
249};
250
251/*
252Function: $time
253	Returns the current timestamp
254
255Returns:
256	a timestamp integer.
257*/
258
259function $time(){
260	return new Date().getTime();
261};
262
263/*
264Function: $clear
265	clears a timeout or an Interval.
266
267Returns:
268	null
269
270Arguments:
271	timer - the setInterval or setTimeout to clear.
272
273Example:
274	>var myTimer = myFunction.delay(5000); //wait 5 seconds and execute my function.
275	>myTimer = $clear(myTimer); //nevermind
276
277See also:
278	<Function.delay>, <Function.periodical>
279*/
280
281function $clear(timer){
282	clearTimeout(timer);
283	clearInterval(timer);
284	return null;
285};
286
287/*
288Class: window
289	Some properties are attached to the window object by the browser detection.
290
291Properties:
292	window.ie - will be set to true if the current browser is internet explorer (any).
293	window.ie6 - will be set to true if the current browser is internet explorer 6.
294	window.ie7 - will be set to true if the current browser is internet explorer 7.
295	window.gecko - will be set to true if the current browser is Mozilla/Gecko.
296	window.webkit - will be set to true if the current browser is Safari/Konqueror.
297	window.webkit419 - will be set to true if the current browser is Safari2 / webkit till version 419.
298	window.webkit420 - will be set to true if the current browser is Safari3 (Webkit SVN Build) / webkit over version 419.
299	window.opera - is set to true by opera itself.
300*/
301
302window.xpath = !!(document.evaluate);
303if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
304else if (document.childNodes && !document.all && !navigator.taintEnabled) window.khtml = window.webkit = window[window.xpath ? 'webkit420' : 'webkit419'] = true;
305else if (document.getBoxObjectFor != null) window.gecko = true;
306
307//htmlelement
308
309if (typeof HTMLElement == 'undefined'){
310	var HTMLElement = function(){};
311	if (window.webkit) document.createElement("iframe"); //fixes safari
312	HTMLElement.prototype = (window.webkit) ? window["[[DOMElement.prototype]]"] : {};
313}
314HTMLElement.prototype.htmlElement = true;
315
316//enables background image cache for internet explorer 6
317
318if (window.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch(e){};
319
320/*
321Script: Class.js
322	Contains the Class Function, aims to ease the creation of reusable Classes.
323
324License:
325	MIT-style license.
326*/
327
328/*
329Class: Class
330	The base class object of the <http://mootools.net> framework.
331	Creates a new class, its initialize method will fire upon class instantiation.
332	Initialize wont fire on instantiation when you pass *null*.
333
334Arguments:
335	properties - the collection of properties that apply to the class.
336
337Example:
338	(start code)
339	var Cat = new Class({
340		initialize: function(name){
341			this.name = name;
342		}
343	});
344	var myCat = new Cat('Micia');
345	alert(myCat.name); //alerts 'Micia'
346	(end)
347*/
348
349var Class = function(properties){
350	var klass = function(){
351		return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;
352	};
353	$extend(klass, this);
354	klass.prototype = properties;
355	klass.constructor = Class;
356	return klass;
357};
358
359/*
360Property: empty
361	Returns an empty function
362*/
363
364Class.empty = function(){};
365
366Class.prototype = {
367
368	/*
369	Property: extend
370		Returns the copy of the Class extended with the passed in properties.
371
372	Arguments:
373		properties - the properties to add to the base class in this new Class.
374
375	Example:
376		(start code)
377		var Animal = new Class({
378			initialize: function(age){
379				this.age = age;
380			}
381		});
382		var Cat = Animal.extend({
383			initialize: function(name, age){
384				this.parent(age); //will call the previous initialize;
385				this.name = name;
386			}
387		});
388		var myCat = new Cat('Micia', 20);
389		alert(myCat.name); //alerts 'Micia'
390		alert(myCat.age); //alerts 20
391		(end)
392	*/
393
394	extend: function(properties){
395		var proto = new this(null);
396		for (var property in properties){
397			var pp = proto[property];
398			proto[property] = Class.Merge(pp, properties[property]);
399		}
400		return new Class(proto);
401	},
402
403	/*
404	Property: implement
405		Implements the passed in properties to the base Class prototypes, altering the base class, unlike <Class.extend>.
406
407	Arguments:
408		properties - the properties to add to the base class.
409
410	Example:
411		(start code)
412		var Animal = new Class({
413			initialize: function(age){
414				this.age = age;
415			}
416		});
417		Animal.implement({
418			setName: function(name){
419				this.name = name
420			}
421		});
422		var myAnimal = new Animal(20);
423		myAnimal.setName('Micia');
424		alert(myAnimal.name); //alerts 'Micia'
425		(end)
426	*/
427
428	implement: function(){
429		for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);
430	}
431
432};
433
434//internal
435
436Class.Merge = function(previous, current){
437	if (previous && previous != current){
438		var type = $type(current);
439		if (type != $type(previous)) return current;
440		switch(type){
441			case 'function':
442				var merged = function(){
443					this.parent = arguments.callee.parent;
444					return current.apply(this, arguments);
445				};
446				merged.parent = previous;
447				return merged;
448			case 'object': return $merge(previous, current);
449		}
450	}
451	return current;
452};
453
454/*
455Script: Class.Extras.js
456	Contains common implementations for custom classes. In Mootools is implemented in <Ajax>, <XHR> and <Fx.Base> and many more.
457
458License:
459	MIT-style license.
460*/
461
462/*
463Class: Chain
464	An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
465	Currently implemented in <Fx.Base>, <XHR> and <Ajax>. In <Fx.Base> for example, is used to execute a list of function, one after another, once the effect is completed.
466	The functions will not be fired all togheter, but one every completion, to create custom complex animations.
467
468Example:
469	(start code)
470	var myFx = new Fx.Style('element', 'opacity');
471
472	myFx.start(1,0).chain(function(){
473		myFx.start(0,1);
474	}).chain(function(){
475		myFx.start(1,0);
476	}).chain(function(){
477		myFx.start(0,1);
478	});
479	//the element will appear and disappear three times
480	(end)
481*/
482
483var Chain = new Class({
484
485	/*
486	Property: chain
487		adds a function to the Chain instance stack.
488
489	Arguments:
490		fn - the function to append.
491	*/
492
493	chain: function(fn){
494		this.chains = this.chains || [];
495		this.chains.push(fn);
496		return this;
497	},
498
499	/*
500	Property: callChain
501		Executes the first function of the Chain instance stack, then removes it. The first function will then become the second.
502	*/
503
504	callChain: function(){
505		if (this.chains && this.chains.length) this.chains.shift().delay(10, this);
506	},
507
508	/*
509	Property: clearChain
510		Clears the stack of a Chain instance.
511	*/
512
513	clearChain: function(){
514		this.chains = [];
515	}
516
517});
518
519/*
520Class: Events
521	An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
522
523	In <Fx.Base> Class, for example, is used to give the possibility add any number of functions to the Effects events, like onComplete, onStart, onCancel.
524
525Example:
526	(start code)
527	var myFx = new Fx.Style('element', 'opacity').addEvent('onComplete', function(){
528		alert('the effect is completed');
529	}).addEvent('onComplete', function(){
530		alert('I told you the effect is completed');
531	});
532
533	myFx.start(0,1);
534	//upon completion it will display the 2 alerts, in order.
535	(end)
536
537Implementing:
538	This class can be implemented into other classes to add the functionality to them.
539	Goes well with the <Options> class.
540
541Example:
542	(start code)
543	var Widget = new Class({
544		initialize: function(){},
545		finish: function(){
546			this.fireEvent('onComplete');
547		}
548	});
549	Widget.implement(new Events);
550	//later...
551	var myWidget = new Widget();
552	myWidget.addEvent('onComplete', myfunction);
553	(end)
554*/
555
556var Events = new Class({
557
558	/*
559	Property: addEvent
560		adds an event to the stack of events of the Class instance.
561
562	Arguments:
563		type - string; the event name (e.g. 'onComplete')
564		fn - function to execute
565	*/
566
567	addEvent: function(type, fn){
568		if (fn != Class.empty){
569			this.$events = this.$events || {};
570			this.$events[type] = this.$events[type] || [];
571			this.$events[type].include(fn);
572		}
573		return this;
574	},
575
576	/*
577	Property: fireEvent
578		fires all events of the specified type in the Class instance.
579
580	Arguments:
581		type - string; the event name (e.g. 'onComplete')
582		args - array or single object; arguments to pass to the function; if more than one argument, must be an array
583		delay - (integer) delay (in ms) to wait to execute the event
584
585	Example:
586	(start code)
587	var Widget = new Class({
588		initialize: function(arg1, arg2){
589			...
590			this.fireEvent("onInitialize", [arg1, arg2], 50);
591		}
592	});
593	Widget.implement(new Events);
594	(end)
595	*/
596
597	fireEvent: function(type, args, delay){
598		if (this.$events && this.$events[type]){
599			this.$events[type].each(function(fn){
600				fn.create({'bind': this, 'delay': delay, 'arguments': args})();
601			}, this);
602		}
603		return this;
604	},
605
606	/*
607	Property: removeEvent
608		removes an event from the stack of events of the Class instance.
609
610	Arguments:
611		type - string; the event name (e.g. 'onComplete')
612		fn - function that was added
613	*/
614
615	removeEvent: function(type, fn){
616		if (this.$events && this.$events[type]) this.$events[type].remove(fn);
617		return this;
618	}
619
620});
621
622/*
623Class: Options
624	An "Utility" Class. Its methods can be implemented with <Class.implement> into any <Class>.
625	Used to automate the options settings, also adding Class <Events> when the option begins with on.
626
627	Example:
628		(start code)
629		var Widget = new Class({
630			options: {
631				color: '#fff',
632				size: {
633					width: 100
634					height: 100
635				}
636			},
637			initialize: function(options){
638				this.setOptions(options);
639			}
640		});
641		Widget.implement(new Options);
642		//later...
643		var myWidget = new Widget({
644			color: '#f00',
645			size: {
646				width: 200
647			}
648		});
649		//myWidget.options = {color: #f00, size: {width: 200, height: 100}}
650		(end)
651*/
652
653var Options = new Class({
654
655	/*
656	Property: setOptions
657		sets this.options
658
659	Arguments:
660		defaults - object; the default set of options
661		options - object; the user entered options. can be empty too.
662
663	Note:
664		if your Class has <Events> implemented, every option beginning with on, followed by a capital letter (onComplete) becomes an Class instance event.
665	*/
666
667	setOptions: function(){
668		this.options = $merge.apply(null, [this.options].extend(arguments));
669		if (!this.addEvent) return this;
670		for (var option in this.options){
671			if ($type(this.options[option] == 'function') && option.test(/^on[A-Z]/)) this.addEvent(option, this.options[option]);
672		}
673		return this;
674	}
675
676});
677
678/*
679Script: Array.js
680	Contains Array prototypes, <$A>, <$each>
681
682License:
683	MIT-style license.
684*/
685
686/*
687Class: Array
688	A collection of The Array Object prototype methods.
689*/
690
691//custom methods
692
693Array.extend({
694
695	/*
696	Property: forEach
697		Iterates through an array; This method is only available for browsers without native *forEach* support.
698		For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach>
699
700		*forEach* executes the provided function (callback) once for each element present in the array. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
701
702	Arguments:
703		fn - function to execute with each item in the array; passed the item and the index of that item in the array
704		bind - the object to bind "this" to (see <Function.bind>)
705
706	Example:
707		>['apple','banana','lemon'].each(function(item, index) {
708		>	alert(index + " = " + item); //alerts "0 = apple" etc.
709		>}, bindObj); //optional second arg for binding, not used here
710	*/
711
712	forEach: function(fn, bind){
713		for (var i = 0, j = this.length; i < j; i++) fn.call(bind, this[i], i, this);
714	},
715
716	/*
717	Property: filter
718		This method is provided only for browsers without native *filter* support.
719		For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter>
720
721		*filter* calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a true value. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values. Array elements which do not pass the callback test are simply skipped, and are not included in the new array.
722
723	Arguments:
724		fn - function to execute with each item in the array; passed the item and the index of that item in the array
725		bind - the object to bind "this" to (see <Function.bind>)
726
727	Example:
728		>var biggerThanTwenty = [10,3,25,100].filter(function(item, index) {
729		> return item > 20;
730		>});
731		>//biggerThanTwenty = [25,100]
732	*/
733
734	filter: function(fn, bind){
735		var results = [];
736		for (var i = 0, j = this.length; i < j; i++){
737			if (fn.call(bind, this[i], i, this)) results.push(this[i]);
738		}
739		return results;
740	},
741
742	/*
743	Property: map
744		This method is provided only for browsers without native *map* support.
745		For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map>
746
747		*map* calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. c
747allback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
748
749	Arguments:
750		fn - function to execute with each item in the array; passed the item and the index of that item in the array
751		bind - the object to bind "this" to (see <Function.bind>)
752
753	Example:
754		>var timesTwo = [1,2,3].map(function(item, index){
755		> return item*2;
756		>});
757		>//timesTwo = [2,4,6];
758	*/
759
760	map: function(fn, bind){
761		var results = [];
762		for (var i = 0, j = this.length; i < j; i++) results[i] = fn.call(bind, this[i], i, this);
763		return results;
764	},
765
766	/*
767	Property: every
768		This method is provided only for browsers without native *every* support.
769		For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
770
771		*every* executes the provided callback function once for each element present in the array until it finds one where callback returns a false value. If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
772
773	Arguments:
774		fn - function to execute with each item in the array; passed the item and the index of that item in the array
775		bind - the object to bind "this" to (see <Function.bind>)
776
777	Example:
778		>var areAllBigEnough = [10,4,25,100].every(function(item, index){
779		> return item > 20;
780		>});
781		>//areAllBigEnough = false
782	*/
783
784	every: function(fn, bind){
785		for (var i = 0, j = this.length; i < j; i++){
786			if (!fn.call(bind, this[i], i, this)) return false;
787		}
788		return true;
789	},
790
791	/*
792	Property: some
793		This method is provided only for browsers without native *some* support.
794		For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some>
795
796		*some* executes the callback function once for each element present in the array until it finds one where callback returns a true value. If such an element is found, some immediately returns true. Otherwise, some returns false. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
797
798	Arguments:
799		fn - function to execute with each item in the array; passed the item and the index of that item in the array
800		bind - the object to bind "this" to (see <Function.bind>)
801
802	Example:
803		>var isAnyBigEnough = [10,4,25,100].some(function(item, index){
804		> return item > 20;
805		>});
806		>//isAnyBigEnough = true
807	*/
808
809	some: function(fn, bind){
810		for (var i = 0, j = this.length; i < j; i++){
811			if (fn.call(bind, this[i], i, this)) return true;
812		}
813		return false;
814	},
815
816	/*
817	Property: indexOf
818		This method is provided only for browsers without native *indexOf* support.
819		For more info see <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
820
821		*indexOf* compares a search element to elements of the Array using strict equality (the same method used by the ===, or triple-equals, operator).
822
823	Arguments:
824		item - any type of object; element to locate in the array
825		from - integer; optional; the index of the array at which to begin the search (defaults to 0)
826
827	Example:
828		>['apple','lemon','banana'].indexOf('lemon'); //returns 1
829		>['apple','lemon'].indexOf('banana'); //returns -1
830	*/
831
832	indexOf: function(item, from){
833		var len = this.length;
834		for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
835			if (this[i] === item) return i;
836		}
837		return -1;
838	},
839
840	/*
841	Property: each
842		Same as <Array.forEach>.
843
844	Arguments:
845		fn - function to execute with each item in the array; passed the item and the index of that item in the array
846		bind - optional, the object that the "this" of the function will refer to.
847
848	Example:
849		>var Animals = ['Cat', 'Dog', 'Coala'];
850		>Animals.each(function(animal){
851		>	document.write(animal)
852		>});
853	*/
854
855	/*
856	Property: copy
857		returns a copy of the array.
858
859	Returns:
860		a new array which is a copy of the current one.
861
862	Arguments:
863		start - integer; optional; the index where to start the copy, default is 0. If negative, it is taken as the offset from the end of the array.
864		length - integer; optional; the number of elements to copy. By default, copies all elements from start to the end of the array.
865
866	Example:
867		>var letters = ["a","b","c"];
868		>
868var copy = letters.copy();		// ["a","b","c"] (new instance)
869	*/
870
871	copy: function(start, length){
872		start = start || 0;
873		if (start < 0) start = this.length + start;
874		length = length || (this.length - start);
875		var newArray = [];
876		for (var i = 0; i < length; i++) newArray[i] = this[start++];
877		return newArray;
878	},
879
880	/*
881	Property: remove
882		Removes all occurrences of an item from the array.
883
884	Arguments:
885		item - the item to remove
886
887	Returns:
888		the Array with all occurrences of the item removed.
889
890	Example:
891		>["1","2","3","2"].remove("2") // ["1","3"];
892	*/
893
894	remove: function(item){
895		var i = 0;
896		var len = this.length;
897		while (i < len){
898			if (this[i] === item){
899				this.splice(i, 1);
900				len--;
901			} else {
902				i++;
903			}
904		}
905		return this;
906	},
907
908	/*
909	Property: contains
910		Tests an array for the presence of an item.
911
912	Arguments:
913		item - the item to search for in the array.
914		from - integer; optional; the index at which to begin the search, default is 0. If negative, it is taken as the offset from the end of the array.
915
916	Returns:
917		true - the item was found
918		false - it wasn't
919
920	Example:
921		>["a","b","c"].contains("a"); // true
922		>["a","b","c"].contains("d"); // false
923	*/
924
925	contains: function(item, from){
926		return this.indexOf(item, from) != -1;
927	},
928
929	/*
930	Property: associate
931		Creates an object with key-value pairs based on the array of keywords passed in
932		and the current content of the array.
933
934	Arguments:
935		keys - the array of keywords.
936
937	Example:
938		(start code)
939		var Animals = ['Cat', 'Dog', 'Coala', 'Lizard'];
940		var Speech = ['Miao', 'Bau', 'Fruuu', 'Mute'];
941		var Speeches = Animals.associate(Speech);
942		//Speeches['Miao'] is now Cat.
943		//Speeches['Bau'] is now Dog.
944		//...
945		(end)
946	*/
947
948	associate: function(keys){
949		var obj = {}, length = Math.min(this.length, keys.length);
950		for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
951		return obj;
952	},
953
954	/*
955	Property: extend
956		Extends an array with another one.
957
958	Arguments:
959		array - the array to extend ours with
960
961	Example:
962		>var Animals = ['Cat', 'Dog', 'Coala'];
963		>Animals.extend(['Lizard']);
964		>//Animals is now: ['Cat', 'Dog', 'Coala', 'Lizard'];
965	*/
966
967	extend: function(array){
968		for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
969		return this;
970	},
971
972	/*
973	Property: merge
974		merges an array in another array, without duplicates. (case- and type-sensitive)
975
976	Arguments:
977		array - the array to merge from.
978
979	Example:
980		>['Cat','Dog'].merge(['Dog','Coala']); //returns ['Cat','Dog','Coala']
981	*/
982
983	merge: function(array){
984		for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
985		return this;
986	},
987
988	/*
989	Property: include
990		includes the passed in element in the array, only if its not already present. (case- and type-sensitive)
991
992	Arguments:
993		item - item to add to the array (if not present)
994
995	Example:
996		>['Cat','Dog'].include('Dog'); //returns ['Cat','Dog']
997		>['Cat','Dog'].include('Coala'); //returns ['Cat','Dog','Coala']
998	*/
999
1000	include: function(item){
1001		if (!this.contains(item)) this.push(item);
1002		return this;
1003	},
1004
1005	/*
1006	Property: getRandom
1007		returns a random item in the Array
1008	*/
1009
1010	getRandom: function(){
1011		return this[$random(0, this.length - 1)] || false;
1012	},
1013
1014	/*
1015	Property: getLast
1016		returns the last item in the Array
1017	*/
1018
1019	getLast: function(){
1020		return this[this.length - 1] || false;
1021	}
1022
1023});
1024
1025//copies
1026
1027Array.prototype.each = Array.prototype.forEach;
1028Array.prototype.test = Array.prototype.contains;
1029
1030/* Section: Utility Functions */
1031
1032/*
1033Function: $A()
1034	Same as <Array.copy>, but as function.
1035	Useful to apply Array prototypes to iterable objects, as a collection of DOM elements or the arguments object.
1036
1037Example:
1038	(start code)
1039	function myFunction(){
1040		$A(arguments).each(argument, function(){
1041			alert(argument);
1042		});
1043	};
1044	//the above will alert all the arguments passed to the function myFunction.
1045	(end)
1046*/
1047
1048function $A(array){
1049	return Array.copy(array);
1050};
1051
1052/*
1053Function: $each
1054	Use to iterate through iterables that are not regular arrays, such as builtin getElementsByTagName calls, arguments of a function, or an object.
1055
1056Arguments:
1057	iterable - an iterable element or an objct.
1058	function - function to apply to the iterable.
1059	bind - optional, the 'this' of the function will refer to this object.
1060
1061Function argument:
1062	The function argument will be passed the following arguments.
1063
1064	item - the current item in the iterator being procesed
1065	index - integer; the index of the item, or key in case of an object.
1066
1067Examples:
1068	(start code)
1069	$each(['Sun','Mon','Tue'], function(day, index) {
1070		alert('name:' + day + ', index: ' + index);
1071	});
1072	//alerts "name: Sun, index: 0", "name: Mon, index: 1", etc.
1073	//over an object
1074	$each({first: "Sunday", second: "Monday", third: "Tuesday"}, function(value, key){
1075		alert("the " + key + " day of the week is " + value);
1076	});
1077	//alerts "the first day of the week is Sunday",
1078	//"the second day of the week is Monday", etc.
1079	(end)
1080*/
1081
1082function $each(iterable, fn, bind){
1083	if (iterable && typeof iterable.length == 'number' && $type(iterable) != 'object') Array.forEach(iterable, fn, bind);
1084	else for (var name in iterable) fn.call(bind || iterable, iterable[name], name);
1085};
1086
1087/*
1088Script: String.js
1089	Contains String prototypes and Number prototypes.
1090
1091License:
1092	MIT-style license.
1093*/
1094
1095/*
1096Class: String
1097	A collection of The String Object prototype methods.
1098*/
1099
1100String.extend({
1101
1102	/*
1103	Property: test
1104		Tests a string with a regular expression.
1105
1106	Arguments:
1107		regex - a string or regular expression object, the regular expression you want to match the string with
1108		params - optional, if first parameter is a string, any parameters you want to pass to the regex ('g' has no effect)
1109
1110	Returns:
1111		true if a match for the regular expression is found in the string, false if not.
1112		See <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:RegExp:test>
1113
1114	Example:
1115		>"I like cookies".test("cookie"); // returns true
1116		>"I like cookies".test("COOKIE", "i") // ignore case, returns true
1117		>"I like cookies".test("cake"); // returns false
1118	*/
1119
1120	test: function(regex, params){
1121		return (($type(regex) == 'string') ? new RegExp(regex, params) : regex).test(this);
1122	},
1123
1124	/*
1125	Property: toInt
1126		parses a string to an integer.
1127
1128	Returns:
1129		either an int or "NaN" if the string is not a number.
1130
1131	Example:
1132		>var value = "10px".toInt(); // value is 10
1133	*/
1134
1135	toInt: function(){
1136		return parseInt(this, 10);
1137	},
1138
1139	/*
1140	Property: toFloat
1141		parses a string to an float.
1142
1143	Returns:
1144		either a float or "NaN" if the string is not a number.
1145
1146	Example:
1147		>var value = "10.848".toFloat(); // value is 10.848
1148	*/
1149
1150	toFloat: function(){
1151		return parseFloat(this);
1152	},
1153
1154	/*
1155	Property: camelCase
1156		Converts a hiphenated string to a camelcase string.
1157
1158	Example:
1159		>
1159"I-like-cookies".camelCase(); //"ILikeCookies"
1160
1161	Returns:
1162		the camel cased string
1163	*/
1164
1165	camelCase: function(){
1166		return this.replace(/-\D/g, function(match){
1167			return match.charAt(1).toUpperCase();
1168		});
1169	},
1170
1171	/*
1172	Property: hyphenate
1173		Converts a camelCased string to a hyphen-ated string.
1174
1175	Example:
1176		>"ILikeCookies".hyphenate(); //"I-like-cookies"
1177	*/
1178
1179	hyphenate: function(){
1180		return this.replace(/\w[A-Z]/g, function(match){
1181			return (match.charAt(0) + '-' + match.charAt(1).toLowerCase());
1182		});
1183	},
1184
1185	/*
1186	Property: capitalize
1187		Converts the first letter in each word of a string to Uppercase.
1188
1189	Example:
1190		>"i like cookies".capitalize(); //"I Like Cookies"
1191
1192	Returns:
1193		the capitalized string
1194	*/
1195
1196	capitalize: function(){
1197		return this.replace(/\b[a-z]/g, function(match){
1198			return match.toUpperCase();
1199		});
1200	},
1201
1202	/*
1203	Property: trim
1204		Trims the leading and trailing spaces off a string.
1205
1206	Example:
1207		>"    i like cookies     ".trim() //"i like cookies"
1208
1209	Returns:
1210		the trimmed string
1211	*/
1212
1213	trim: function(){
1214		return this.replace(/^\s+|\s+$/g, '');
1215	},
1216
1217	/*
1218	Property: clean
1219		trims (<String.trim>) a string AND removes all the double spaces in a string.
1220
1221	Returns:
1222		the cleaned string
1223
1224	Example:
1225		>" i      like     cookies      \n\n".clean() //"i like cookies"
1226	*/
1227
1228	clean: function(){
1229		return this.replace(/\s{2,}/g, ' ').trim();
1230	},
1231
1232	/*
1233	Property: rgbToHex
1234		Converts an RGB value to hexidecimal. The string must be in the format of "rgb(255,255,255)" or "rgba(255,255,255,1)";
1235
1236	Arguments:
1237		array - boolean value, defaults to false. Use true if you want the array ['FF','33','00'] as output instead of "#FF3300"
1238
1239	Returns:
1240		hex string or array. returns "transparent" if the output is set as string and the fourth value of rgba in input string is 0.
1241
1242	Example:
1243		>"rgb(17,34,51)".rgbToHex(); //"#112233"
1244		>"rgba(17,34,51,0)".rgbToHex(); //"transparent"
1245		>"rgb(17,34,51)".rgbToHex(true); //['11','22','33']
1246	*/
1247
1248	rgbToHex: function(array){
1249		var rgb = this.match(/\d{1,3}/g);
1250		return (rgb) ? rgb.rgbToHex(array) : false;
1251	},
1252
1253	/*
1254	Property: hexToRgb
1255		Converts a hexidecimal color value to RGB. Input string must be the hex color value (with or without the hash). Also accepts triplets ('333');
1256
1257	Arguments:
1258		array - boolean value, defaults to false. Use true if you want the array [255,255,255] as output instead of "rgb(255,255,255)";
1259
1260	Returns:
1261		rgb string or array.
1262
1263	Example:
1264		>"#112233".hexToRgb(); //"rgb(17,34,51)"
1265		>"#112233".hexToRgb(true); //[17,34,51]
1266	*/
1267
1268	hexToRgb: function(array){
1269		var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
1270		return (hex) ? hex.slice(1).hexToRgb(array) : false;
1271	},
1272
1273	/*
1274	Property: contains
1275		checks if the passed in string is contained in the String. also accepts an optional second parameter, to check if the string is contained in a list of separated values.
1276
1277	Example:
1278		>'a b c'.contains('c', ' '); //true
1279		>'a bc'.contains('bc'); //true
1280		>'a bc'.contains('b', ' '); //false
1281	*/
1282	
1283	contains: function(string, s){
1284		return (s) ? (s + this + s).indexOf(s + string + s) > -1 : this.indexOf(string) > -1;
1285	},
1286
1287	/*
1288	Property: escapeRegExp
1289		Returns string with escaped regular expression characters
1290
1291	Example:
1292		>var search = 'animals.sheeps[1]'.escapeRegExp(); // search is now 'animals\.sheeps\[1\]'
1293
1294	Returns:
1295		Escaped string
1296	*/
1297
1298	escapeRegExp: function(){
1299		return this.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
1300	}
1301
1302});
1303
1304Array.extend({
1305
1306	/*
1307	Property: rgbToHex
1308		see <String.rgbToHex>, but as an array method.
1309	*/
1310
1311	rgbToHex: function(array){
1312		if (this.length < 3) return false;
1313		if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
1314		var hex = [];
1315		for (var i = 0; i < 3; i++){
1316			var bit = (this[i] - 0).toString(16);
1317			hex.push((bit.length == 1) ? '0' + bit : bit);
1318		}
1319		return array ? hex : '#' + hex.join('');
1320	},
1321
1322	/*
1323	Property: hexToRgb
1324		same as <String.hexToRgb>, but as an array method.
1325	*/
1326
1327	hexToRgb: function(array){
1328		if (this.length != 3) return false;
1329		var rgb = [];
1330		for (var i = 0; i < 3; i++){
1331			rgb.push(parseInt((this[i].length == 1) ? this[i] + this[i] : this[i], 16));
1332		}
1333		return array ? rgb : 'rgb(' + rgb.join(',') + ')';
1334	}
1335
1336});
1337
1338/* 
1339Script: Function.js
1340	Contains Function prototypes and utility functions .
1341
1342License:
1343	MIT-style license.
1344
1345Credits:
1346	- Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
1347*/
1348
1349/*
1350Class: Function
1351	A collection of The Function Object prototype methods.
1352*/
1353
1354Function.extend({
1355
1356	/*
1357	Property: create
1358		Main function to create closures.
1359
1360	Returns:
1361		a function.
1362
1363	Arguments:
1364		options - An Options object.
1365
1366	Options:
1367		bind - The object that the "this" of the function will refer to. Default is the current function.
1368		event - If set to true, the function will act as an event listener and receive an event as first argument.
1369				If set to a class name, the function will receive a new instance of this class (with the event passed as argument's constructor) as first argument.
1370				Default is false.
1371		arguments - A single argument or array of arguments that will be passed to the function when called.
1372		
1373					If both the event and arguments options are set, the event is passed as first argument and the arguments array will follow.
1374					
1375					Default is no custom arguments, the function will receive the standard arguments when called.
1376					
1377		delay - Numeric value: if set, the returned function will delay the actual execution by this amount of milliseconds and return a timer handle when called.
1378				Default is no delay.
1379		periodical - Numeric value: if set, the returned function will periodically perform the actual execution with this specified interval and return a timer handle when called.
1380				Default is no periodical execution.
1381		attempt - If set to true, the returned function will try to execute and return either the results or false on error. Default is false.
1382	*/
1383
1384	create: function(options){
1385		var fn = this;
1386		options = $merge({
1387			'bind': fn,
1388			'event': false,
1389			'arguments': null,
1390			'delay': false,
1391			'periodical': false,
1392			'attempt': false
1393		}, options);
1394		if ($chk(options.arguments) && $type(options.arguments) != 'array') o
1394ptions.arguments = [options.arguments];
1395		return function(event){
1396			var args;
1397			if (options.event){
1398				event = event || window.event;
1399				args = [(options.event === true) ? event : new options.event(event)];
1400				if (options.arguments) args.extend(options.arguments);
1401			}
1402			else args = options.arguments || arguments;
1403			var returns = function(){
1404				return fn.apply($pick(options.bind, fn), args);
1405			};
1406			if (options.delay) return setTimeout(returns, options.delay);
1407			if (options.periodical) return setInterval(returns, options.periodical);
1408			if (options.attempt) try {return returns();} catch(err){return false;};
1409			return returns();
1410		};
1411	},
1412
1413	/*
1414	Property: pass
1415		Shortcut to create closures with arguments and bind.
1416
1417	Returns:
1418		a function.
1419
1420	Arguments:
1421		args - the arguments passed. must be an array if arguments > 1
1422		bind - optional, the object that the "this" of the function will refer to.
1423
1424	Example:
1425		>myFunction.pass([arg1, arg2], myElement);
1426	*/
1427
1428	pass: function(args, bind){
1429		return this.create({'arguments': args, 'bind': bind});
1430	},
1431
1432	/*
1433	Property: attempt
1434		Tries to execute the function, returns either the result of the function or false on error.
1435
1436	Arguments:
1437		args - the arguments passed. must be an array if arguments > 1
1438		bind - optional, the object that the "this" of the function will refer to.
1439
1440	Example:
1441		>myFunction.attempt([arg1, arg2], myElement);
1442	*/
1443
1444	attempt: function(args, bind){
1445		return this.create({'arguments': args, 'bind': bind, 'attempt': true})();
1446	},
1447
1448	/*
1449	Property: bind
1450		method to easily create closures with "this" altered.
1451
1452	Arguments:
1453		bind - optional, the object that the "this" of the function will refer to.
1454		args - optional, the arguments passed. must be an array if arguments > 1
1455
1456	Returns:
1457		a function.
1458
1459	Example:
1460		>function myFunction(){
1461		>	this.setStyle('color', 'red');
1462		>	// note that 'this' here refers to myFunction, not an element
1463		>	// we'll need to bind this function to the element we want to alter
1464		>};
1465		>var myBoundFunction = myFunction.bind(myElement);
1466		>myBoundFunction(); // this will make the element myElement red.
1467	*/
1468
1469	bind: function(bind, args){
1470		return this.create({'bind': bind, 'arguments': args});
1471	},
1472
1473	/*
1474	Property: bindAsEventListener
1475		cross browser method to pass event firer
1476
1477	Arguments:
1478		bind - optional, the object that the "this" of the function will refer to.
1479		args - optional, the arguments passed. must be an array if arguments > 1
1480
1481	Returns:
1482		a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
1483
1484	Example:
1485		>function myFunction(event){
1486		>	alert(event.clientx) //returns the coordinates of the mouse..
1487		>};
1488		>myElement.onclick = myFunction.bindAsEventListener(myElement);
1489	*/
1490
1491	bindAsEventListener: function(bind, args){
1492		return this.create({'bind': bind, 'event': true, 'arguments': args});
1493	},
1494
1495	/*
1496	Property: delay
1497		Delays the execution of a function by a specified duration.
1498
1499	Arguments:
1500		delay - the duration to wait in milliseconds.
1501		bind - optional, the object that the "this" of the function will refer to.
1502		args - optional, the arguments passed. must be an array if arguments > 1
1503
1504	Example:
1505		>myFunction.delay(50, myElement) //wait 50 milliseconds, then call myFunction and bind myElement to it
1506		>(function(){alert('one second later...')}).delay(1000); //wait a second and alert
1507	*/
1508
1509	delay: function(delay, bind, args){
1510		return this.create({'delay': delay, 'bind': bind, 'arguments': args})();
1511	},
1512
1513	/*
1514	Property: periodical
1515		Executes a function in the specified intervals of time
1516
1517	Arguments:
1518		interval - the duration of the intervals between executions.
1519		bind - optional, the object that the "this" of the function will refer to.
1520		args - optional, the arguments passed. must be an array if arguments > 1
1521	*/
1522
1523	periodical: function(interval, bind, args){
1524		return this.create({'periodical': interval, 'bind': bind, 'arguments': args})();
1525	}
1526
1527});
1528
1529/*
1530Class: Number
1531	A collection of The Number Object prototype methods.
1532*/
1533
1534Number.extend({
1535
1536	/*
1537	Property: toInt
1538		Returns this number; useful because toInt must work on both Strings and Numbers.
1539	*/
1540
1541	toInt: function(){
1542		return parseInt(this);
1543	},
1544
1545	/*
1546	Property: toFloat
1547		Returns this number as a float; useful because toFloat must work on both Strings and Numbers.
1548	*/
1549
1550	toFloat: function(){
1551		return parseFloat(this);
1552	},
1553
1554	/*
1555	Property: limit
1556		Limits the number.
1557		
1558	Arguments:
1559		min - number, minimum value
1560		max - number, maximum value
1561		
1562	Returns:
1563		the number in the given limits.
1564		
1565	Example:
1566		>(12).limit(2, 6.5)  // returns 6.5
1567		>(-4).limit(2, 6.5)  // returns 2
1568		>(4.3).limit(2, 6.5) // returns 4.3
1569	*/
1570
1571	limit: function(min, max){
1572		return Math.min(max, Math.max(min, this));
1573	},
1574
1575	/*
1576	Property: round
1577		Returns the number rounded to specified precision.
1578
1579	Arguments:
1580		precision - integer, number of digits after the decimal point. Can also be negative or zero (default).
1581
1582	Example:
1583		>12.45.round() // returns 12
1584		>12.45.round(1) // returns 12.5
1585		>12.45.round(-1) // returns 10
1586		
1587	Returns:
1588		The rounded number.
1589	*/
1590
1591	round: function(precision){
1592		precision = Math.pow(10, precision || 0);
1593		return Math.round(this * precision) / precision;
1594	},
1595
1596	/*
1597	Property: times
1598		Executes a passed in function the specified number of times
1599
1600	Arguments:
1601		function - the function to be executed on each iteration of the loop
1602
1603	Example:
1604		>(4).times(alert);
1605	*/
1606
1607	times: function(fn) {
1608		for (var i = 0; i < this; i++) fn(i);
1609	}
1610
1611});
1612
1613/*
1614Script: Element.js
1615	Contains useful Element prototypes, to be used with the dollar function <$>.
1616
1617License:
1618	MIT-style license.
1619
1620Credits:
1621	- Some functions are inspired by those found in prototype.js <http://prototype.conio.net/> (c) 2005 Sam Stephenson sam [at] conio [dot] net, MIT-style license
1622*/
1623
1624/*
1625Class: Element
1626	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
1627*/
1628
1629var Element = new Class({
1630
1631	/*
1632	Property: initialize
1633		Creates a new element of the type passed in.
1634
1635	Arguments:
1636		el - string; the tag name for the element you wish to create. you can also pass in an element reference, in which case it will be extended.
1637		props - object; the properties you want to add to your element.
1638		Accepts the same keys as <Element.setProperties>, but also allows events and styles
1639
1640	Props:
1641		the key styles will be used as setStyles, the key events will be used as addEvents. any other key is used as setProperty.
1642
1643	Example:
1644		(start code)
1645		new Element('a', {
1646			'styles': {
1647				'display': 'block',
1648				'border': '1px solid black'
1649			},
1650			'events': {
1651				'click': function(){
1652					//aaa
1653				},
1654				'mousedown': function(){
1655					//aaa
1656				}
1657			},
1658			'class': 'myClassSuperClass',
1659			'href': 'http://mad4milk.net'
1660		});
1661
1662		(end)
1663	*/
1664
1665	initialize: function(el, props){
1666		if ($type(el) == 'string'){
1667			if (window.ie && props && (props.name || props.type)){
1668				var name = (props.name) ? ' name="' + props.name + '"' : '';
1669				var type = (props.type) ? ' type="' + props.type + '"' : '';
1670				delete props.name;
1671				delete props.type;
1672				el = '<' + el + name + type + '>';
1673			}
1674			el = document.createElement(el);
1675		}
1676		el = $(el);
1677		return (!props || !el) ? el : el.set(props);
1678	}
1679
1680});
1681
1682/*
1683Class: Elements
1684	- Every dom function such as <$$>, or in general every function that returns a collection of nodes in mootools, returns them as an Elements class.
1685	- The purpose of the Elements class is to allow <Element> methods to work also on <Elements> array.
1686	- Elements is also an Array, so it accepts all the <Array> methods.
1687	- Every node of the Elements instance is already extended with <$>.
1688
1689Example:
1690	>$$('myselector').each(function(el){
1691	> //...
1692	>});
1693
1694	some iterations here, $$('myselector') is also an array.
1695
1696	>$$('myselector').setStyle('color', 'red');
1697	every element returned by $$('myselector') also accepts <Element> methods, in this example every element will be made red.
1698*/
1699
1700var Elements = new Class({
1701
1702	initialize: function(elements){
1703		return (elements) ? $extend(elements, this) : this;
1704	}
1705
1706});
1707
1708Elements.extend = function(props){
1709	for (var prop in props){
1710		this.prototype[prop] = props[prop];
1711		this[prop] = $native.generic(prop);
1712	}
1713};
1714
1715/*
1716Section: Utility Functions
1717
1718Function: $
1719	returns the element passed in with all the Element prototypes applied.
1720
1721Arguments:
1722	el - a reference to an actual element or a string representing the id of an element
1723
1724Example:
1725	>$('myElement') // gets a DOM element by id with all the Element prototypes applied.
1726	>var div = document.getElementById('myElement');
1727	>$(div) //returns an Element also with all the mootools extentions applied.
1728
1729	You'll use this when you aren't sure if a variable is an actual element or an id, as
1730	well as just shorthand for document.getElementById().
1731
1732Returns:
1733	a DOM element or false (if no id was found).
1734
1735Note:
1736	you need to call $ on an element only once to get all the prototypes.
1737	But its no harm to call it multiple times, as it will detect if it has been already extended.
1738*/
1739
1740function $(el){
1741	if (!el) return false;
1742	if (el.htmlElement) return Garbage.collect(el);
1743	if ([window, document].contains(el)) return el;
1744	var type = $type(el);
1745	if (type == 'string'){
1746		el = document.getElementById(el);
1747		type = (el) ? 'element' : false;
1748	}
1749	if (type != 'element') return false;
1750	if (el.htmlElement) return Garbage.collect(el);
1751	if (['object', 'embed'].contains(el.tagName.toLowerCase())) return el;
1752	$extend(el, Element.prototype);
1753	el.htmlElement = true;
1754	return Garbage.collect(el);
1755};
1756
1757/*
1758Function: $$
1759	Selects, and extends DOM elements. Elements arrays returned with $$ will also accept all the <Element> methods.
1760	The return type of element methods run through $$ is always an array. If the return array is only made by elements,
1761	$$ will be applied automatically.
1762
1763Arguments:
1764	HTML Collections, arrays of elements, arrays of strings as element ids, elements, strings as selectors.
1765	Any number of the above as arguments are accepted.
1766
1767Note:
1768	if you load <Element.Selectors.js>, $$ will also accept CSS Selectors, otherwise the only selectors supported are tag names.
1769
1770Example:
1771	>$$('a') //an array of all anchor tags on the page
1772	>$$('a', 'b') //an array of all anchor and bold tags on the page
1773	>$$('#myElement') //array containing only the element with id = myElement. (only with <Element.Selectors.js>)
1774	>$$('#myElement a.myClass') //an array of all anchor tags with the class "myClass"
1775	>//within the DOM element with id "myElement" (only with <Element.Selectors.js>)
1776	>$$(myelement, myelement2, 'a', ['myid', myid2, 'myid3'], document.getElementsByTagName('div')) //an array containing:
1777	>// the element referenced as myelement if existing,
1778	>// the element referenced as myelement2 if existing,
1779	>// all the elements with a as tag in the page,
1780	>// the element with id = myid if existing
1781	>// the element with id = myid2 if existing
1782	>// the element with id = myid3 if existing
1783	>// all the elements with div as tag in the page
1784
1785Returns:
1786	array - array of all the dom elements matched, extended with <$>.  Returns as <Elements>.
1787*/
1788
1789document.getElementsBySelector = document.getElementsByTagName;
1790
1791function $$(){
1792	var elements = [];
1793	for (var i = 0, j = arguments.length; i < j; i++){
1794		var selector = arguments[i];
1795		switch($type(selector)){
1796			case 'element': elements.push(selector);
1797			case 'boolean': break;
1798			case false: break;
1799			case 'string': selector = document.getElementsBySelector(selector, true);
1800			default: elements.extend(selector);
1801		}
1802	}
1803	return $$.unique(elements);
1804};
1805
1806$$.unique = function(array){
1807	var elements = [];
1808	for (var i = 0, l = array.length; i < l; i++){
1809		if (array[i].$included) continue;
1810		var element = $(array[i]);
1811		if (element && !element.$included){
1812			element.$included = true;
1813			elements.push(element);
1814		}
1815	}
1816	for (var i = 0, l = elements.length; i < l; i++) elements[i].$included = null;
1817	return new Elements(elements);
1818};
1819
1820Elements.Multi = function(property){
1821	return function(){
1822		var args = arguments;
1823		var items = [];
1824		var elements = true;
1825		for (var i = 0, j = this.length, returns; i < j; i++){
1826			returns = this[i][property].apply(this[i], args);
1827			if ($type(returns) != 'element') elements = false;
1828			items.push(returns);
1829		};
1830		return (elements) ? $$.unique(items) : items;
1831	};
1832};
1833
1834Element.extend = function(properties){
1835	for (var property in properties){
1836		HTMLElement.prototype[property] = properties[property];
1837		Element.prototype[property] = properties[property];
1838		Element[property] = $native.generic(property);
1839		var elementsProperty = (Array.prototype[property]) ? property + 'Elements' : property;
1840		Elements.prototype[elementsProperty] = Elements.Multi(property);
1841	}
1842};
1843
1844/*
1845Class: Element
1846	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
1847*/
1848
1849Element.extend({
1850
1851	/*
1852	Property: set
1853		you can set events, styles and properties with this shortcut. same as calling new Element.
1854	*/
1855
1856	set: function(props){
1857		for (var prop in props){
1858			var val = props[prop];
1859			switch(prop){
1860				case 'styles': this.setStyles(val); break;
1861				case 'events': if (this.addEvents) this.addEvents(val); break;
1862				case 'properties': this.setProperties(val); break;
1863				default: this.setProperty(prop, val);
1864			}
1865		}
1866		return this;
1867	},
1868
1869	inject: function(el, where){
1870		el = $(el);
1871		switch(where){
1872			case 'before': el.parentNode.insertBefore(this, el); break;
1873			case 'after':
1874				var next = el.getNext();
1875				if (!next) el.parentNode.appendChild(this);
1876				else el.parentNode.insertBefore(this, next);
1877				break;
1878			case 'top':
1879				var first = el.firstChild;
1880				if (first){
1881					el.insertBefore(this, first);
1882					break;
1883				}
1884			default: el.appendChild(this);
1885		}
1886		return this;
1887	},
1888
1889	/*
1890	Property: injectBefore
1891		Inserts the Element before the passed element.
1892
1893	Arguments:
1894		el - an element reference or the id of the element to be injected in.
1895
1896	Example:
1897		>html:
1898		><div id="myElement"></div>
1899		><div id="mySecondElement"></div>
1900		>js:
1901		>$('mySecondElement').injectBefore('myElement');
1902		>resulting html:
1903		><div id="mySecondElement"></div>
1904		><div id="myElement"></div>
1905	*/
1906
1907	injectBefore: function(el){
1908		return this.inject(el, 'before');
1909	},
1910
1911	/*
1912	Property: injectAfter
1913		Same as <Element.injectBefore>, but inserts the element after.
1914	*/
1915
1916	injectAfter: function(el){
1917		return this.inject(el, 'after');
1918	},
1919
1920	/*
1921	Property: injectInside
1922		Same as <Element.injectBefore>, but inserts the element inside.
1923	*/
1924
1925	injectInside: function(el){
1926		return this.inject(el, 'bottom');
1927	},
1928
1929	/*
1930	Property: injectTop
1931		Same as <Element.injectInside>, but inserts the element inside, at the top.
1932	*/
1933
1934	injectTop: function(el){
1935		return this.inject(el, 'top');
1936	},
1937
1938	/*
1939	Property: adopt
1940		Inserts the passed elements inside the Element.
1941
1942	Arguments:
1943		accepts elements references, element ids as string, selectors ($$('stuff')) / array of elements, array of ids as strings and collections.
1944	*/
1945
1946	adopt: function(){
1947		var elements = [];
1948		$each(arguments, function(argument){
1949			elements = elements.concat(argument);
1950		});
1951		$$(elements).inject(this);
1952		return this;
1953	},
1954
1955	/*
1956	Property: remove
1957		Removes the Element from the DOM.
1958
1959	Example:
1960		>$('myElement').remove() //bye bye
1961	*/
1962
1963	remove: function(){
1964		return this.parentNode.removeChild(this);
1965	},
1966
1967	/*
1968	Property: clone
1969		Clones the Element and returns the cloned one.
1970
1971	Arguments:
1972		contents - boolean, when true the Element is cloned with childNodes, default true
1973
1974	Returns:
1975		the cloned element
1976
1977	Example:
1978		>var clone = $('myElement').clone().injectAfter('myElement');
1979		>//clones the Element and append the clone after the Element.
1980	*/
1981
1982	clone: function(contents){
1983		var el = $(this.cloneNode(contents !== false));
1984		if (!el.$events) return el;
1985		el.$events = {};
1986		for (var type in this.$events) el.$events[type] = {
1987			'keys': $A(this.$events[type].keys),
1988			'values': $A(this.$events[type].values)
1989		};
1990		return el.removeEvents();
1991	},
1992
1993	/*
1994	Property: replaceWith
1995		Replaces the Element with an element passed.
1996
1997	Arguments:
1998		el - a string representing the element to be injected in (myElementId, or div), or an element reference.
1999		If you pass div or another tag, the element will be created.
2000
2001	Returns:
2002		the passed in element
2003
2004	Example:
2005		>$('myOldElement').replaceWith($('myNewElement')); //$('myOldElement') is gone, and $('myNewElement') is in its place.
2006	*/
2007
2008	replaceWith: function(el){
2009		el = $(el);
2010		this.parentNode.replaceChild(el, this);
2011		return el;
2012	},
2013
2014	/*
2015	Property: appendText
2016		Appends text node to a DOM element.
2017
2018	Arguments:
2019		text - the text to append.
2020
2021	Example:
2022		><div id="myElement">hey</div>
2023		>$('myElement').appendText(' howdy'); //myElement innerHTML is now "hey howdy"
2024	*/
2025
2026	appendText: function(text){
2027		if (window.ie){
2028			switch(this.getTag()){
2029				case 'style': this.styleSheet.cssText = text; return this;
2030				case 'script': return this.setProperty('text', text);
2031			}
2032		}
2033		this.appendChild(document.createTextNode(text));
2034		return this;
2035	},
2036
2037	/*
2038	Property: hasClass
2039		Tests the Element to see if it has the passed in className.
2040
2041	Returns:
2042		true - the Element has the class
2043		false - it doesn't
2044
2045	Arguments:
2046		className - string; the class name to test.
2047
2048	Example:
2049		>
2049<div id="myElement" class="testClass"></div>
2050		>$('myElement').hasClass('testClass'); //returns true
2051	*/
2052
2053	hasClass: function(className){
2054		return this.className.contains(className, ' ');
2055	},
2056
2057	/*
2058	Property: addClass
2059		Adds the passed in class to the Element, if the element doesnt already have it.
2060
2061	Arguments:
2062		className - string; the class name to add
2063
2064	Example:
2065		><div id="myElement" class="testClass"></div>
2066		>$('myElement').addClass('newClass'); //<div id="myElement" class="testClass newClass"></div>
2067	*/
2068
2069	addClass: function(className){
2070		if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
2071		return this;
2072	},
2073
2074	/*
2075	Property: removeClass
2076		Works like <Element.addClass>, but removes the class from the element.
2077	*/
2078
2079	removeClass: function(className){
2080		this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean();
2081		return this;
2082	},
2083
2084	/*
2085	Property: toggleClass
2086		Adds or removes the passed in class name to the element, depending on if it's present or not.
2087
2088	Arguments:
2089		className - the class to add or remove
2090
2091	Example:
2092		><div id="myElement" class="myClass"></div>
2093		>$('myElement').toggleClass('myClass');
2094		><div id="myElement" class=""></div>
2095		>$('myElement').toggleClass('myClass');
2096		><div id="myElement" class="myClass"></div>
2097	*/
2098
2099	toggleClass: function(className){
2100		return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
2101	},
2102
2103	/*
2104	Property: setStyle
2105		Sets a css property to the Element.
2106
2107		Arguments:
2108			property - the property to set
2109			value - the value to which to set it; for numeric values that require "px" you can pass an integer
2110
2111		Example:
2112			>$('myElement').setStyle('width', '300px'); //the width is now 300px
2113			>$('myElement').setStyle('width', 300); //the width is now 300px
2114	*/
2115
2116	setStyle: function(property, value){
2117		switch(property){
2118			case 'opacity': return this.setOpacity(parseFloat(value));
2119			case 'float': property = (window.ie) ? 'styleFloat' : 'cssFloat';
2120		}
2121		property = property.camelCase();
2122		switch($type(value)){
2123			case 'number': if (!['zIndex', 'zoom'].contains(property)) value += 'px'; break;
2124			case 'array': value = 'rgb(' + value.join(',') + ')';
2125		}
2126		this.style[property] = value;
2127		return this;
2128	},
2129
2130	/*
2131	Property: setStyles
2132		Applies a collection of styles to the Element.
2133
2134	Arguments:
2135		source - an object or string containing all the styles to apply. When its a string it overrides old style.
2136
2137	Examples:
2138		>$('myElement').setStyles({
2139		>	border: '1px solid #000',
2140		>	width: 300,
2141		>	height: 400
2142		>});
2143
2144		OR
2145
2146		>$('myElement').setStyles('border: 1px solid #000; width: 300px; height: 400px;');
2147	*/
2148
2149	setStyles: function(source){
2150		switch($type(source)){
2151			case 'object': Element.setMany(this, 'setStyle', source); break;
2152			case 'string': this.style.cssText = source;
2153		}
2154		return this;
2155	},
2156
2157	/*
2158	Property: setOpacity
2159		Sets the opacity of the Element, and sets also visibility == "hidden" if opacity == 0, and visibility = "visible" if opacity > 0.
2160
2161	Arguments:
2162		opacity - float; Accepts values from 0 to 1.
2163
2164	Example:
2165		>$('myElement').setOpacity(0.5) //make it 50% transparent
2166	*/
2167
2168	setOpacity: function(opacity){
2169		if (opacity == 0){
2170			if (this.style.visibility != "hidden") this.style.visibility = "hidden";
2171		} else {
2172			if (this.style.visibility != "visible") this.style.visibility = "visible";
2173		}
2174		if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
2175		if (window.ie) this.style.filter = (opacity == 1) ? '' : "alpha(opacity=" + opacity * 100 + ")";
2176		this.style.opacity = this.$tmp.opacity = opacity;
2177		return this;
2178	},
2179
2180	/*
2181	Property: getStyle
2182		Returns the style of the Element given the property passed in.
2183
2184	Arguments:
2185		property - the css style property you want to retrieve
2186
2187	Example:
2188		>$('myElement').getStyle('width'); //returns "400px"
2189		>//but you can also use
2190		>$('myElement').getStyle('width').toInt(); //returns 400
2191
2192	Returns:
2193		the style as a string
2194	*/
2195
2196	getStyle: function(property){
2197		property = property.camelCase();
2198		var result = this.style[property];
2199		if (!$chk(result)){
2200			if (property == 'opacity') return this.$tmp.opacity;
2201			var result = [];
2202			for (var style in Element.Styles){
2203				if (property == style){
2204					Element.Styles[style].each(function(s){
2205						var style = this.getStyle(s);
2206						result.push(parseInt(style) ? style : '0px');
2207					}, this);
2208					if (property == 'border'){
2209						var every = result.every(function(bit){
2210							return (bit == result[0]);
2211						});
2212						return (every) ? result[0] : false;
2213					}
2214					return result.join(' ');
2215				}
2216			}
2217			if (property.contains('border')){
2218				if (Element.Styles.border.contains(property)){
2219					return ['Width', 'Style', 'Color'].map(function(p){
2220						return this.getStyle(property + p);
2221					}, this).join(' ');
2222				} else if (Element.borderShort.contains(property)){
2223					return ['Top', 'Right', 'Bottom', 'Left'].map(function(p){
2224						return this.getStyle('border' + p + property.replace('border', ''));
2225					}, this).join(' ');
2226				}
2227			}
2228			if (document.defaultView) result = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate());
2229			else if (this.currentStyle) result = this.currentStyle[property];
2230		}
2231		if (window.ie) result = Element.fixStyle(property, result, this);
2232		if (result && property.test(/color/i) && result.contains('rgb')){
2233			return result.split('rgb').splice(1,4).map(function(color){
2234				return color.rgbToHex();
2235			}).join(' ');
2236		}
2237		return result;
2238	},
2239
2240	/*
2241	Property: getStyles
2242		Returns an object of styles of the Element for each argument passed in.
2243		Arguments:
2244		properties - strings; any number of style properties
2245	Example:
2246		>$('myElement').getStyles('width','height','padding');
2247		>//returns an object like:
2248		>{width: "10px", height: "10px", padding: "10px 0px 10px 0px"}
2249	*/
2250
2251	getStyles: function(){
2252		return Element.getMany(this, 'getStyle', arguments);
2253	},
2254
2255	walk: function(brother, start){
2256		brother += 'Sibling';
2257		var el = (start) ? this[start] : this[brother];
2258		while (el && $type(el) != 'element') el = el[brother];
2259		return $(el);
2260	},
2261
2262	/*
2263	Property: getPrevious
2264		Returns the previousSibling of the Element, excluding text nodes.
2265
2266	Example:
2267		>$('myElement').getPrevious(); //get the previous DOM element from myElement
2268
2269	Returns:
2270		the sibling element or undefined if none found.
2271	*/
2272
2273	getPrevious: function(){
2274		return this.walk('previous');
2275	},
2276
2277	/*
2278	Property: getNext
2279		Works as Element.getPrevious, but tries to find the nextSibling.
2280	*/
2281
2282	getNext: function(){
2283		return this.walk('next');
2284	},
2285
2286	/*
2287	Property: getFirst
2288		Works as <Element.getPrevious>, but tries to find the firstChild.
2289	*/
2290
2291	getFirst: function(){
2292		return this.walk('next', 'firstChild');
2293	},
2294
2295	/*
2296	Property: getLast
2297		Works as <Element.getPrevious>, but tries to find the lastChild.
2298	*/
2299
2300	getLast: function(){
2301		return this.walk('previous', 'lastChild');
2302	},
2303
2304	/*
2305	Property: getParent
2306		returns the $(element.parentNode)
2307	*/
2308
2309	getParent: function(){
2310		return $(this.parentNode);
2311	},
2312
2313	/*
2314	Property: getChildren
2315		returns all the $(element.childNodes), excluding text nodes. Returns as <Elements>.
2316	*/
2317
2318	getChildren: function(){
2319		return $$(this.childNodes);
2320	},
2321
2322	/*
2323	Property: hasChild
2324		returns true if the passed in element is a child of the $(element).
2325	*/
2326
2327	hasChild: function(el) {
2328		return !!$A(this.getElementsByTagName('*')).contains(el);
2329	},
2330
2331	/*
2332	Property: getProperty
2333		Gets the an attribute of the Element.
2334
2335	Arguments:
2336		property - string; the attribute to retrieve
2337
2338	Example:
2339		>$('myImage').getProperty('src') // returns whatever.gif
2340
2341	Returns:
2342		the value, or an empty string
2343	*/
2344
2345	getProperty: function(property){
2346		var index = Element.Properties[property];
2347		if (index) return this[index];
2348		if (!window.ie) return this.getAttribute(property);
2349		var node = this.attributes[property];
2350		return (node) ? node.nodeValue : null;
2351	},
2352
2353	/*
2354	Property: removeProperty
2355		Removes an attribute from the Element
2356
2357	Arguments:
2358		property - string; the attribute to remove
2359	*/
2360
2361	removeProperty: function(property){
2362		var index = Element.Properties[property];
2363		if (index) this[index] = '';
2364		else this.removeAttribute(property);
2365		return this;
2366	},
2367
2368	/*
2369	Property: getProperties
2370		same as <Element.getStyles>, but for properties
2371	*/
2372
2373	getProperties: function(){
2374		return Element.getMany(this, 'getProperty', arguments);
2375	},
2376
2377	/*
2378	Property: setProperty
2379		Sets an attribute for the Element.
2380
2381	Arguments:
2382		property - string; the property to assign the value passed in
2383		value - the value to assign to the property passed in
2384
2385	Example:
2386		>
2386$('myImage').setProperty('src', 'whatever.gif'); //myImage now points to whatever.gif for its source
2387	*/
2388
2389	setProperty: function(property, value){
2390		var index = Element.Properties[property];
2391		if (index) this[index] = value;
2392		else this.setAttribute(property, value);
2393		return this;
2394	},
2395
2396	/*
2397	Property: setProperties
2398		Sets numerous attributes for the Element.
2399
2400	Arguments:
2401		source - an object with key/value pairs.
2402
2403	Example:
2404		(start code)
2405		$('myElement').setProperties({
2406			src: 'whatever.gif',
2407			alt: 'whatever dude'
2408		});
2409		<img src="whatever.gif" alt="whatever dude">
2410		(end)
2411	*/
2412
2413	setProperties: function(source){
2414		return Element.setMany(this, 'setProperty', source);
2415	},
2416
2417	/*
2418	Property: setHTML
2419		Sets the innerHTML of the Element.
2420
2421	Arguments:
2422		html - string; the new innerHTML for the element.
2423
2424	Example:
2425		>$('myElement').setHTML(newHTML) //the innerHTML of myElement is now = newHTML
2426	*/
2427
2428	setHTML: function(){
2429		this.innerHTML = $A(arguments).join('');
2430		return this;
2431	},
2432
2433	/*
2434	Property: getTag
2435		Returns the tagName of the element in lower case.
2436
2437	Example:
2438		>$('myImage').getTag() // returns 'img'
2439
2440	Returns:
2441		The tag name in lower case
2442	*/
2443
2444	getTag: function(){
2445		return this.tagName.toLowerCase();
2446	},
2447
2448	/*
2449	Property: empty
2450		Empties an element of all its children.
2451
2452	Example:
2453		>$('myDiv').empty() // empties the Div and returns it
2454
2455	Returns:
2456		The element.
2457	*/
2458
2459	empty: function(){
2460		Garbage.trash(this.getElementsByTagName('*'));
2461		return this.setHTML('');
2462	}
2463
2464});
2465
2466Element.fixStyle = function(property, result, element){
2467	if ($chk(parseInt(result))) return result;
2468	if (['height', 'width'].contains(property)){
2469		var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'];
2470		var size = 0;
2471		values.each(function(value){
2472			size += element.getStyle('border-' + value + '-width').toInt() + element.getStyle('padding-' + value).toInt();
2473		});
2474		return element['offset' + property.capitalize()] - size + 'px';
2475	} else if (property.test(/border(.+)Width|margin|padding/)){
2476		return '0px';
2477	}
2478	return result;
2479};
2480
2481Element.Styles = {'border': [], 'padding': [], 'margin': []};
2482['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
2483	for (var style in Element.Styles) Element.Styles[style].push(style + direction);
2484});
2485
2486Element.borderShort = ['borderWidth', 'borderStyle', 'borderColor'];
2487
2488Element.getMany = function(el, method, keys){
2489	var result = {};
2490	$each(keys, function(key){
2491		result[key] = el[method](key);
2492	});
2493	return result;
2494};
2495
2496Element.setMany = function(el, method, pairs){
2497	for (var key in pairs) el[method](key, pairs[key]);
2498	return el;
2499};
2500
2501Element.Properties = new Abstract({
2502	'class': 'className', 'for': 'htmlFor', 'colspan': 'colSpan',
2503	'rowspan': 'rowSpan', 'accesskey': 'accessKey', 'tabindex': 'tabIndex',
2504	'maxlength': 'maxLength', 'readonly': 'readOnly', 'value': 'value',
2505	'disabled': 'disabled', 'checked': 'checked', 'multiple': 'multiple'
2506});
2507
2508Element.Methods = {
2509	Listeners: {
2510		addListener: function(type, fn){
2511			if (this.addEventListener) this.addEventListener(type, fn, false);
2512			else this.attachEvent('on' + type, fn);
2513			return this;
2514		},
2515
2516		removeListener: function(type, fn){
2517			if (this.removeEventListener) this.removeEventListener(type, fn, false);
2518			else this.detachEvent('on' + type, fn);
2519			return this;
2520		}
2521	}
2522};
2523
2524window.extend(Element.Methods.Listeners);
2525document.extend(Element.Methods.Listeners);
2526Element.extend(Element.Methods.Listeners);
2527
2528var Garbage = {
2529
2530	elements: [],
2531
2532	collect: function(el){
2533		if (!el.$tmp){
2534			Garbage.elements.push(el);
2535			el.$tmp = {'opacity': 1};
2536		}
2537		return el;
2538	},
2539
2540	trash: function(elements){
2541		for (var i = 0, j = elements.length, el; i < j; i++){
2542			if (!(el = elements[i]) || !el.$tmp) continue;
2543			if (el.$events) el.fireEvent('trash').removeEvents();
2544			for (var p in el.$tmp) el.$tmp[p] = null;
2545			for (var p in Element.prototype) el[p] = null;
2546			el.htmlElement = el.$tmp = el = null;
2547			Garbage.elements.remove(el);
2548		}
2549	},
2550
2551	empty: function(){
2552		Garbage.collect(window);
2553		Garbage.collect(document);
2554		Garbage.trash(Garbage.elements);
2555	}
2556
2557};
2558
2559
2560window.addListener('beforeunload', function(){
2561	window.addListener('unload', Garbage.empty);
2562	if (window.ie) window.addListener('unload', CollectGarbage);
2563});
2564
2565/*
2566Script: Element.Event.js
2567	Contains the Event Class, Element methods to deal with Element events, custom Events, and the Function prototype bindWithEvent.
2568
2569License:
2570	MIT-style license.
2571*/
2572
2573/*
2574Class: Event
2575	Cross browser methods to manage events.
2576
2577Arguments:
2578	event - the event
2579
2580Properties:
2581	shift - true if the user pressed the shift
2582	control - true if the user pressed the control
2583	alt - true if the user pressed the alt
2584	meta - true if the user pressed the meta key
2585	wheel - the amount of third button scrolling
2586	code - the keycode of the key pressed
2587	page.x - the x position of the mouse, relative to the full window
2588	page.y - the y position of the mouse, relative to the full window
2589	client.x - the x position of the mouse, relative to the viewport
2590	client.y - the y position of the mouse, relative to the viewport
2591	key - the key pressed as a lowercase string. key also returns 'enter', 'up', 'down', 'left', 'right', 'space', 'backspace', 'delete', 'esc'. Handy for these special keys.
2592	target - the event target
2593	relatedTarget - the event related target
2594
2595Example:
2596	(start code)
2597	$('myLink').onkeydown = function(event){
2598		var event = new Event(event);
2599		//event is now the Event class.
2600		alert(event.key); //returns the lowercase letter pressed
2601		alert(event.shift); //returns true if the key pressed is shift
2602		if (event.key == 's' && event.control) alert('document saved');
2603	};
2604	(end)
2605*/
2606
2607var Event = new Class({
2608
2609	initialize: function(event){
2610		if (event && event.$extended) return event;
2611		this.$extended = true;
2612		event = event || window.event;
2613		this.event = event;
2614		this.type = event.type;
2615		this.target = event.target || event.srcElement;
2616		if (this.target.nodeType == 3) this.target = this.target.parentNode;
2617		this.shift = event.shiftKey;
2618		this.control = event.ctrlKey;
2619		this.alt = event.altKey;
2620		this.meta = event.metaKey;
2621		if (['DOMMouseScroll', 'mousewheel'].contains(this.type)){
2622			this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
2623		}
2623 else if (this.type.contains('key')){
2624			this.code = event.which || event.keyCode;
2625			for (var name in Event.keys){
2626				if (Event.keys[name] == this.code){
2627					this.key = name;
2628					break;
2629				}
2630			}
2631			if (this.type == 'keydown'){
2632				var fKey = this.code - 111;
2633				if (fKey > 0 && fKey < 13) this.key = 'f' + fKey;
2634			}
2635			this.key = this.key || String.fromCharCode(this.code).toLowerCase();
2636		} else if (this.type.test(/(click|mouse|menu)/)){
2637			this.page = {
2638				'x': event.pageX || event.clientX + document.documentElement.scrollLeft,
2639				'y': event.pageY || event.clientY + document.documentElement.scrollTop
2640			};
2641			this.client = {
2642				'x': event.pageX ? event.pageX - window.pageXOffset : event.clientX,
2643				'y': event.pageY ? event.pageY - window.pageYOffset : event.clientY
2644			};
2645			this.rightClick = (event.which == 3) || (event.button == 2);
2646			switch(this.type){
2647				case 'mouseover': this.relatedTarget = event.relatedTarget || event.fromElement; break;
2648				case 'mouseout': this.relatedTarget = event.relatedTarget || event.toElement;
2649			}
2650			this.fixRelatedTarget();
2651		}
2652		return this;
2653	},
2654
2655	/*
2656	Property: stop
2657		cross browser method to stop an event
2658	*/
2659
2660	stop: function() {
2661		return this.stopPropagation().preventDefault();
2662	},
2663
2664	/*
2665	Property: stopPropagation
2666		cross browser method to stop the propagation of an event
2667	*/
2668
2669	stopPropagation: function(){
2670		if (this.event.stopPropagation) this.event.stopPropagation();
2671		else this.event.cancelBubble = true;
2672		return this;
2673	},
2674
2675	/*
2676	Property: preventDefault
2677		cross browser method to prevent the default action of the event
2678	*/
2679
2680	preventDefault: function(){
2681		if (this.event.preventDefault) this.event.preventDefault();
2682		else this.event.returnValue = false;
2683		return this;
2684	}
2685
2686});
2687
2688Event.fix = {
2689
2690	relatedTarget: function(){
2691		if (this.relatedTarget && this.relatedTarget.nodeType == 3) this.relatedTarget = this.relatedTarget.parentNode;
2692	},
2693
2694	relatedTargetGecko: function(){
2695		try {Event.fix.relatedTarget.call(this)} catch(e){this.relatedTarget = this.target};
2696	}
2697
2698};
2699
2700Event.prototype.fixRelatedTarget = (window.gecko) ? Event.fix.relatedTargetGecko : Event.fix.relatedTarget;
2701
2702/*
2703Property: keys
2704	you can add additional Event keys codes this way:
2705
2706Example:
2707	(start code)
2708	Event.keys.whatever = 80;
2709	$(myelement).addEvent(keydown, function(event){
2710		event = new Event(event);
2711		if (event.key == 'whatever') console.log(whatever key clicked).
2712	});
2713	(end)
2714*/
2715
2716Event.keys = new Abstract({
2717	'enter': 13,
2718	'up': 38,
2719	'down': 40,
2720	'left': 37,
2721	'right': 39,
2722	'esc': 27,
2723	'space': 32,
2724	'backspace': 8,
2725	'tab': 9,
2726	'delete': 46
2727});
2728
2729/*
2730Class: Element
2731	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
2732*/
2733
2734Element.Methods.Events = {
2735
2736	/*
2737	Property: addEvent
2738		Attaches an event listener to a DOM element.
2739
2740	Arguments:
2741		type - the event to monitor ('click', 'load', etc) without the prefix 'on'.
2742		fn - the function to execute
2743
2744	Example:
2745		>$('myElement').addEvent('click', function(){alert('clicked!')});
2746	*/
2747
2748	addEvent: function(type, fn){
2749		this.$events = this.$events || {};
2750		this.$events[type] = this.$events[type] || {'keys': [], 'values': []};
2751		if (this.$events[type].keys.contains(fn)) return this;
2752		this.$events[type].keys.push(fn);
2753		var realType = type;
2754		var custom = Element.Events[type];
2755		if (custom){
2756			if (custom.add) custom.add.call(this, fn);
2757			if (custom.map) fn = custom.map;
2758			if (custom.type) realType = custom.type;
2759		}
2760		if (!this.addEventListener) fn = fn.create({'bind': this, 'event': true});
2761		this.$events[type].values.push(fn);
2762		return this.addListener(realType, fn);
2763	},
2764
2765	/*
2766	Property: removeEvent
2767		Works as Element.addEvent, but instead removes the previously added event listener.
2768	*/
2769
2770	removeEvent: function(type, fn){
2771		if (!this.$events || !this.$events[type]) return this;
2772		var pos = this.$events[type].keys.indexOf(fn);
2773		if (pos == -1) return this;
2774		var key = this.$events[type].keys.splice(pos,1)[0];
2775		var value = this.$events[type].values.splice(pos,1)[0];
2776		var custom = Element.Events[type];
2777		if (custom){
2778			if (custom.remove) custom.remove.call(this, fn);
2779			if (custom.type) type = custom.type;
2780		}
2781		return this.removeListener(type, value);
2782	},
2783
2784	/*
2785	Property: addEvents
2786		As <addEvent>, but accepts an object and add multiple events at once.
2787	*/
2788
2789	addEvents: function(source){
2790		return Element.setMany(this, 'addEvent', source);
2791	},
2792
2793	/*
2794	Property: removeEvents
2795		removes all events of a certain type from an element. if no argument is passed in, removes all events.
2796
2797	Arguments:
2798		type - string; the event name (e.g. 'click')
2799	*/
2800
2801	removeEvents: function(type){
2802		if (!this.$events) return this;
2803		if (!type){
2804			for (var evType in this.$events) this.removeEvents(evType);
2805			this.$events = null;
2806		} else if (this.$events[type]){
2807			this.$events[type].keys.each(function(fn){
2808				this.removeEvent(type, fn);
2809			}, this);
2810			this.$events[type] = null;
2811		}
2812		return this;
2813	},
2814
2815	/*
2816	Property: fireEvent
2817		executes all events of the specified type present in the element.
2818
2819	Arguments:
2820		type - string; the event name (e.g. 'click')
2821		args - array or single object; arguments to pass to the function; if more than one argument, must be an array
2822		delay - (integer) delay (in ms) to wait to execute the event
2823	*/
2824
2825	fireEvent: function(type, args, delay){
2826		if (!this.$events || !this.$events[type]) return this;
2827		this.$events[type].keys.each(function(fn){
2828			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
2829		}, this);
2830		return this;
2831	},
2832
2833	/*
2834	Property: cloneEvents
2835		Clones all events from an element to this element.
2836
2837	Arguments:
2838		from - element, copy all events from this element
2839		type - optional, copies only events of this type
2840	*/
2841
2842	cloneEvents: function(from, type){
2843		if (!from.$events) return this;
2844		if (!type){
2845			for (var evType in from.$events) this.cloneEvents(from, evType);
2846		} else if (from.$events[type]){
2847			from.$events[type].keys.each(function(fn){
2848				this.addEvent(type, fn);
2849			}, this);
2850		}
2851		return this;
2852	}
2853
2854};
2855
2856window.extend(Element.Methods.Events);
2857document.extend(Element.Methods.Events);
2858Element.extend(Element.Methods.Events);
2859
2860/* Section: Custom Events */
2861
2862Element.Events = new Abstract({
2863
2864	/*
2865	Event: mouseenter
2866		In addition to the standard javascript events (load, mouseover, mouseout, click, etc.) <Event.js> contains two custom events
2867		this event fires when the mouse enters the area of the dom element; will not be fired again if the mouse crosses over children of the element (unlike mouseover)
2868
2869
2870	Example:
2871		>$(myElement).addEvent('mouseenter', myFunction);
2872	*/
2873
2874	'mouseenter': {
2875		type: 'mouseover',
2876		map: function(event){
2877			event = new Event(event);
2878			if (event.relatedTarget == this || this.hasChild(event.relatedTarget)) return;
2879			this.fireEvent('mouseenter', event);
2880		}
2881	},
2882
2883	/*
2884	Event: mouseleave
2885		this event fires when the mouse exits the area of the dom element; will not be fired again if the mouse crosses over children of the element (unlike mouseout)
2886
2887
2888	Example:
2889		>$(myElement).addEvent('mouseleave', myFunction);
2890	*/
2891
2892	'mouseleave': {
2893		type: 'mouseout',
2894		map: function(event){
2895			event = new Event(event);
2896			if (event.relatedTarget == this || this.hasChild(event.relatedTarget)) return;
2897			this.fireEvent('mouseleave', event);
2898		}
2899	},
2900
2901	'mousewheel': {
2902		type: (window.gecko) ? 'DOMMouseScroll' : 'mousewheel'
2903	}
2904
2905});
2906
2907/*
2908Class: Function
2909	A collection of The Function Object prototype methods.
2910*/
2911
2912Function.extend({
2913
2914	/*
2915	Property: bindWithEvent
2916		automatically passes mootools Event Class.
2917
2918	Arguments:
2919		bind - optional, the object that the "this" of the function will refer to.
2920		args - optional, an argument to pass to the function; if more than one argument, it must be an array of arguments.
2921
2922	Returns:
2923		a function with the parameter bind as its "this" and as a pre-passed argument event or window.event, depending on the browser.
2924
2925	Example:
2926		>function myFunction(event){
2927		>	alert(event.client.x) //returns the coordinates of the mouse..
2928		>};
2929		>myElement.onclick = myFunction.bindWithEvent(myElement);
2930	*/
2931
2932	bindWithEvent: function(bind, args){
2933		return this.create({'bind': bind, 'arguments': args, 'event': Event});
2934	}
2935
2936});
2937
2938/*
2939Script: Element.Filters.js
2940	add Filters capability to <Elements>.
2941
2942License:
2943	MIT-style license.
2944*/
2945
2946/*
2947Class: Elements
2948	A collection of methods to be used with <$$> elements collections.
2949*/
2950
2951Elements.extend({
2952	
2953	/*
2954	Property: filterByTag
2955		Filters the collection by a specified tag name.
2956		Returns a new Elements collection, while the original remains untouched.
2957	*/
2958	
2959	filterByTag: function(tag){
2960		return new Elements(this.filter(function(el){
2961			return (Element.getTag(el) == tag);
2962		}));
2963	},
2964	
2965	/*
2966	Property: filterByClass
2967		Filters the collection by a specified class name.
2968		Returns a new Elements collection, while the original remains untouched.
2969	*/
2970	
2971	filterByClass: function(className, nocash){
2972		var elements = this.filter(function(el){
2973			return (el.className && el.className.contains(className, ' '));
2974		});
2975		return (nocash) ? elements : new Elements(elements);
2976	},
2977	
2978	/*
2979	Property: filterById
2980		Filters the collection by a specified ID.
2981		Returns a new Elements collection, while the original remains untouched.
2982	*/
2983	
2984	filterById: function(id, nocash){
2985		var elements = this.filter(function(el){
2986			return (el.id == id);
2987		});
2988		return (nocash) ? elements : new Elements(elements);
2989	},
2990	
2991	/*
2992	Property: filterByAttribute
2993		Filters the collection by a specified attribute.
2994		Returns a new Elements collection, while the original remains untouched.
2995		
2996	Arguments:
2997		name - the attribute name.
2998		operator - optional, the attribute operator.
2999		value - optional, the attribute value, only valid if the operator is specified.
3000	*/
3001	
3002	filterByAttribute: function(name, operator, value, nocash){
3003		var elements = this.filter(function(el){
3004			var current = Element.getProperty(el, name);
3005			if (!current) return false;
3006			if (!operator) return true;
3007			switch(operator){
3008				case '=': return (current == value);
3009				case '*=': return (current.contains(value));
3010				case '^=': return (current.substr(0, value.length) == value);
3011				case '$=': return (current.substr(current.length - value.length) == value);
3012				case '!=': return (current != value);
3013				case '~=': return current.contains(value, ' ');
3014			}
3015			return false;
3016		});
3017		return (nocash) ? elements : new Elements(elements);
3018	}
3019
3020});
3021
3022/*
3023Script: Element.Selectors.js
3024	Css Query related functions and <Element> extensions
3025
3026License:
3027	MIT-style license.
3028*/
3029
3030/* Section: Utility Functions */
3031
3032/*
3033Function: $E
3034	Selects a single (i.e. the first found) Element based on the selector passed in and an optional filter element.
3035	Returns as <Element>.
3036
3037Arguments:
3038	selector - string; the css selector to match
3039	filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
3040
3041Example:
3042	>$E('a', 'myElement') //find the first anchor tag inside the DOM element with id 'myElement'
3043
3044Returns:
3045	a DOM element - the first element that matches the selector
3046*/
3047
3048function $E(selector, filter){
3049	return ($(filter) || document).getElement(selector);
3050};
3051
3052/*
3053Function: $ES
3054	Returns a collection of Elements that match the selector passed in limited to the scope of the optional filter.
3055	See Also: <Element.getElements> for an alternate syntax.
3056	Returns as <Elements>.
3057
3058Returns:
3059	an array of dom elements that match the selector within the filter
3060
3061Arguments:
3062	selector - string; css selector to match
3063	filter - optional; a DOM element to limit the scope of the selector match; defaults to document.
3064
3065Examples:
3066	>$ES("a") //gets all the anchor tags; synonymous with $$("a")
3067	>$ES('a','myElement') //get all the anchor tags within $('myElement')
3068*/
3069
3070function $ES(selector, filter){
3071	return ($(filter) || document).getElementsBySelector(selector);
3072};
3073
3074$$.shared = {
3075
3076	'regexp': /^(\w*|\*)(?:#([\w-]+)|\.([\w-]+))?(?:\[(\w+)(?:([!*^$]?=)["']?([^"'\]]*)["']?)?])?$/,
3077	
3078	'xpath': {
3079
3080		getParam: function(items, context, param, i){
3081			var temp = [context.namespaceURI ? 'xhtml:' : '', param[1]];
3082			if (param[2]) temp.push('[@id="', param[2], '"]');
3083			if (param[3]) temp.push('[contains(concat(" ", @class, " "), " ', param[3], ' ")]');
3084			if (param[4]){
3085				if (param[5] && param[6]){
3086					switch(param[5]){
3087						case '*=': temp.push('[contains(@', param[4], ', "', param[6], '")]'); break;
3088						case '^=': temp.push('[starts-with(@', param[4], ', "', param[6], '")]'); break;
3089						case '$=': temp.push('[substring(@', param[4], ', string-length(@', param[4], ') - ', param[6].length, ' + 1) = "', param[6], '"]'); break;
3090						case '=': temp.push('[@', param[4], '="', param[6], '"]'); break;
3091						case '!=': temp.push('[@', param[4], '!="', param[6], '"]');
3092					}
3093				} else {
3094					temp.push('[@', param[4], ']');
3095				}
3096			}
3097			items.push(temp.join(''));
3098			return items;
3099		},
3100		
3101		getItems: function(items, context, nocash){
3102			var elements = [];
3103			var xpath = document.evaluate('.//' + items.join('//'), context, $$.shared.resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
3104			for (var i = 0, j = xpath.snapshotLength; i < j; i++) elements.push(xpath.snapshotItem(i));
3105			return (nocash) ? elements : new Elements(elements.map($));
3106		}
3107
3108	},
3109	
3110	'normal': {
3111		
3112		getParam: function(items, context, param, i){
3113			if (i == 0){
3114				if (param[2]){
3115					var el = context.getElementById(param[2]);
3116					if (!el || ((param[1] != '*') && (Element.getTag(el) != param[1]))) return false;
3117					items = [el];
3118				} else {
3119					items = $A(context.getElementsByTagName(param[1]));
3120				}
3121			} else {
3122				items = $$.shared.getElementsByTagName(items, param[1]);
3123				if (param[2]) items = Elements.filterById(items, param[2], true);
3124			}
3125			if (param[3]) items = Elements.filterByClass(items, param[3], true);
3126			if (param[4]) items = Elements.filterByAttribute(items, param[4], param[5], param[6], true);
3127			return items;
3128		},
3129
3130		getItems: function(items, context, nocash){
3131			return (nocash) ? items : $$.unique(items);
3132		}
3133
3134	},
3135
3136	resolver: function(prefix){
3137		return (prefix == 'xhtml') ? 'http://www.w3.org/1999/xhtml' : false;
3138	},
3139
3140	getElementsByTagName: function(context, tagName){
3141		var found = [];
3142		for (var i = 0, j = context.length; i < j; i++) found.extend(context[i].getElementsByTagName(tagName));
3143		return found;
3144	}
3145
3146};
3147
3148$$.shared.method = (window.xpath) ? 'xpath' : 'normal';
3149
3150/*
3151Class: Element
3152	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3153*/
3154
3155Element.Methods.Dom = {
3156
3157	/*
3158	Property: getElements
3159		Gets all the elements within an element that match the given (single) selector.
3160		Returns as <Elements>.
3161
3162	Arguments:
3163		selector - string; the css selector to match
3164
3165	Examples:
3166		>$('myElement').getElements('a'); // get all anchors within myElement
3167		>$('myElement').getElements('input[name=dialog]') //get all input tags with name 'dialog'
3168		>$('myElement').getElements('input[name$=log]') //get all input tags with names ending with 'log'
3169
3170	Notes:
3171		Supports these operators in attribute selectors:
3172
3173		- = : is equal to
3174		- ^= : starts-with
3175		- $= : ends-with
3176		- != : is not equal to
3177
3178		Xpath is used automatically for compliant browsers.
3179	*/
3180
3181	getElements: function(selector, nocash){
3182		var items = [];
3183		selector = selector.trim().split(' ');
3184		for (var i = 0, j = selector.length; i < j; i++){
3185			var sel = selector[i];
3186			var param = sel.match($$.shared.regexp);
3187			if (!param) break;
3188			param[1] = param[1] || '*';
3189			var temp = $$.shared[$$.shared.method].getParam(items, this, param, i);
3190			if (!temp) break;
3191			items = temp;
3192		}
3193		return $$.shared[$$.shared.method].getItems(items, this, nocash);
3194	},
3195
3196	/*
3197	Property: getElement
3198		Same as <Element.getElements>, but returns only the first. Alternate syntax for <$E>, where filter is the Element.
3199		Returns as <Element>.
3200
3201	Arguments:
3202		selector - string; css selector
3203	*/
3204
3205	getElement: function(selector){
3206		return $(this.getElements(selector, true)[0] || false);
3207	},
3208
3209	/*
3210	Property: getElementsBySelector
3211		Same as <Element.getElements>
3211, but allows for comma separated selectors, as in css. Alternate syntax for <$$>, where filter is the Element.
3212		Returns as <Elements>.
3213
3214	Arguments:
3215		selector - string; css selector
3216	*/
3217
3218	getElementsBySelector: function(selector, nocash){
3219		var elements = [];
3220		selector = selector.split(',');
3221		for (var i = 0, j = selector.length; i < j; i++) elements = elements.concat(this.getElements(selector[i], true));
3222		return (nocash) ? elements : $$.unique(elements);
3223	},
3224
3225	/*
3226	Property: getElementsByClassName
3227		Returns all the elements that match a specific class name.
3228		Here for compatibility purposes. can also be written: document.getElements('.className'), or $$('.className')
3229		Returns as <Elements>.
3230
3231	Arguments:
3232		className - string; css classname
3233	*/
3234
3235	getElementsByClassName: function(className){
3236		return this.getElements('.' + className);
3237	}
3238
3239};
3240
3241Element.extend({
3242
3243	/*
3244	Property: getElementById
3245		Targets an element with the specified id found inside the Element. Does not overwrite document.getElementById.
3246
3247	Arguments:
3248		id - string; the id of the element to find.
3249	*/
3250
3251	getElementById: function(id){
3252		var el = document.getElementById(id);
3253		if (!el) return false;
3254		for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
3255			if (!parent) return false;
3256		}
3257		return el;
3258	}
3259
3260});
3261
3262document.extend(Element.Methods.Dom);
3263Element.extend(Element.Methods.Dom);
3264
3265/*
3266Script: Element.Form.js
3267	Contains Element prototypes to deal with Forms and their elements.
3268
3269License:
3270	MIT-style license.
3271*/
3272
3273/*
3274Class: Element
3275	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3276*/
3277
3278Element.extend({
3279
3280	/*
3281	Property: getValue
3282		Returns the value of the Element, if its tag is textarea, select or input. getValue called on a multiple select will return an array.
3283	*/
3284
3285	getValue: function(){
3286		switch(this.getTag()){
3287			case 'select':
3288				var values = [];
3289				$each(this.options, function(option){
3290					if (option.selected) values.push($pick(option.value, option.text));
3291				});
3292				return (this.multiple) ? values : values[0];
3293			case 'input': if (!(this.checked && ['checkbox', 'radio'].contains(this.type)) && !['hidden', 'text', 'password'].contains(this.type)) break;
3294			case 'textarea': return this.value;
3295		}
3296		return false;
3297	},
3298
3299	getFormElements: function(){
3300		return $$(this.getElementsByTagName('input'), this.getElementsByTagName('select'), this.getElementsByTagName('textarea'));
3301	},
3302
3303	/*
3304	Property: toQueryString
3305		Reads the children inputs of the Element and generates a query string, based on their values. Used internally in <Ajax>
3306
3307	Example:
3308		(start code)
3309		<form id="myForm" action="submit.php">
3310		<input name="email" value="[email protected]">
3311		<input name="zipCode" value="90210">
3312		</form>
3313
3314		<script>
3315		 $('myForm').toQueryString()
3316		</script>
3317		(end)
3318
3319		Returns:
3320			[email protected]&zipCode=90210
3321	*/
3322
3323	toQueryString: function(){
3324		var queryString = [];
3325		this.getFormElements().each(function(el){
3326			var name = el.name;
3327			var value = el.getValue();
3328			if (value === false || !name || el.disabled) return;
3329			var qs = function(val){
3330				queryString.push(name + '=' + encodeURIComponent(val));
3331			};
3332			if ($type(value) == 'array') value.each(qs);
3333			else qs(value);
3334		});
3335		return queryString.join('&');
3336	}
3337
3338});
3339
3340/*
3341Script: Element.Dimensions.js
3342	Contains Element prototypes to deal with Element size and position in space.
3343
3344Note:
3345	The functions in this script require n XHTML doctype.
3346
3347License:
3348	MIT-style license.
3349*/
3350
3351/*
3352Class: Element
3353	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3354*/
3355
3356Element.extend({
3357
3358	/*
3359	Property: scrollTo
3360		Scrolls the element to the specified coordinated (if the element has an overflow)
3361
3362	Arguments:
3363		x - the x coordinate
3364		y - the y coordinate
3365
3366	Example:
3367		>$('myElement').scrollTo(0, 100)
3368	*/
3369
3370	scrollTo: function(x, y){
3371		this.scrollLeft = x;
3372		this.scrollTop = y;
3373	},
3374
3375	/*
3376	Property: getSize
3377		Return an Object representing the size/scroll values of the element.
3378
3379	Example:
3380		(start code)
3381		$('myElement').getSize();
3382		(end)
3383
3384	Returns:
3385		(start code)
3386		{
3387			'scroll': {'x': 100, 'y': 100},
3388			'size': {'x': 200, 'y': 400},
3389			'scrollSize': {'x': 300, 'y': 500}
3390		}
3391		(end)
3392	*/
3393
3394	getSize: function(){
3395		return {
3396			'scroll': {'x': this.scrollLeft, 'y': this.scrollTop},
3397			'size': {'x': this.offsetWidth, 'y': this.offsetHeight},
3398			'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight}
3399		};
3400	},
3401
3402	/*
3403	Property: getPosition
3404		Returns the real offsets of the element.
3405
3406	Arguments:
3407		overflown - optional, an array of nested scrolling containers for scroll offset calculation, use this if your element is inside any element containing scrollbars
3408
3409	Example:
3410		>$('element').getPosition();
3411
3412	Returns:
3413		>{x: 100, y:500};
3414	*/
3415
3416	getPosition: function(overflown){
3417		overflown = overflown || [];
3418		var el = this, left = 0, top = 0;
3419		do {
3420			left += el.offsetLeft || 0;
3421			top += el.offsetTop || 0;
3422			el = el.offsetParent;
3423		} while (el);
3424		overflown.each(function(element){
3425			left -= element.scrollLeft || 0;
3426			top -= element.scrollTop || 0;
3427		});
3428		return {'x': left, 'y': top};
3429	},
3430
3431	/*
3432	Property: getTop
3433		Returns the distance from the top of the window to the Element.
3434
3435	Arguments:
3436		overflown - optional, an array of nested scrolling containers, see Element::getPosition
3437	*/
3438
3439	getTop: function(overflown){
3440		return this.getPosition(overflown).y;
3441	},
3442
3443	/*
3444	Property: getLeft
3445		Returns the distance from the left of the window to the Element.
3446
3447	Arguments:
3448		overflown - optional, an array of nested scrolling containers, see Element::getPosition
3449	*/
3450
3451	getLeft: function(overflown){
3452		return this.getPosition(overflown).x;
3453	},
3454
3455	/*
3456	Property: getCoordinates
3457		Returns an object with width, height, left, right, top, and bottom, representing the values of the Element
3458
3459	Arguments:
3460		overflown - optional, an array of nested scrolling containers, see Element::getPosition
3461
3462	Example:
3463		(start code)
3464		var myValues = $('myElement').getCoordinates();
3465		(end)
3466
3467	Returns:
3468		(start code)
3469		{
3470			width: 200,
3471			height: 300,
3472			left: 100,
3473			top: 50,
3474			right: 300,
3475			bottom: 350
3476		}
3477		(end)
3478	*/
3479
3480	getCoordinates: function(overflown){
3481		var position = this.getPosition(overflown);
3482		var obj = {
3483			'width': this.offsetWidth,
3484			'height': this.offsetHeight,
3485			'left': position.x,
3486			'top': position.y
3487		};
3488		obj.right = obj.left + obj.width;
3489		obj.bottom = obj.top + obj.height;
3490		return obj;
3491	}
3492
3493});
3494
3495/*
3496Script: Window.DomReady.js
3497	Contains the custom event domready, for window.
3498
3499License:
3500	MIT-style license.
3501*/
3502
3503/* Section: Custom Events */
3504
3505/*
3506Event: domready
3507	executes a function when the dom tree is loaded, without waiting for images. Only works when called from window. 
3508
3509Credits:
3510	(c) Dean Edwards/Matthias Miller/John Resig, remastered for mootools.
3511
3512Arguments:
3513	fn - the function to execute when the DOM is ready
3514
3515Example:
3516	> window.addEvent('domready', function(){
3517	>	alert('the dom is ready');
3518	> });
3519*/
3520
3521Element.Events.domready = {
3522
3523	add: function(fn){
3524		if (window.loaded){
3525			fn.call(this);
3526			return;
3527		}
3528		var domReady = function(){
3529			if (window.loaded) return;
3530			window.loaded = true;
3531			window.timer = $clear(window.timer);
3532			this.fireEvent('domready');
3533		}.bind(this);
3534		if (document.readyState && window.webkit){
3535			window.timer = function(){
3536				if (['loaded','complete'].contains(document.readyState)) domReady();
3537			}.periodical(50);
3538		} else if (document.readyState && window.ie){
3539			if (!$('ie_ready')){
3540				var src = (window.location.protocol == 'https:') ? '://0' : 'javascript:void(0)';
3541				document.write('<script id="ie_ready" defer src="' + src + '"><\/script>');
3542				$('ie_ready').onreadystatechange = function(){
3543					if (this.readyState == 'complete') domReady();
3544				};
3545			}
3546		} else {
3547			window.addListener("load", domReady);
3548			document.addListener("DOMContentLoaded", domReady);
3549		}
3550	}
3551
3552};
3553
3554window.onDomReady = function(fn){
3555	return this.addEvent('domready', fn);
3556};
3557
3558/*
3559Script: Window.Size.js
3560	Window cross-browser dimensions methods.
3561	
3562Note:
3563	The Functions in this script require an XHTML doctype.
3564
3565License:
3566	MIT-style license.
3567*/
3568
3569/*
3570Class: window
3571	Cross browser methods to get various window dimensions.
3572	Warning: All these methods require that the browser operates in strict mode, not quirks mode.
3573*/
3574
3575window.extend({
3576
3577	/*
3578	Property: getWidth
3579		Returns an integer representing the width of the browser window (without the scrollbar).
3580	*/
3581
3582	getWidth: function(){
3583		if (this.webkit419) return this.innerWidth;
3584		if (this.opera) return document.body.clientWidth;
3585		return document.documentElement.clientWidth;
3586	},
3587
3588	/*
3589	Property: getHeight
3590		Returns an integer representing the height of the browser window (without the scrollbar).
3591	*/
3592
3593	getHeight: function(){
3594		if (this.webkit419) return this.innerHeight;
3595		if (this.opera) return document.body.clientHeight;
3596		return document.documentElement.clientHeight;
3597	},
3598
3599	/*
3600	Property: getScrollWidth
3601		Returns an integer representing the scrollWidth of the window.
3602		This value is equal to or bigger than <getWidth>.
3603
3604	See Also:
3605		<http://developer.mozilla.org/en/docs/DOM:element.scrollWidth>
3606	*/
3607
3608	getScrollWidth: function(){
3609		if (this.ie) return Math.max(document.documentElement.offsetWidth, document.documentElement.scrollWidth);
3610		if (this.webkit) return document.body.scrollWidth;
3611		return document.documentElement.scrollWidth;
3612	},
3613
3614	/*
3615	Property: getScrollHeight
3616		Returns an integer representing the scrollHeight of the window.
3617		This value is equal to or bigger than <getHeight>.
3618
3619	See Also:
3620		<http://developer.mozilla.org/en/docs/DOM:element.scrollHeight>
3621	*/
3622
3623	getScrollHeight: function(){
3624		if (this.ie) return Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight);
3625		if (this.webkit) return document.body.scrollHeight;
3626		return document.documentElement.scrollHeight;
3627	},
3628
3629	/*
3630	Property: getScrollLeft
3631		Returns an integer representing the scrollLeft of the window (the number of pixels the window has scrolled from the left).
3632
3633	See Also:
3634		<http://developer.mozilla.org/en/docs/DOM:element.scrollLeft>
3635	*/
3636
3637	getScrollLeft: function(){
3638		return this.pageXOffset || document.documentElement.scrollLeft;
3639	},
3640
3641	/*
3642	Property: getScrollTop
3643		Returns an integer representing the scrollTop of the window (the number of pixels the window has scrolled from the top).
3644
3645	See Also:
3646		<http://developer.mozilla.org/en/docs/DOM:element.scrollTop>
3647	*/
3648
3649	getScrollTop: function(){
3650		return this.pageYOffset || document.documentElement.scrollTop;
3651	},
3652
3653	/*
3654	Property: getSize
3655		Same as <Element.getSize>
3656	*/
3657
3658	getSize: function(){
3659		return {
3660			'size': {'x': this.getWidth(), 'y': this.getHeight()},
3661			'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()},
3662			'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()}
3663		};
3664	},
3665
3666	//ignore
3667	getPosition: function(){return {'x': 0, 'y': 0}}
3668
3669});
3670
3671/*
3672Script: Fx.Base.js
3673	Contains <Fx.Base> and two Transitions.
3674
3675License:
3676	MIT-style license.
3677*/
3678
3679var Fx = {Shared: {}};
3680
3681/*
3682Class: Fx.Base
3683	Base class for the Mootools Effects (Moo.Fx) library.
3684
3685Options:
3686	onStart - the function to execute as the effect begins; nothing (<Class.empty>) by default.
3687	onComplete - the function to execute after the effect has processed; nothing (<Class.empty>) by default.
3688	transition - the equation to use for the effect see <Fx.Transitions>; default is <Fx.Transitions.Sine.easeInOut>
3689	duration - the duration of the effect in ms; 500 is the default.
3690	unit - the unit is 'px' by default (other values include things like 'em' for fonts or '%').
3691	wait - boolean: to wait or not to wait for a current transition to end before running another of the same instance. defaults to true.
3692	fps - the frames per second for the transition; default is 30
3693*/
3694
3695Fx.Base = new Class({
3696
3697	options: {
3698		onStart: Class.empty,
3699		onComplete: Class.empty,
3700		onCancel: Class.empty,
3701		transition: function(p){
3702			return -(Math.cos(Math.PI * p) - 1) / 2;
3703		},
3704		duration: 500,
3705		unit: 'px',
3706		wait: true,
3707		fps: 50
3708	},
3709
3710	initialize: function(options){
3711		this.element = this.element || null;
3712		this.setOptions(options);
3713		if (this.options.initialize) this.options.initialize.call(this);
3714	},
3715
3716	step: function(){
3717		var time = $time();
3718		if (time < this.time + this.options.duration){
3719			this.delta = this.options.transition((time - this.time) / this.options.duration);
3720			this.setNow();
3721			this.increase();
3722		} else {
3723			this.stop(true);
3724			this.set(this.to);
3725			this.fireEvent('onComplete', this.element, 10);
3726			this.callChain();
3727		}
3728	},
3729
3730	/*
3731	Property: set
3732		Immediately sets the value with no transition.
3733
3734	Arguments:
3735		to - the point to jump to
3736
3737	Example:
3738		>var myFx = new Fx.Style('myElement', 'opacity').set(0); //will make it immediately transparent
3739	*/
3740
3741	set: function(to){
3742		this.now = to;
3743		this.increase();
3744		return this;
3745	},
3746	
3747	setNow: function(){
3748		this.now = this.compute(this.from, this.to);
3749	},
3750	
3751	compute: function(from, to){
3752		return (to - from) * this.delta + from;
3753	},
3754
3755	/*
3756	Property: start
3757		Executes an effect from one position to the other.
3758
3759	Arguments:
3760		from - integer: staring value
3761		to - integer: the ending value
3762
3763	Examples:
3764		>var myFx = new Fx.Style('myElement', 'opacity').start(0,1); //display a transition from transparent to fing.
3765	*/
3766
3767	start: function(from, to){
3768		if (!this.options.wait) this.stop();
3769		else if (this.timer) return this;
3770		this.from = from;
3771		this.to = to;
3772		this.change = this.to - this.from;
3773		this.time = $time();
3774		this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
3775		this.fireEvent('onStart', this.element);
3776		return this;
3777	},
3778
3779	/*
3780	Property: stop
3781		Stops the transition.
3782	*/
3783
3784	stop: function(end){
3785		if (!this.timer) return this;
3786		this.timer = $clear(this.timer);
3787		if (!end) this.fireEvent('onCancel', this.element);
3788		return this;
3789	},
3790
3791	//compat
3792	custom: function(from, to){return this.start(from, to)},
3793	clearTimer: function(end){return this.stop(end)}
3794
3795});
3796
3797Fx.Base.implement(new Chain, new Events, new Options);
3798
3799/*
3800Script: Fx.CSS.js
3801	Css parsing class for effects. Required by <Fx.Style>, <Fx.Styles>, <Fx.Elements>. No documentation needed, as its used internally.
3802
3803License:
3804	MIT-style license.
3805*/
3806
3807Fx.CSS = {
3808
3809	select: function(property, to){
3810		if (property.test(/color/i)) return this.Color;
3811		if (to.contains && to.contains(' ')) return this.Multi;
3812		return this.Single;
3813	},
3814
3815	parse: function(el, property, fromTo){
3816		if (!fromTo.push) fromTo = [fromTo];
3817		var from = fromTo[0], to = fromTo[1];
3818		if (!to && to != 0){
3819			to = from;
3820			from = el.getStyle(property);
3821		}
3822		var css = this.select(property, to);
3823		return {from: css.parse(from), to: css.parse(to), css: css};
3824	}
3825
3826};
3827
3828Fx.CSS.Single = {
3829
3830	parse: function(value){
3831		return parseFloat(value);
3832	},
3833
3834	getNow: function(from, to, fx){
3835		return fx.compute(from, to);
3836	},
3837
3838	getValue: function(value, unit, property){
3839		if (unit == 'px' && property != 'opacity') value = Math.round(value);
3840		return value + unit;
3841	}
3842
3843};
3844
3845Fx.CSS.Multi = {
3846
3847	parse: function(value){
3848		return value.push ? value : value.split(' ').map(function(v){
3849			return parseFloat(v);
3850		});
3851	},
3852
3853	getNow: function(from, to, fx){
3854		var now = [];
3855		for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]);
3856		return now;
3857	},
3858
3859	getValue: function(value, unit, property){
3860		if (unit == 'px' && property != 'opacity') value = value.map(Math.round);
3861		return value.join(unit + ' ') + unit;
3862	}
3863
3864};
3865
3866Fx.CSS.Color = {
3867
3868	parse: function(value){
3869		return value.push ? value : value.hexToRgb(true);
3870	},
3871
3872	getNow: function(from, to, fx){
3873		var now = [];
3874		for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i]));
3875		return now;
3876	},
3877
3878	getValue: function(value){
3879		return 'rgb(' + value.join(',') + ')';
3880	}
3881
3882};
3883
3884/*
3885Script: Fx.Style.js
3886	Contains <Fx.Style>
3887
3888License:
3889	MIT-style license.
3890*/
3891
3892/*
3893Class: Fx.Style
3894	The Style effect; Extends <Fx.Base>, inherits all its properties. Used to transition any css property from one value to another. Includes colors.
3895	Colors must be in hex format.
3896
3897Arguments:
3898	el - the $(element) to apply the style transition to
3899	property - the property to transition
3900	options - the Fx.Base options (see: <Fx.Base>)
3901
3902Example:
3903	>var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
3904	>marginChange.start(10, 100);
3905*/
3906
3907Fx.Style = Fx.Base.extend({
3908
3909	initialize: function(el, property, options){
3910		this.element = $(el);
3911		this.property = property;
3912		this.parent(options);
3913	},
3914
3915	/*
3916	Property: hide
3917		Same as <Fx.Base.set> (0); hides the element immediately without transition.
3918	*/
3919
3920	hide: function(){
3921		return this.set(0);
3922	},
3923
3924	setNow: function(){
3925		this.now = this.css.getNow(this.from, this.to, this);
3926	},
3927
3928	/*
3929	Property: set
3930		Sets the element's css property (specified at instantiation) to the specified value immediately.
3931
3932	Example:
3933		(start code)
3934		var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
3935		marginChange.set(10); //margin-top is set to 10px immediately
3936		(end)
3937	*/
3938
3939	set: function(to){
3940		this.css = Fx.CSS.select(this.property, to);
3941		return this.parent(this.css.parse(to));
3942	},
3943
3944	/*
3945	Property: start
3946		Displays the transition to the value/values passed in
3947
3948	Arguments:
3949		from - (integer; optional) the starting position for the transition
3950		to - (integer) the ending position for the transition
3951
3952	Note:
3953		If you provide only one argument, the transition will use the current css value for its starting value.
3954
3955	Example:
3956		(start code)
3957		var marginChange = new Fx.Style('myElement', 'margin-top', {duration:500});
3958		marginChange.start(10); //tries to read current margin top value and goes from current to 10
3959		(end)
3960	*/
3961
3962	start: function(from, to){
3963		if (this.timer && this.options.wait) return this;
3964		var parsed = Fx.CSS.parse(this.element, this.property, [from, to]);
3965		this.css = parsed.css;
3966		return this.parent(parsed.from, parsed.to);
3967	},
3968
3969	increase: function(){
3970		this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit, this.property));
3971	}
3972
3973});
3974
3975/*
3976Class: Element
3977	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
3978*/
3979
3980Element.extend({
3981
3982	/*
3983	Property: effect
3984		Applies an <Fx.Style> to the Element; This a shortcut for <Fx.Style>.
3985
3986	Arguments:
3987		property - (string) the css property to alter
3988		options - (object; optional) key/value set of options (see <Fx.Style>)
3989
3990	Example:
3991		>var myEffect = $('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear});
3992		>myEffect.start(10, 100);
3993		>//OR
3994		>$('myElement').effect('height', {duration: 1000, transition: Fx.Transitions.linear}).start(10,100);
3995	*/
3996
3997	effect: function(property, options){
3998		return new Fx.Style(this, property, options);
3999	}
4000
4001});
4002
4003/*
4004Script: Fx.Styles.js
4005	Contains <Fx.Styles>
4006
4007License:
4008	MIT-style license.
4009*/
4010
4011/*
4012Class: Fx.Styles
4013	Allows you to animate multiple css properties at once; Extends <Fx.Base>, inherits all its properties. Includes colors.
4014	Colors must be in hex format.
4015
4016Arguments:
4017	el - the $(element) to apply the styles transition to
4018	options - the fx options (see: <Fx.Base>)
4019
4020Example:
4021	(start code)
4022	var myEffects = new Fx.Styles('myElement', {duration: 1000, transition: Fx.Transitions.linear});
4023
4024	//height from 10 to 100 and width from 900 to 300
4025	myEffects.start({
4026		'height': [10, 100],
4027		'width': [900, 300]
4028	});
4029
4030	//or height from current height to 100 and width from current width to 300
4031	myEffects.start({
4032		'height': 100,
4033		'width': 300
4034	});
4035	(end)
4036*/
4037
4038Fx.Styles = Fx.Base.extend({
4039
4040	initialize: function(el, options){
4041		this.element = $(el);
4042		this.parent(options);
4043	},
4044
4045	setNow: function(){
4046		for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this);
4047	},
4048
4049	set: function(to){
4050		var parsed = {};
4051		this.css = {};
4052		for (var p in to){
4053			this.css[p] = Fx.CSS.select(p, to[p]);
4054			parsed[p] = this.css[p].parse(to[p]);
4055		}
4056		return this.parent(parsed);
4057	},
4058
4059	/*
4060	Property: start
4061		Executes a transition for any number of css properties in tandem.
4062
4063	Arguments:
4064		obj - an object containing keys that specify css properties to alter and values that specify either the from/to values (as an array) or just the end value (an integer).
4065
4066	Example:
4067		see <Fx.Styles>
4068	*/
4069
4070	start: function(obj){
4071		if (this.timer && this.options.wait) return this;
4072		this.now = {};
4073		this.css = {};
4074		var from = {}, to = {};
4075		for (var p in obj){
4076			var parsed = Fx.CSS.parse(this.element, p, obj[p]);
4077			from[p] = parsed.from;
4078			to[p] = parsed.to;
4079			this.css[p] = parsed.css;
4080		}
4081		return this.parent(from, to);
4082	},
4083
4084	increase: function(){
4085		for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit, p));
4086	}
4087
4088});
4089
4090/*
4091Class: Element
4092	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
4093*/
4094
4095Element.extend({
4096
4097	/*
4098	Property: effects
4099		Applies an <Fx.Styles> to the Element; This a shortcut for <Fx.Styles>.
4100
4101	Example:
4102		>var myEffects = $(myElement).effects({duration: 1000, transition: Fx.Transitions.Sine.easeInOut});
4103 		>myEffects.start({'height': [10, 100], 'width': [900, 300]});
4104	*/
4105
4106	effects: function(options){
4107		return new Fx.Styles(this, options);
4108	}
4109
4110});
4111
4112/*
4113Script: Fx.Elements.js
4114	Contains <Fx.Elements>
4115
4116License:
4117	MIT-style license.
4118*/
4119
4120/*
4121Class: Fx.Elements
4122	Fx.Elements allows you to apply any number of styles transitions to a selection of elements. Includes colors (must be in hex format).
4123
4124Arguments:
4125	elements - a collection of elements the effects will be applied to.
4126	options - same as <Fx.Base> options.
4127*/
4128
4129Fx.Elements = Fx.Base.extend({
4130
4131	initialize: function(elements, options){
4132		this.elements = $$(elements);
4133		this.parent(options);
4134	},
4135
4136	setNow: function(){
4137		for (var i in this.from){
4138			var iFrom = this.from[i], iTo = this.to[i], iCss = this.css[i], iNow = this.now[i] = {};
4139			for (var p in iFrom) iNow[p] = iCss[p].getNow(iFrom[p], iTo[p], this);
4140		}
4141	},
4142
4143	set: function(to){
4144		var parsed = {};
4145		this.css = {};
4146		for (var i in to){
4147			var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {};
4148			for (var p in iTo){
4149				iCss[p] = Fx.CSS.select(p, iTo[p]);
4150				iParsed[p] = iCss[p].parse(iTo[p]);
4151			}
4152		}
4153		return this.parent(parsed);
4154	},
4155
4156	/*
4157	Property: start
4158		Applies the passed in style transitions to each object named (see example). Each item in the collection is refered to as a numerical string ("1" for instance). The first item is "0", the second "1", etc.
4159
4160	Example:
4161		(start code)
4162		var myElementsEffects = new Fx.Elements($$('a'));
4163		myElementsEffects.start({
4164			'0': { //let's change the first element's opacity and width
4165				'opacity': [0,1],
4166				'width': [100,200]
4167			},
4168			'4': { //and the fifth one's opacity
4169				'opacity': [0.2, 0.5]
4170			}
4171		});
4172		(end)
4173	*/
4174
4175	start: function(obj){
4176		if (this.timer && this.options.wait) return this;
4177		this.now = {};
4178		this.css = {};
4179		var from = {}, to = {};
4180		for (var i in obj){
4181			var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}, iCss = this.css[i] = {};
4182			for (var p in iProps){
4183				var parsed = Fx.CSS.parse(this.elements[i], p, iProps[p]);
4184				iFrom[p] = parsed.from;
4185				iTo[p] = parsed.to;
4186				iCss[p] = parsed.css;
4187			}
4188		}
4189		return this.parent(from, to);
4190	},
4191
4192	increase: function(){
4193		for (var i in this.now){
4194			var iNow = this.now[i], iCss = this.css[i];
4195			for (var p in iNow) this.elements[i].setStyle(p, iCss[p].getValue(iNow[p], this.options.unit, p));
4196		}
4197	}
4198
4199});
4200
4201/*
4202Script: Fx.Scroll.js
4203	Contains <Fx.Scroll>
4204
4205License:
4206	MIT-style license.
4207*/
4208
4209/*
4210Class: Fx.Scroll
4211	Scroll any element with an overflow, including the window element.
4212
4213Note:
4214	Fx.Scroll requires an XHTML doctype.
4215
4216Arguments:
4217	element - the element to scroll
4218	options - optional, see Options below.
4219
4220Options:
4221	all the Fx.Base options, plus:
4222	offset - the distance for the scrollTo point/element. an Object with x/y properties.
4223	overflown - an array of nested scrolling containers, see <Element.getPosition>
4224*/
4225
4226Fx.Scroll = Fx.Base.extend({
4227
4228	options: {
4229		overflown: [],
4230		offset: {'x': 0, 'y': 0}
4231	},
4232
4233	initialize: function(element, options){
4234		this.now = [];
4235		this.element = $(element);
4236		this.bound = {'stop': this.stop.bind(this, false)};
4237		this.addEvent('onStart', function(){
4238			document.addEvent('mousewheel', this.bound.stop);
4239		}.bind(this));
4240		this.removeEvent('onComplete', function(){
4241			document.removeEvent('mousewheel', this.bound.stop);
4242		}.bind(this));
4243		this.parent(options);
4244	},
4245
4246	setNow: function(){
4247		for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
4248	},
4249
4250	/*
4251	Property: scrollTo
4252		Scrolls the chosen element to the x/y coordinates.
4253
4254	Arguments:
4255		x - the x coordinate to scroll the element to
4256		y - the y coordinate to scroll the element to
4257	*/
4258
4259	scrollTo: function(x, y){
4260		if (this.timer && this.options.wait) return this;
4261		var el = this.element.getSize();
4262		var values = {'x': x, 'y': y};
4263		for (var z in el.size){
4264			var max = el.scrollSize[z] - el.size[z];
4265			if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
4266			else values[z] = el.scroll[z];
4267			values[z] += this.options.offset[z];
4268		}
4269		return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]);
4270	},
4271
4272	/*
4273	Property: toTop
4274		Scrolls the chosen element to its maximum top.
4275	*/
4276
4277	toTop: function(){
4278		return this.scrollTo(false, 0);
4279	},
4280
4281	/*
4282	Property: toBottom
4283		Scrolls the chosen element to its maximum bottom.
4284	*/
4285
4286	toBottom: function(){
4287		return this.scrollTo(false, 'full');
4288	},
4289
4290	/*
4291	Property: toLeft
4292		Scrolls the chosen element to its maximum left.
4293	*/
4294
4295	toLeft: function(){
4296		return this.scrollTo(0, false);
4297	},
4298
4299	/*
4300	Property: toRight
4301		Scrolls the chosen element to its maximum right.
4302	*/
4303
4304	toRight: function(){
4305		return this.scrollTo('full', false);
4306	},
4307
4308	/*
4309	Property: toElement
4310		Scrolls the specified element to the position the passed in element is found.
4311
4312	Arguments:
4313		el - the $(element) to scroll the window to
4314	*/
4315
4316	toElement: function(el){
4317		var parent = this.element.getPosition(this.options.overflown);
4318		var target = $(el).getPosition(this.options.overflown);
4319		return this.scrollTo(target.x - parent.x, target.y - parent.y);
4320	},
4321
4322	increase: function(){
4323		this.element.scrollTo(this.now[0], this.now[1]);
4324	}
4325
4326});
4327
4328/*
4329Script: Fx.Slide.js
4330	Contains <Fx.Slide>
4331
4332License:
4333	MIT-style license.
4334*/
4335
4336/*
4337Class: Fx.Slide
4338	The slide effect; slides an element in horizontally or vertically, the contents will fold inside. Extends <Fx.Base>, inherits all its properties.
4339	
4340Note:
4341	Fx.Slide requires an XHTML doctype.
4342
4343Options:
4344	mode - set it to vertical or horizontal. Defaults to vertical.
4345	options - all the <Fx.Base> options
4346
4347Example:
4348	(start code)
4349	var mySlider = new Fx.Slide('myElement', {duration: 500});
4350	mySlider.toggle() //toggle the slider up and down.
4351	(end)
4352*/
4353
4354Fx.Slide = Fx.Base.extend({
4355
4356	options: {
4357		mode: 'vertical'
4358	},
4359
4360	initialize: function(el, options){
4361		this.element = $(el);
4362		this.wrapper = new Element('div', {'styles': $extend(this.element.getStyles('margin'), {'overflow': 'hidden'})}).injectAfter(this.element).adopt(this.element);
4363		this.element.setStyle('margin', 0);
4364		this.setOptions(options);
4365		this.now = [];
4366		this.parent(this.options);
4367		if (window.webkit419) this.addEvent('onComplete', function(){
4368			this.element.remove().inject(this.wrapper);
4369		});
4370	},
4371
4372	setNow: function(){
4373		for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
4374	},
4375
4376	vertical: function(){
4377		this.margin = 'margin-top';
4378		this.layout = 'height';
4379		this.offset = this.element.offsetHeight;
4380	},
4381
4382	horizontal: function(){
4383		this.margin = 'margin-left';
4384		this.layout = 'width';
4385		this.offset = this.element.offsetWidth;
4386	},
4387
4388	/*
4389	Property: slideIn
4390		Slides the elements in view horizontally or vertically.
4391
4392	Arguments:
4393		mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4394	*/
4395
4396	slideIn: function(mode){
4397		this[mode || this.options.mode]();
4398		return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [0, this.offset]);
4399	},
4400
4401	/*
4402	Property: slideOut
4403		Sides the elements out of view horizontally or vertically.
4404
4405	Arguments:
4406		mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4407	*/
4408
4409	slideOut: function(mode){
4410		this[mode || this.options.mode]();
4411		return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [-this.offset, 0]);
4412	},
4413
4414	/*
4415	Property: hide
4416		Hides the element without a transition.
4417
4418	Arguments:
4419		mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4420	*/
4421
4422	hide: function(mode){
4423		this[mode || this.options.mode]();
4424		return this.set([-this.offset, 0]);
4425	},
4426
4427	/*
4428	Property: show
4429		Shows the element without a transition.
4430
4431	Arguments:
4432		mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4433	*/
4434
4435	show: function(mode){
4436		this[mode || this.options.mode]();
4437		return this.set([0, this.offset]);
4438	},
4439
4440	/*
4441	Property: toggle
4442		Slides in or Out the element, depending on its state
4443
4444	Arguments:
4445		mode - (optional, string) 'horizontal' or 'vertical'; defaults to options.mode.
4446
4447	*/
4448
4449	toggle: function(mode){
4450		if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode);
4451		return this.slideOut(mode);
4452	},
4453
4454	increase: function(){
4455		this.element.setStyle(this.margin, this.now[0] + this.options.unit);
4456		this.wrapper.setStyle(this.layout, this.now[1] + this.options.unit);
4457	}
4458
4459});
4460
4461/*
4462Script: Fx.Transitions.js
4463	Effects transitions, to be used with all the effects.
4464
4465License:
4466	MIT-style license.
4467
4468Credits:
4469	Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified & optimized to be used with mootools.
4470*/
4471
4472/*
4473Class: Fx.Transitions
4474	A collection of tweening transitions for use with the <Fx.Base> classes.
4475
4476Example:
4477	>//Elastic.easeOut with default values:
4478	>new Fx.Style('margin', {transition: Fx.Transitions.Elastic.easeOut});
4479	>//Elastic.easeOut with user-defined value for elasticity.
4480	> var myTransition = new Fx.Transition(Fx.Transitions.Elastic, 3);
4481	>new Fx.Style('margin', {transition: myTransition.easeOut});
4482
4483See also:
4484	http://www.robertpenner.com/easing/
4485*/
4486
4487Fx.Transition = function(transition, params){
4488	params = params || [];
4489	if ($type(params) != 'array') params = [params];
4490	return $extend(transition, {
4491		easeIn: function(pos){
4492			return transition(pos, params);
4493		},
4494		easeOut: function(pos){
4495			return 1 - transition(1 - pos, params);
4496		},
4497		easeInOut: function(pos){
4498			return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
4499		}
4500	});
4501};
4502
4503Fx.Transitions = new Abstract({
4504
4505	/*
4506	Property: linear
4507		displays a linear transition.
4508
4509	Graph:
4510		(see Linear.png)
4511	*/
4512
4513	linear: function(p){
4514		return p;
4515	}
4516
4517});
4518
4519Fx.Transitions.extend = function(transitions){
4520	for (var transition in transitions){
4521		Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
4522		Fx.Transitions.compat(transition);
4523	};
4524};
4525
4526Fx.Transitions.compat = function(transition){
4527	['In', 'Out', 'InOut'].each(function(easeType){
4528		Fx.Transitions[transition.toLowerCase() + easeType] = Fx.Transitions[transition]['ease' + easeType];
4529	});
4530};
4531
4532Fx.Transitions.extend({
4533
4534	/*
4535	Property: Quad
4536		displays a quadratic transition. Must be used as Quad.easeIn or Quad.easeOut or Quad.easeInOut
4537
4538	Graph:
4539		(see Quad.png)
4540	*/
4541
4542	//auto generated
4543
4544	/*
4545	Property: Cubic
4546		displays a cubicular transition. Must be used as Cubic.easeIn or Cubic.easeOut or Cubic.easeInOut
4547
4548	Graph:
4549		(see Cubic.png)
4550	*/
4551
4552	//auto generated
4553
4554	/*
4555	Property: Quart
4556		displays a quartetic transition. Must be used as Quart.easeIn or Quart.easeOut or Quart.easeInOut
4557
4558	Graph:
4559		(see Quart.png)
4560	*/
4561
4562	//auto generated
4563
4564	/*
4565	Property: Quint
4566		displays a quintic transition. Must be used as Quint.easeIn or Quint.easeOut or Quint.easeInOut
4567
4568	Graph:
4569		(see Quint.png)
4570	*/
4571
4572	//auto generated
4573
4574	/*
4575	Property: Pow
4576		Used to generate Quad, Cubic, Quart and Quint.
4577		By default is p^6.
4578
4579	Graph:
4580		(see Pow.png)
4581	*/
4582
4583	Pow: function(p, x){
4584		return Math.pow(p, x[0] || 6);
4585	},
4586
4587	/*
4588	Property: Expo
4589		displays a exponential transition. Must be used as Expo.easeIn or Expo.easeOut or Expo.easeInOut
4590
4591	Graph:
4592		(see Expo.png)
4593	*/
4594
4595	Expo: function(p){
4596		return Math.pow(2, 8 * (p - 1));
4597	},
4598
4599	/*
4600	Property: Circ
4601		displays a circular transition. Must be used as Circ.easeIn or Circ.easeOut or Circ.easeInOut
4602
4603	Graph:
4604		(see Circ.png)
4605	*/
4606
4607	Circ: function(p){
4608		return 1 - Math.sin(Math.acos(p));
4609	},
4610
4611
4612	/*
4613	Property: Sine
4614		displays a sineousidal transition. Must be used as Sine.easeIn or Sine.easeOut or Sine.easeInOut
4615
4616	Graph:
4617		(see Sine.png)
4618	*/
4619
4620	Sine: function(p){
4621		return 1 - Math.sin((1 - p) * Math.PI / 2);
4622	},
4623
4624	/*
4625	Property: Back
4626		makes the transition go back, then all forth. Must be used as Back.easeIn or Back.easeOut or Back.easeInOut
4627
4628	Graph:
4629		(see Back.png)
4630	*/
4631
4632	Back: function(p, x){
4633		x = x[0] || 1.618;
4634		return Math.pow(p, 2) * ((x + 1) * p - x);
4635	},
4636
4637	/*
4638	Property: Bounce
4639		makes the transition bouncy. Must be used as Bounce.easeIn or Bounce.easeOut or Bounce.easeInOut
4640
4641	Graph:
4642		(see Bounce.png)
4643	*/
4644
4645	Bounce: function(p){
4646		var value;
4647		for (var a = 0, b = 1; 1; a += b, b /= 2){
4648			if (p >= (7 - 4 * a) / 11){
4649				value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
4650				break;
4651			}
4652		}
4653		return value;
4654	},
4655
4656	/*
4657	Property: Elastic
4658		Elastic curve. Must be used as Elastic.easeIn or Elastic.easeOut or Elastic.easeInOut
4659
4660	Graph:
4661		(see Elastic.png)
4662	*/
4663
4664	Elastic: function(p, x){
4665		return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
4666	}
4667
4668});
4669
4670['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
4671	Fx.Transitions[transition] = new Fx.Transition(function(p){
4672		return Math.pow(p, [i + 2]);
4673	});
4674	Fx.Transitions.compat(transition);
4675});
4676
4677/*
4678Script: Drag.Base.js
4679	Contains <Drag.Base>, <Element.makeResizable>
4680
4681License:
4682	MIT-style license.
4683*/
4684
4685var Drag = {};
4686
4687/*
4688Class: Drag.Base
4689	Modify two css properties of an element based on the position of the mouse.
4690	
4691Note:
4692	Drag.Base requires an XHTML doctype.
4693
4694Arguments:
4695	el - the $(element) to apply the transformations to.
4696	options - optional. The options object.
4697
4698Options:
4699	handle - the $(element) to act as the handle for the draggable element. defaults to the $(element) itself.
4700	modifiers - an object. see Modifiers Below.
4701	onStart - optional, function to execute when the user starts to drag (on mousedown);
4702	onComplete - optional, function to execute when the user completes the drag.
4703	onDrag - optional, function to execute at every step of the drag
4704	limit - an object, see Limit below.
4705	grid - optional, distance in px for snap-to-grid dragging
4706	snap - optional, the distance you have to drag before the element starts to respond to the drag. defaults to false
4707
4708	modifiers:
4709		x - string, the style you want to modify when the mouse moves in an horizontal direction. defaults to 'left'
4710		y - string, the style you want to modify when the mouse moves in a vertical direction. defaults to 'top'
4711
4712	limit:
4713		x - array with start and end limit relative to modifiers.x
4714		y - array with start and end limit relative to modifiers.y
4715*/
4716
4717Drag.Base = new Class({
4718
4719	options: {
4720		handle: false,
4721		unit: 'px',
4722		onStart: Class.empty,
4723		onBeforeStart: Class.empty,
4724		onComplete: Class.empty,
4725		onSnap: Class.empty,
4726		onDrag: Class.empty,
4727		limit: false,
4728		modifiers: {x: 'left', y: 'top'},
4729		grid: false,
4730		snap: 6
4731	},
4732
4733	initialize: function(el, options){
4734		this.setOptions(options);
4735		this.element = $(el);
4736		this.handle = $(this.options.handle) || this.element;
4737		this.mouse = {'now': {}, 'pos': {}};
4738		this.value = {'start': {}, 'now': {}};
4739		this.bound = {
4740			'start': this.start.bindWithEvent(this),
4741			'check': this.check.bindWithEvent(this),
4742			'drag': this.drag.bindWithEvent(this),
4743			'stop': this.stop.bind(this)
4744		};
4745		this.attach();
4746		if (this.options.initialize) this.options.initialize.call(this);
4747	},
4748
4749	attach: function(){
4750		this.handle.addEvent('mousedown', this.bound.start);
4751		return this;
4752	},
4753
4754	detach: function(){
4755		this.handle.removeEvent('mousedown', this.bound.start);
4756		return this;
4757	},
4758
4759	start: function(event){
4760		this.fireEvent('onBeforeStart', this.element);
4761		this.mouse.start = event.page;
4762		var limit = this.options.limit;
4763		this.limit = {'x': [], 'y': []};
4764		for (var z in this.options.modifiers){
4765			if (!this.options.modifiers[z]) continue;
4766			this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
4767			this.mouse.pos[z] = event.page[z] - this.value.now[z];
4768			if (limit && limit[z]){
4769				for (var i = 0; i < 2; i++){
4770					if ($chk(limit[z][i])) this.limit[z][i] = ($type(limit[z][i]) == 'function') ? limit[z][i]() : limit[z][i];
4771				}
4772			}
4773		}
4774		if ($type(this.options.grid) == 'number') this.options.grid = {'x': this.options.grid, 'y': this.options.grid};
4775		document.addListener('mousemove', this.bound.check);
4776		document.addListener('mouseup', this.bound.stop);
4777		this.fireEvent('onStart', this.element);
4778		event.stop();
4779	},
4780
4781	check: function(event){
4782		var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
4783		if (distance > this.options.snap){
4784			document.removeListener('mousemove', this.bound.check);
4785			document.addListener('mousemove', this.bound.drag);
4786			this.drag(event);
4787			this.fireEvent('onSnap', this.element);
4788		}
4789		event.stop();
4790	},
4791
4792	drag: function(event){
4793		this.out = false;
4794		this.mouse.now = event.page;
4795		for (var z in this.options.modifiers){
4796			if (!this.options.modifiers[z]) continue;
4797			this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
4798			if (this.limit[z]){
4799				if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
4800					this.value.now[z] = this.limit[z][1];
4801					this.out = true;
4802				} else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
4803					this.value.now[z] = this.limit[z][0];
4804					this.out = true;
4805				}
4806			}
4807			if (this.options.grid[z]) this.value.now[z] -= (this.value.now[z] % this.options.grid[z]);
4808			this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
4809		}
4810		this.fireEvent('onDrag', this.element);
4811		event.stop();
4812	},
4813
4814	stop: function(){
4815		document.removeListener('mousemove', this.bound.check);
4816		document.removeListener('mousemove', this.bound.drag);
4817		document.removeListener('mouseup', this.bound.stop);
4818		this.fireEvent('onComplete', this.element);
4819	}
4820
4821});
4822
4823Drag.Base.implement(new Events, new Options);
4824
4825/*
4826Class: Element
4827	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
4828*/
4829
4830Element.extend({
4831
4832	/*
4833	Property: makeResizable
4834		Makes an element resizable (by dragging) with the supplied options.
4835
4836	Arguments:
4837		options - see <Drag.Base> for acceptable options.
4838	*/
4839
4840	makeResizable: function(options){
4841		return new Drag.Base(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
4842	}
4843
4844});
4845
4846/*
4847Script: Drag.Move.js
4848	Contains <Drag.Move>, <Element.makeDraggable>
4849
4850License:
4851	MIT-style license.
4852*/
4853
4854/*
4855Class: Drag.Move
4856	Extends <Drag.Base>, has additional functionality for dragging an element, support snapping and droppables.
4857	Drag.move supports either position absolute or relative. If no position is found, absolute will be set.
4858
4859Note:
4860	Drag.Move requires an XHTML doctype.
4861
4862Arguments:
4863	el - the $(element) to apply the drag to.
4864	options - optional. see Options below.
4865
4866Options:
4867	all the drag.Base options, plus:
4868	container - an element, will fill automatically limiting options based on the $(element) size and position. defaults to false (no limiting)
4869	droppables - an array of elements you can drop your draggable to.
4870	overflown - an array of nested scrolling containers, see Element::getPosition
4871*/
4872
4873Drag.Move = Drag.Base.extend({
4874
4875	options: {
4876		droppables: [],
4877		container: false,
4878		overflown: []
4879	},
4880
4881	initialize: function(el, options){
4882		this.setOptions(options);
4883		this.element = $(el);
4884		this.droppables = $$(this.options.droppables);
4885		this.container = $(this.options.container);
4886		this.position = {'element': this.element.getStyle('position'), 'container': false};
4887		if (this.container) this.position.container = this.container.getStyle('position');
4888		if (!['absolute', 'relative'].contains(this.position.element)) this.position.element = 'absolute';
4889		var top = this.element.getStyle('top').toInt();
4890		var left = this.element.getStyle('left').toInt();
4891		if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
4892			top = $chk(top) ? top : this.element.getTop(this.options.overflown);
4893			left = $chk(left) ? left : this.element.getLeft(this.options.overflown);
4894		} else {
4895			top = $chk(top) ? top : 0;
4896			left = $chk(left) ? left : 0;
4897		}
4898		this.element.setStyles({'top': top, 'left': left, 'position': this.position.element});
4899		this.parent(this.element);
4900	},
4901
4902	start: function(event){
4903		this.overed = null;
4904		if (this.container){
4905			var cont = this.container.getCoordinates();
4906			var el = this.element.getCoordinates();
4907			if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
4908				this.options.limit = {
4909					'x': [cont.left, cont.right - el.width],
4910					'y': [cont.top, cont.bottom - el.height]
4911				};
4912			} else {
4913				this.options.limit = {
4914					'y': [0, cont.height - el.height],
4915					'x': [0, cont.width - el.width]
4916				};
4917			}
4918		}
4919		this.parent(event);
4920	},
4921
4922	drag: function(event){
4923		this.parent(event);
4924		var overed = this.out ? false : this.droppables.filter(this.checkAgainst, this).getLast();
4925		if (this.overed != overed){
4926			if (this.overed) this.overed.fireEvent('leave', [this.element, this]);
4927			this.overed = overed ? overed.fireEvent('over', [this.element, this]) : null;
4928		}
4929		return this;
4930	},
4931
4932	checkAgainst: function(el){
4933		el = el.getCoordinates(this.options.overflown);
4934		var now = this.mouse.now;
4935		return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
4936	},
4937
4938	stop: function(){
4939		if (this.overed && !this.out) this.overed.fireEvent('drop', [this.element, this]);
4940		else this.element.fireEvent('emptydrop', this);
4941		this.parent();
4942		return this;
4943	}
4944
4945});
4946
4947/*
4948Class: Element
4949	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
4950*/
4951
4952Element.extend({
4953
4954	/*
4955	Property: makeDraggable
4956		Makes an element draggable with the supplied options.
4957
4958	Arguments:
4959		options - see <Drag.Move> and <Drag.Base> for acceptable options.
4960	*/
4961
4962	makeDraggable: function(options){
4963		return new Drag.Move(this, options);
4964	}
4965
4966});
4967
4968/*
4969Script: XHR.js
4970	Contains the basic XMLHttpRequest Class Wrapper.
4971
4972License:
4973	MIT-style license.
4974*/
4975
4976/*
4977Class: XHR
4978	Basic XMLHttpRequest Wrapper.
4979
4980Arguments:
4981	options - an object with options names as keys. See options below.
4982
4983Options:
4984	method - 'post' or 'get' - the protocol for the request; optional, defaults to 'post'.
4985	async - boolean: asynchronous option; true uses asynchronous requests. Defaults to true.
4986	onRequest - function to execute when the XHR request is fired.
4987	onSuccess - function to execute when the XHR request completes.
4988	onStateChange - function to execute when the state of the XMLHttpRequest changes.
4989	onFailure - function to execute when the state of the XMLHttpRequest changes.
4990	encoding - the encoding, defaults to utf-8.
4991	autoCancel - cancels the already running request if another one is sent. defaults to false.
4992	headers - accepts an object, that will be set to request headers.
4993
4994Properties:
4995	running - true if the request is running.
4996	response - object, text and xml as keys. You can access this property in the onSuccess event.
4997
4998Example:
4999	>var myXHR = new XHR({method: 'get'}).send('http://site.com/requestHandler.php', 'name=john&lastname=dorian');
5000*/
5001
5002var XHR = new Class({
5003
5004	options: {
5005		method: 'post',
5006		async: true,
5007		onRequest: Class.empty,
5008		onSuccess: Class.empty,
5009		onFailure: Class.empty,
5010		urlEncoded: true,
5011		encoding: 'utf-8',
5012		autoCancel: false,
5013		headers: {}
5014	},
5015	
5016	setTransport: function(){
5017		this.transport = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ie ? new ActiveXObject('Microsoft.XMLHTTP') : false);
5018		return this;
5019	},
5020
5021	initialize: function(options){
5022		this.setTransport().setOptions(options);
5023		this.options.isSuccess = this.options.isSuccess || this.isSuccess;
5024		this.headers = {};
5025		if (this.options.urlEncoded && this.options.method == 'post'){
5026			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
5027			this.setHeader('Content-type', 'application/x-www-form-urlencoded' + encoding);
5028		}
5029		if (this.options.initialize) this.options.initialize.call(this);
5030	},
5031
5032	onStateChange: function(){
5033		if (this.transport.readyState != 4 || !this.running) return;
5034		this.running = false;
5035		var status = 0;
5036		try {status = this.transport.status} catch(e){};
5037		if (this.options.isSuccess.call(this, status)) this.onSuccess();
5038		else this.onFailure();
5039		this.transport.onreadystatechange = Class.empty;
5040	},
5041
5042	isSuccess: function(status){
5043		return ((status >= 200) && (status < 300));
5044	},
5045
5046	onSuccess: function(){
5047		this.response = {
5048			'text': this.transport.responseText,
5049			'xml': this.transport.responseXML
5050		};
5051		this.fireEvent('onSuccess', [this.response.text, this.response.xml]);
5052		this.callChain();
5053	},
5054
5055	onFailure: function(){
5056		this.fireEvent('onFailure', this.transport);
5057	},
5058
5059	/*
5060	Property: setHeader
5061		Add/modify an header for the request. It will not override headers from the options.
5062
5063	Example:
5064		>var myAjax = new Ajax(url, {method: 'get', headers: {'X-Request': 'JSON'}});
5065		>myAjax.setHeader('Last-Modified','Sat, 1 Jan 2005 05:00:00 GMT');
5066	*/
5067
5068	setHeader: function(name, value){
5069		this.headers[name] = value;
5070		return this;
5071	},
5072
5073	/*
5074	Property: send
5075		Opens the XHR connection and sends the data. Data has to be null or a string.
5076
5077	Example:
5078		>var myXhr = new XHR({method: 'post'});
5079		>myXhr.send(url, querystring);
5080		>
5081		>var syncXhr = new XHR({async: false, method: 'post'});
5082		>syncXhr.send(url, null);
5083		>
5084	*/
5085
5086	send: function(url, data){
5087		if (this.options.autoCancel) this.cancel();
5088		else if (this.running) return this;
5089		this.running = true;
5090		if (data && this.options.method == 'get') url = url + (url.contains('?') ? '&' : '?') + data, data = null;
5091		this.transport.open(this.options.method, url, this.options.async);
5092		this.transport.onreadystatechange = this.onStateChange.bind(this);
5093		if ((this.options.method == 'post') && this.transport.overrideMimeType) this.setHeader('Connection', 'close');
5094		$extend(this.headers, this.options.headers);
5095		for (var type in this.headers) try {this.transport.setRequestHeader(type, this.headers[type]);} catch(e){};
5096		this.fireEvent('onRequest');
5097		this.transport.send($pick(data, null));
5098		return this;
5099	},
5100
5101	/*
5102	Property: cancel
5103		Cancels the running request. No effect if the request is not running.
5104
5105	Example:
5106		>var myXhr = new XHR({method: 'get'}).send(url);
5107		>myXhr.cancel();
5108	*/
5109
5110	cancel: function(){
5111		if (!this.running) return this;
5112		this.running = false;
5113		this.transport.abort();
5114		this.transport.onreadystatechange = Class.empty;
5115		this.setTransport();
5116		this.fireEvent('onCancel');
5117		return this;
5118	}
5119
5120});
5121
5122XHR.implement(new Chain, new Events, new Options);
5123
5124/*
5125Script: Ajax.js
5126	Contains the <Ajax> class. Also contains methods to generate querystings from forms and Objects.
5127
5128Credits:
5129	Loosely based on the version from prototype.js <http://prototype.conio.net>
5130
5131License:
5132	MIT-style license.
5133*/
5134
5135/*
5136Class: Ajax
5137	An Ajax class, For all your asynchronous needs. Inherits methods, properties and options from <XH
5137R>.
5138
5139Arguments:
5140	url - the url pointing to the server-side script.
5141	options - optional, an object containing options.
5142
5143Options:
5144	data - you can write parameters here. Can be a querystring, an object or a Form element.
5145	onComplete - function to execute when the ajax request completes.
5146	update - $(element) to insert the response text of the XHR into, upon completion of the request.
5147	evalScripts - boolean; default is false. Execute scripts in the response text onComplete. When the response is javascript the whole response is evaluated.
5148	evalResponse - boolean; default is false. Force global evalulation of the whole response, no matter what content-type it is.
5149
5150Example:
5151	>var myAjax = new Ajax(url, {method: 'get'}).request();
5152*/
5153
5154var Ajax = XHR.extend({
5155
5156	options: {
5157		data: null,
5158		update: null,
5159		onComplete: Class.empty,
5160		evalScripts: false,
5161		evalResponse: false
5162	},
5163
5164	initialize: function(url, options){
5165		this.addEvent('onSuccess', this.onComplete);
5166		this.setOptions(options);
5167		this.options.data = this.options.data || this.options.postBody;
5168		if (!['post', 'get'].contains(this.options.method)){
5169			this._method = '_method=' + this.options.method;
5170			this.options.method = 'post';
5171		}
5172		this.parent();
5173		this.setHeader('X-Requested-With', 'XMLHttpRequest');
5174		this.setHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
5175		this.url = url;
5176	},
5177
5178	onComplete: function(){
5179		if (this.options.update) $(this.options.update).empty().setHTML(this.response.text);
5180		if (this.options.evalScripts || this.options.evalResponse) this.evalScripts();
5181		this.fireEvent('onComplete', [this.response.text, this.response.xml], 20);
5182	},
5183
5184	/*
5185	Property: request
5186		Executes the ajax request.
5187
5188	Example:
5189		>var myAjax = new Ajax(url, {method: 'get'});
5190		>myAjax.request();
5191
5192		OR
5193
5194		>new Ajax(url, {method: 'get'}).request();
5195	*/
5196
5197	request: function(data){
5198		data = data || this.options.data;
5199		switch($type(data)){
5200			case 'element': data = $(data).toQueryString(); break;
5201			case 'object': data = Object.toQueryString(data);
5202		}
5203		if (this._method) data = (data) ? [this._method, data].join('&') : this._method;
5204		return this.send(this.url, data);
5205	},
5206
5207	/*
5208	Property: evalScripts
5209		Executes scripts in the response text
5210	*/
5211
5212	evalScripts: function(){
5213		if (this.options.evalResponse || /(ecma|java)script/.test(this.getHeader('Content-type'))) var scripts = this.response.text;
5214		else {
5215			var script, scripts = [], regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi;
5216			while ((script = regexp.exec(this.response.text))) scripts.push(script[1]);
5217			scripts = scripts.join('\n');
5218		}
5219		if (scripts) (window.execScript) ? window.execScript(scripts) : window.setTimeout(scripts, 0);
5220	},
5221
5222	/*
5223	Property: getHeader
5224		Returns the given response header or null
5225	*/
5226
5227	getHeader: function(name) {
5228		try {return this.transport.getResponseHeader(name);} catch(e){};
5229		return null;
5230	}
5231
5232});
5233
5234/* Section: Object related Functions */
5235
5236/*
5237Function: Object.toQueryString
5238	Generates a querystring from key/pair values in an object
5239
5240Arguments:
5241	source - the object to generate the querystring from.
5242
5243Returns:
5244	the query string.
5245
5246Example:
5247	>Object.toQueryString({apple: "red", lemon: "yellow"}); //returns "apple=red&lemon=yellow"
5248*/
5249
5250Object.toQueryString = function(source){
5251	var queryString = [];
5252	for (var property in source) queryString.push(encodeURIComponent(property) + '=' + encodeURIComponent(source[property]));
5253	return queryString.join('&');
5254};
5255
5256/*
5257Class: Element
5258	Custom class to allow all of its methods to be used with any DOM element via the dollar function <$>.
5259*/
5260
5261Element.extend({
5262
5263	/*
5264	Property: send
5265		Sends a form with an ajax post request
5266
5267	Arguments:
5268		options - option collection for ajax request. See <Ajax> for the options list.
5269
5270	Returns:
5271		The Ajax Class Instance
5272
5273	Example:
5274		(start code)
5275		<form id="myForm" action="submit.php">
5276		<input name="email" value="[email protected]">
5277		<input name="zipCode" value="90210">
5278		</form>
5279		<script>
5280		$('myForm').send()
5281		</script>
5282		(end)
5283	*/
5284
5285	send: function(options){
5286		return new Ajax(this.getProperty('action'), $merge({postBody: this.toQueryString()}, options, {method: 'post'})).request();
5287	}
5288
5289});
5290
5291/*
5292Script: Cookie.js
5293	A cookie reader/creator
5294
5295Credits:
5296	based on the functions by Peter-Paul Koch (http://quirksmode.org)
5297*/
5298
5299/*
5300Class: Cookie
5301	Class for creating, getting, and removing cookies.
5302*/
5303
5304var Cookie = new Abstract({
5305
5306	options: {
5307		domain: false,
5308		path: false,
5309		duration: false,
5310		secure: false
5311	},
5312
5313	/*
5314	Property: set
5315		Sets a cookie in the browser.
5316
5317	Arguments:
5318		key - the key (name) for the cookie
5319		value - the value to set, cannot contain semicolons
5320		options - an object representing the Cookie options. See Options below. Default values are stored in Cookie.options.
5321
5322	Options:
5323		domain - the domain the Cookie belongs to. If you want to share the cookie with pages located on a different domain, you have to set this value. Defaults to the current domain.
5324		path - the path the Cookie belongs to. If you want to share the cookie with pages located in a different path, you have to set this value, for example to "/" to share the cookie with all pages on the domain. Defaults to the current path.
5325		duration - the duration of the Cookie before it expires, in days.
5326					If set to false or 0, the cookie will be a session cookie that expires when the browser is closed. This is default.
5327		secure - Stored cookie information can be accessed only from a secure environment.
5328
5329	Returns:
5330		An object with the options, the key and the value. You can give it as first parameter to Cookie.remove.
5331
5332	Example:
5333		>Cookie.set("username", "Harald", {duration: 1}); //save this for 1 day
5334		>Cookie.set("username", "JackBauer", {duration: false}); //session cookie
5335
5336	*/
5337
5338	set: function(key, value, options){
5339		options = $merge(this.options, options);
5340		value = encodeURIComponent(value);
5341		if (options.domain) value += '; domain=' + options.domain;
5342		if (options.path) value += '; path=' + options.path;
5343		if (options.duration){
5344			var date = new Date();
5345			date.setTime(date.getTime() + options.duration * 24 * 60 * 60 * 1000);
5346			value += '; expires=' + date.toGMTString();
5347		}
5348		if (options.secure) value += '; secure';
5349		document.cookie = key + '=' + value;
5350		return $extend(options, {'key': key, 'value': value});
5351	},
5352
5353	/*
5354	Property: get
5355		Gets the value of a cookie.
5356
5357	Arguments:
5358		key - the name of the cookie you wish to retrieve.
5359
5360	Returns:
5361		The cookie string value, or false if not found.
5362
5363	Example:
5364		>Cookie.get("username") //returns Aaron
5365	*/
5366
5367	get: function(key){
5368		var value = document.cookie.match('(?:^|;)\\s*' + key.escapeRegExp() + '=([^;]*)');
5369		return value ? decodeURIComponent(value[1]) : false;
5370	},
5371
5372	/*
5373	Property: remove
5374		Removes a cookie from the browser.
5375
5376	Arguments:
5377		cookie - the name of the cookie to remove or a previous cookie (for domains)
5378		options - optional. you can also pass the domain and path here. Same as options in <Cookie.set>
5379
5380	Examples:
5381		>Cookie.remove("username") //bye-bye Aaron
5382		>var myCookie = Cookie.set('user', 'jackbauer', {domain: 'mootools.net'});
5383		>Cookie.remove(myCookie);
5384	*/
5385
5386	remove: function(cookie, options){
5387		if ($type(cookie) == 'object') this.set(cookie.key, '', $merge(cookie, {duration: -1}));
5388		else this.set(cookie, '', $merge(options, {duration: -1}));
5389	}
5390
5391});
5392
5393/*
5394Script: Json.js
5395	Simple Json parser and Stringyfier, See: <http://www.json.org/>
5396
5397License:
5398	MIT-style license.
5399*/
5400
5401/*
5402Class: Json
5403	Simple Json parser and Stringyfier, See: <http://www.json.org/>
5404*/
5405
5406var Json = {
5407
5408	/*
5409	Property: toString
5410		Converts an object to a string, to be passed in server-side scripts as a parameter. Although its not normal usage for this class, this method can also be used to convert functions and arrays to strings.
5411
5412	Arguments:
5413		obj - the object to convert to string
5414
5415	Returns:
5416		A json string
5417
5418	Example:
5419		(start code)
5420		Json.toString({apple: 'red', lemon: 'yellow'}); '{"apple":"red","lemon":"yellow"}'
5421		(end)
5422	*/
5423
5424	toString: function(obj){
5425		switch($type(obj)){
5426			case 'string':
5427				return '"' + obj.replace(/(["\\])/g, '\\$1') + '"';
5428			case 'array':
5429				return '[' + obj.map(Json.toString).join(',') + ']';
5430			case 'object':
5431				var string = [];
5432				for (var property in obj) string.push(Json.toString(property) + ':' + Json.toString(obj[property]));
5433				return '{' + string.join(',') + '}';
5434		}
5435		return String(obj);
5436	},
5437
5438	/*
5439	Property: evaluate
5440		converts a json string to an javascript Object.
5441
5442	Arguments:
5443		str - the string to evaluate. if its not a string, it returns false.
5444		secure - optionally, performs syntax check on json string. Defaults to false.
5445
5446	Credits:
5447		Json test regexp is by Douglas Crockford <http://crockford.org>.
5448
5449	Example:
5450		>var myObject = Json.evaluate('{"apple":"red","lemon":"yellow"}');
5451		>//myObject will become {apple: 'red', lemon: 'yellow'}
5452	*/
5453
5454	evaluate: function(str, secure){
5455		return (($type(str) != 'string') || (secure && !str.test(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/))) ? false : eval('(' + str + ')');
5456	}
5457
5458};
5459
5460/*
5461Script: Json.Remote.js
5462	Contains <Json.Remote>.
5463
5464License:
5465	MIT-style license.
5466*/
5467
5468/*
5469Class: Json.Remote
5470	Wrapped XHR with automated sending and receiving of Javascript Objects in Json Format.
5471
5472Arguments:
5473	url - the url you want to send your object to.
5474	options - see <XHR> options
5475
5476Example:
5477	this code will send user information based on name/last name
5478	(start code)
5479	var jSonRequest = new Json.Remote("http://site.com/tellMeAge.php", {onComplete: function(person){
5480		alert(person.age); //is 25 years
5481		alert(person.height); //is 170 cm
5482		alert(person.weight); //is 120 kg
5483	}}).send({'name': 'John', 'lastName': 'Doe'});
5484	(end)
5485*/
5486
5487Json.Remote = XHR.extend({
5488
5489	initialize: function(url, options){
5490		this.url = url;
5491		this.addEvent('onSuccess', this.onComplete);
5492		this.parent(options);
5493		this.setHeader('X-Request', 'JSON');
5494	},
5495
5496	send: function(obj){
5497		return this.parent(this.url, 'json=' + Json.toString(obj));
5498	},
5499
5500	onComplete: function(){
5501		this.fireEvent('onComplete', Json.evaluate(this.response.text, this.options.secure));
5502	}
5503
5504});
5505
5506/*
5507Script: Assets.js
5508	provides dynamic loading for images, css and javascript files.
5509
5510License:
5511	MIT-style license.
5512*/
5513
5514var Asset = new Abstract({
5515
5516	/*
5517	Property: javascript
5518		Injects a javascript file in the page.
5519
5520	Arguments:
5521		source - the path of the javascript file
5522		properties - some additional attributes you might want to add to the script element
5523
5524	Example:
5525		>
5525 new Asset.javascript('/scripts/myScript.js', {id: 'myScript'});
5526	*/
5527
5528	javascript: function(source, properties){
5529		properties = $merge({
5530			'onload': Class.empty
5531		}, properties);
5532		var script = new Element('script', {'src': source}).addEvents({
5533			'load': properties.onload,
5534			'readystatechange': function(){
5535				if (this.readyState == 'complete') this.fireEvent('load');
5536			}
5537		});
5538		delete properties.onload;
5539		return script.setProperties(properties).inject(document.head);
5540	},
5541
5542	/*
5543	Property: css
5544		Injects a css file in the page.
5545
5546	Arguments:
5547		source - the path of the css file
5548		properties - some additional attributes you might want to add to the link element
5549
5550	Example:
5551		> new Asset.css('/css/myStyle.css', {id: 'myStyle', title: 'myStyle'});
5552	*/
5553
5554	css: function(source, properties){
5555		return new Element('link', $merge({
5556			'rel': 'stylesheet', 'media': 'screen', 'type': 'text/css', 'href': source
5557		}, properties)).inject(document.head);
5558	},
5559
5560	/*
5561	Property: image
5562		Preloads an image and returns the img element. does not inject it to the page.
5563
5564	Arguments:
5565		source - the path of the image file
5566		properties - some additional attributes you might want to add to the img element
5567
5568	Example:
5569		> new Asset.image('/images/myImage.png', {id: 'myImage', title: 'myImage', onload: myFunction});
5570
5571	Returns:
5572		the img element. you can inject it anywhere you want with <Element.injectInside>/<Element.injectAfter>/<Element.injectBefore>
5573	*/
5574
5575	image: function(source, properties){
5576		properties = $merge({
5577			'onload': Class.empty,
5578			'onabort': Class.empty,
5579			'onerror': Class.empty
5580		}, properties);
5581		var image = new Image();
5582		image.src = source;
5583		var element = new Element('img', {'src': source});
5584		['load', 'abort', 'error'].each(function(type){
5585			var event = properties['on' + type];
5586			delete properties['on' + type];
5587			element.addEvent(type, function(){
5588				this.removeEvent(type, arguments.callee);
5589				event.call(this);
5590			});
5591		});
5592		if (image.width && image.height) element.fireEvent('load', element, 1);
5593		return element.setProperties(properties);
5594	},
5595
5596	/*
5597	Property: images
5598		Preloads an array of images (as strings) and returns an array of img elements. does not inject them to the page.
5599
5600	Arguments:
5601		sources - array, the paths of the image files
5602		options - object, see below
5603
5604	Options:
5605		onComplete - a function to execute when all image files are loaded in the browser's cache
5606		onProgress - a function to execute when one image file is loaded in the browser's cache
5607
5608	Example:
5609		(start code)
5610		new Asset.images(['/images/myImage.png', '/images/myImage2.gif'], {
5611			onComplete: function(){
5612				alert('all images loaded!');
5613			}
5614		});
5615		(end)
5616
5617	Returns:
5618		the img elements as $$. you can inject them anywhere you want with <Element.injectInside>/<Element.injectAfter>/<Element.injectBefore>
5619	*/
5620
5621	images: function(sources, options){
5622		options = $merge({
5623			onComplete: Class.empty,
5624			onProgress: Class.empty
5625		}, options);
5626		if (!sources.push) sources = [sources];
5627		var images = [];
5628		var counter = 0;
5629		sources.each(function(source){
5630			var img = new Asset.image(source, {
5631				'onload': function(){
5632					options.onProgress.call(this, counter);
5633					counter++;
5634					if (counter == sources.length) options.onComplete();
5635				}
5636			});
5637			images.push(img);
5638		});
5639		return new Elements(images);
5640	}
5641
5642});
5643
5644/*
5645Script: Hash.js
5646	Contains the class Hash.
5647
5648License:
5649	MIT-style license.
5650*/
5651
5652/*
5653Class: Hash
5654	It wraps an object that it uses internally as a map. The user must use set(), get(), and remove() to add/change, retrieve and remove values, it must not access the internal object directly. null/undefined values are allowed.
5655
5656Note:
5657	Each hash instance has the length property.
5658
5659Arguments:
5660	obj - an object to convert into a Hash instance.
5661
5662Example:
5663	(start code)
5664	var hash = new Hash({a: 'hi', b: 'world', c: 'howdy'});
5665	hash.remove('b'); // b is removed.
5666	hash.set('c', 'hello');
5667	hash.get('c'); // returns 'hello'
5668	hash.length // returns 2 (a and c)
5669	(end)
5670*/
5671
5672var Hash = new Class({
5673
5674	length: 0,
5675
5676	initialize: function(object){
5677		this.obj = object || {};
5678		this.setLength();
5679	},
5680
5681	/*
5682	Property: get
5683		Retrieves a value from the hash.
5684
5685	Arguments:
5686		key - The key
5687
5688	Returns:
5689		The value
5690	*/
5691
5692	get: function(key){
5693		return (this.hasKey(key)) ? this.obj[key] : null;
5694	},
5695
5696	/*
5697	Property: hasKey
5698		Check the presence of a specified key-value pair in the hash.
5699
5700	Arguments:
5701		key - The key
5702
5703	Returns:
5704		True if the Hash contains a value for the specified key, otherwise false
5705	*/
5706
5707	hasKey: function(key){
5708		return (key in this.obj);
5709	},
5710
5711	/*
5712	Property: set
5713		Adds a key-value pair to the hash or replaces a previous value associated with the key.
5714
5715	Arguments:
5716		key - The key
5717		value - The value
5718	*/
5719
5720	set: function(key, value){
5721		if (!this.hasKey(key)) this.length++;
5722		this.obj[key] = value;
5723		return this;
5724	},
5725
5726	setLength: function(){
5727		this.length = 0;
5728		for (var p in this.obj) this.length++;
5729		return this;
5730	},
5731
5732	/*
5733	Property: remove
5734		Removes a key-value pair from the hash.
5735
5736	Arguments:
5737		key - The key
5738	*/
5739
5740	remove: function(key){
5741		if (!this.hasKey(key)) return this;
5742		delete this.obj[key];
5743		this.length--;
5744		return this;
5745	},
5746
5747	/*
5748	Property: each
5749		Calls a function for each key-value pair. The first argument passed to the function will be the value, the second one will be the key, like $each.
5750
5751	Arguments:
5752		fn - The function to call for each key-value pair
5753		bind - Optional, the object that will be referred to as "this" in the function
5754	*/
5755
5756	each: function(fn, bind){
5757		$each(this.obj, fn, bind);
5758	},
5759
5760	/*
5761	Property: extend
5762		Extends the current hash with an object containing key-value pairs. Values for duplicate keys will be replaced by the new ones.
5763
5764	Arguments:
5765		obj - An object containing key-value pairs
5766	*/
5767
5768	extend: function(obj){
5769		$extend(this.obj, obj);
5770		return this.setLength();
5771	},
5772
5773	/*
5774	Property: merge
5775		Merges the current hash with multiple objects.
5776	*/
5777
5778	merge: function(){
5779		this.obj = $merge.apply(null, [this.obj].extend(arguments));
5780		return this.setLength();
5781	},
5782
5783	/*
5784	Property: empty
5785		Empties all hash values properties and values.
5786	*/
5787
5788	empty: function(){
5789		this.obj = {};
5790		this.length = 0;
5791		return this;
5792	},
5793
5794	/*
5795	Property: keys
5796		Returns an array containing all the keys, in the same order as the values returned by <Hash.values>.
5797
5798	Returns:
5799		An array containing all the keys of the hash
5800	*/
5801
5802	keys: function(){
5803		var keys = [];
5804		for (var property in this.obj) keys.push(property);
5805		return keys;
5806	},
5807
5808	/*
5809	Property: values
5810		Returns an array containing all the values, in the same order as the keys returned by <Hash.keys>.
5811
5812	Returns:
5813		An array containing all the values of the hash
5814	*/
5815
5816	values: function(){
5817		var values = [];
5818		for (var property in this.obj) values.push(this.obj[property]);
5819		return values;
5820	}
5821
5822});
5823
5824/* Section: Utility Functions */
5825
5826/*
5827Function: $H
5828	Shortcut to create a Hash from an Object.
5829*/
5830
5831function $H(obj){
5832	return new Hash(obj);
5833};
5834
5835/*
5836Script: Hash.Cookie.js
5837	Stores and loads an Hash as a cookie using Json format.
5838*/
5839
5840/*
5841Class: Hash.Cookie
5842	Inherits all the methods from <Hash>, additional methods are save and load.
5843	Hash json string has a limit of 4kb (4096byte), so be careful with your Hash size.
5844	Creating a new instance automatically loads the data from the Cookie into the Hash.
5845	If the Hash is emptied, the cookie is also removed.
5846
5847Arguments:
5848	name - the key (name) for the cookie
5849	options - options are identical to <Cookie> and are simply passed along to it.
5850		In addition, it has the autoSave option, to save the cookie at every operation. defaults to true.
5851
5852Example:
5853	(start code)
5854	var fruits = new Hash.Cookie('myCookieName', {duration: 3600});
5855	fruits.extend({
5856		'lemon': 'yellow',
5857		'apple': 'red'
5858	});
5859	fruits.set('melon', 'green');
5860	fruits.get('lemon'); // yellow
5861
5862	// ... on another page ... values load automatically
5863
5864	var fruits = new Hash.Cookie('myCookieName', {duration: 365});
5865	fruits.get('melon'); // green
5866
5867	fruits.erase(); // delete cookie
5868	(end)
5869*/
5870
5871Hash.Cookie = Hash.extend({
5872
5873	initialize: function(name, options){
5874		this.name = name;
5875		this.options = $extend({'autoSave': true}, options || {});
5876		this.load();
5877	},
5878
5879	/*
5880	Property: save
5881		Saves the Hash to the cookie. If the hash is empty, removes the cookie.
5882
5883	Returns:
5884		Returns false when the JSON string cookie is too long (4kb), otherwise true.
5885
5886	Example:
5887		(start code)
5888		var login = new Hash.Cookie('userstatus', {autoSave: false});
5889
5890		login.extend({
5891			'username': 'John',
5892			'credentials': [4, 7, 9]
5893		});
5894		login.set('last_message', 'User logged in!');
5895
5896		login.save(); // finally save the Hash
5897		(end)
5898	*/
5899
5900	save: function(){
5901		if (this.length == 0){
5902			Cookie.remove(this.name, this.options);
5903			return true;
5904		}
5905		var str = Json.toString(this.obj);
5906		if (str.length > 4096) return false; //cookie would be truncated!
5907		Cookie.set(this.name, str, this.options);
5908		return true;
5909	},
5910	
5911	/*
5912	Property: load
5913		Loads the cookie and assigns it to the Hash.
5914	*/
5915
5916	load: function(){
5917		this.obj = Json.evaluate(Cookie.get(this.name), true) || {};
5918		this.setLength();
5919	}
5920
5921});
5922
5923Hash.Cookie.Methods = {};
5924['extend', 'set', 'merge', 'empty', 'remove'].each(function(method){
5925	Hash.Cookie.Methods[method] = function(){
5926		Hash.prototype[method].apply(this, arguments);
5927		if (this.options.autoSave) this.save();
5928		return this;
5929	};
5930});
5931Hash.Cookie.implement(Hash.Cookie.Methods);
5932
5933/*
5934Script: Color.js
5935	Contains the Color class.
5936
5937License:
5938	MIT-style license.
5939*/
5940
5941/*
5942Class: Color
5943	Creates a new Color Object, which is an array with some color specific methods.
5944Arguments:
5945	color - the hex, the RGB array or the HSB array of the color to create. For HSB colors, you need to specify the second argument.
5946	type - a string representing the type of the color to create. needs to be specified if you intend to create the color with HSB values, or an array of HEX values. Can be 'rgb', 'hsb' or 'hex'.
5947
5948Example:
5949	(start code)
5950	var black = new Color('#000');
5951	var purple = new Color([255,0,255]);
5952	// mix black with white and purple, each time at 10% of the new color
5953	var darkpurple = black.mix('#fff', purple, 10);
5954	$('myDiv').setStyle('background-color', darkpurple);
5955	(end)
5956*/
5957
5958var Color = new Class({
5959
5960	initialize: function(color, type){
5961		type = type || (color.push ? 'rgb' : 'hex');
5962		var rgb, hsb;
5963		switch(type){
5964			case 'rgb':
5965				rgb = color;
5966				hsb = rgb.rgbToHsb();
5967				break;
5968			case 'hsb':
5969				rgb = color.hsbToRgb();
5970				hsb = color;
5971				break;
5972			default:
5973				rgb = color.hexToRgb(true);
5974				hsb = rgb.rgbToHsb();
5975		}
5976		rgb.hsb = hsb;
5977		rgb.hex = rgb.rgbToHex();
5978		return $extend(rgb, Color.prototype);
5979	},
5980
5981	/*
5982	Property: mix
5983		Mixes two or more colors with the Color.
5984		
5985	Arguments:
5986		color - a color to mix. you can use as arguments how many colors as you want to mix with the original one.
5987		alpha - if you use a number as the last argument, it will be threated as the amount of the color to mix.
5988	*/
5989
5990	mix: function(){
5991		var colors = $A(arguments);
5992		var alpha = ($type(colors[colors.length - 1]) == 'number') ? colors.pop() : 50;
5993		var rgb = this.copy();
5994		colors.each(function(color){
5995			color = new Color(color);
5996			for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
5997		});
5998		return new Color(rgb, 'rgb');
5999	},
6000
6001	/*
6002	Property: invert
6003		Inverts the Color.
6004	*/
6005
6006	invert: function(){
6007		return new Color(this.map(function(value){
6008			return 255 - value;
6009		}));
6010	},
6011
6012	/*
6013	Property: setHue
6014		Modifies the hue of the Color, and returns a new one.
6015	
6016	Arguments:
6017		value - the hue to set
6018	*/
6019
6020	setHue: function(value){
6021		return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
6022	},
6023
6024	/*
6025	Property: setSaturation
6026		Changes the saturation of the Color, and returns a new one.
6027	
6028	Arguments:
6029		percent - the percentage of the saturation to set
6030	*/
6031
6032	setSaturation: function(percent){
6033		return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
6034	},
6035
6036	/*
6037	Property: setBrightness
6038		Changes the brightness of the Color, and returns a new one.
6039	
6040	Arguments:
6041		percent - the percentage of the brightness to set
6042	*/
6043
6044	setBrightness: function(percent){
6045		return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
6046	}
6047
6048});
6049
6050/* Section: Utility Functions */
6051
6052/*
6053Function: $RGB
6054	Shortcut to create a new color, based on red, green, blue values.
6055
6056Arguments:
6057	r - (integer) red value (0-255)
6058	g - (integer) green value (0-255)
6059	b - (integer) blue value (0-255)
6060
6061*/
6062
6063function $RGB(r, g, b){
6064	return new Color([r, g, b], 'rgb');
6065};
6066
6067/*
6068Function: $HSB
6069	Shortcut to create a new color, based on hue, saturation, brightness values.
6070
6071Arguments:
6072	h - (integer) hue value (0-100)
6073	s - (integer) saturation value (0-100)
6074	b - (integer) brightness value (0-100)
6075*/
6076
6077function $HSB(h, s, b){
6078	return new Color([h, s, b], 'hsb');
6079};
6080
6081/*
6082Class: Array
6083	A collection of The Array Object prototype methods.
6084*/
6085
6086Array.extend({
6087	
6088	/*
6089	Property: rgbToHsb
6090		Converts a RGB array to an HSB array.
6091
6092	Returns:
6093		the HSB array.
6094	*/
6095
6096	rgbToHsb: function(){
6097		var red = this[0], green = this[1], blue = this[2];
6098		var hue, saturation, brightness;
6099		var max = Math.max(red, green, blue), min = Math.min(red, green, blue);
6100		var delta = max - min;
6101		brightness = max / 255;
6102		saturation = (max != 0) ? delta / max : 0;
6103		if (saturation == 0){
6104			hue = 0;
6105		} else {
6106			var rr = (max - red) / delta;
6107			var gr = (max - green) / delta;
6108			var br = (max - blue) / delta;
6109			if (red == max) hue = br - gr;
6110			else if (green == max) hue = 2 + rr - br;
6111			else hue = 4 + gr - rr;
6112			hue /= 6;
6113			if (hue < 0) hue++;
6114		}
6115		return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
6116	},
6117
6118	/*
6119	Property: hsbToRgb
6120		Converts an HSB array to an RGB array.
6121
6122	Returns:
6123		the RGB array.
6124	*/
6125
6126	hsbToRgb: function(){
6127		var br = Math.round(this[2] / 100 * 255);
6128		if (this[1] == 0){
6129			return [br, br, br];
6130		} else {
6131			var hue = this[0] % 360;
6132			var f = hue % 60;
6133			var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
6134			var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
6135			var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
6136			switch(Math.floor(hue / 60)){
6137				case 0: return [br, t, p];
6138				case 1: return [q, br, p];
6139				case 2: return [p, br, t];
6140				case 3: return [p, q, br];
6141				case 4: return [t, p, br];
6142				case 5: return [br, p, q];
6143			}
6144		}
6145		return false;
6146	}
6147
6148});
6149
6150/*
6151Script: Scroller.js
6152	Contains the <Scroller>.
6153
6154License:
6155	MIT-style license.
6156*/
6157
6158/*
6159Class: Scroller
6160	The Scroller is a class to scroll any element with an overflow (including the window) when the mouse 
6160cursor reaches certain buondaries of that element.
6161	You must call its start method to start listening to mouse movements.
6162	
6163Note:
6164	The Scroller requires an XHTML doctype.
6165
6166Arguments:
6167	element - required, the element to scroll.
6168	options - optional, see options below, and <Fx.Base> options.
6169
6170Options:
6171	area - integer, the necessary boundaries to make the element scroll.
6172	velocity - integer, velocity ratio, the modifier for the window scrolling speed.
6173	onChange - optionally, when the mouse reaches some boundaries, you can choose to alter some other values, instead of the scrolling offsets.
6174		Automatically passes as parameters x and y values.
6175*/
6176
6177var Scroller = new Class({
6178
6179	options: {
6180		area: 20,
6181		velocity: 1,
6182		onChange: function(x, y){
6183			this.element.scrollTo(x, y);
6184		}
6185	},
6186
6187	initialize: function(element, options){
6188		this.setOptions(options);
6189		this.element = $(element);
6190		this.mousemover = ([window, document].contains(element)) ? $(document.body) : this.element;
6191	},
6192
6193	/*
6194	Property: start
6195		The scroller starts listening to mouse movements.
6196	*/
6197
6198	start: function(){
6199		this.coord = this.getCoords.bindWithEvent(this);
6200		this.mousemover.addListener('mousemove', this.coord);
6201	},
6202
6203	/*
6204	Property: stop
6205		The scroller stops listening to mouse movements.
6206	*/
6207
6208	stop: function(){
6209		this.mousemover.removeListener('mousemove', this.coord);
6210		this.timer = $clear(this.timer);
6211	},
6212
6213	getCoords: function(event){
6214		this.page = (this.element == window) ? event.client : event.page;
6215		if (!this.timer) this.timer = this.scroll.periodical(50, this);
6216	},
6217
6218	scroll: function(){
6219		var el = this.element.getSize();
6220		var pos = this.element.getPosition();
6221
6222		var change = {'x': 0, 'y': 0};
6223		for (var z in this.page){
6224			if (this.page[z] < (this.options.area + pos[z]) && el.scroll[z] != 0)
6225				change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity;
6226			else if (this.page[z] + this.options.area > (el.size[z] + pos[z]) && el.scroll[z] + el.size[z] != el.scrollSize[z])
6227				change[z] = (this.page[z] - el.size[z] + this.options.area - pos[z]) * this.options.velocity;
6228		}
6229		if (change.y || change.x) this.fireEvent('onChange', [el.scroll.x + change.x, el.scroll.y + change.y]);
6230	}
6231
6232});
6233
6234Scroller.implement(new Events, new Options);
6235
6236/*
6237Script: Slider.js
6238	Contains <Slider>
6239
6240License:
6241	MIT-style license.
6242*/
6243
6244/*
6245Class: Slider
6246	Creates a slider with two elements: a knob and a container. Returns the values.
6247	
6248Note:
6249	The Slider requires an XHTML doctype.
6250
6251Arguments:
6252	element - the knob container
6253	knob - the handle
6254	options - see Options below
6255
6256Options:
6257	onChange - a function to fire when the value changes.
6258	onComplete - a function to fire when you're done dragging.
6259	onTick - optionally, you can alter the onTick behavior, for example displaying an effect of the knob moving to the desired position.
6260		Passes as parameter the new position.
6261	steps - the number of steps for your slider.
6262	mode - either 'horizontal' or 'vertical'. defaults to horizontal.
6263	offset - relative offset for knob position. default to 0.
6264*/
6265
6266var Slider = new Class({
6267
6268	options: {
6269		onChange: Class.empty,
6270		onComplete: Class.empty,
6271		onTick: function(pos){
6272			this.knob.setStyle(this.p, pos);
6273		},
6274		mode: 'horizontal',
6275		steps: 100,
6276		offset: 0
6277	},
6278
6279	initialize: function(el, knob, options){
6280		this.element = $(el);
6281		this.knob = $(knob);
6282		this.setOptions(options);
6283		this.previousChange = -1;
6284		this.previousEnd = -1;
6285		this.step = -1;
6286		this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
6287		var mod, offset;
6288		switch(this.options.mode){
6289			case 'horizontal':
6290				this.z = 'x';
6291				this.p = 'left';
6292				mod = {'x': 'left', 'y': false};
6293				offset = 'offsetWidth';
6294				break;
6295			case 'vertical':
6296				this.z = 'y';
6297				this.p = 'top';
6298				mod = {'x': false, 'y': 'top'};
6299				offset = 'offsetHeight';
6300		}
6301		this.max = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
6302		this.half = this.knob[offset]/2;
6303		this.getPos = this.element['get' + this.p.capitalize()].bind(this.element);
6304		this.knob.setStyle('position', 'relative').setStyle(this.p, - this.options.offset);
6305		var lim = {};
6306		lim[this.z] = [- this.options.offset, this.max - this.options.offset];
6307		this.drag = new Drag.Base(this.knob, {
6308			limit: lim,
6309			modifiers: mod,
6310			snap: 0,
6311			onStart: function(){
6312				this.draggedKnob();
6313			}.bind(this),
6314			onDrag: function(){
6315				this.draggedKnob();
6316			}.bind(this),
6317			onComplete: function(){
6318				this.draggedKnob();
6319				this.end();
6320			}.bind(this)
6321		});
6322		if (this.options.initialize) this.options.initialize.call(this);
6323	},
6324
6325	/*
6326	Property: set
6327		The slider will get the step you pass.
6328
6329	Arguments:
6330		step - one integer
6331	*/
6332
6333	set: function(step){
6334		this.step = step.limit(0, this.options.steps);
6335		this.checkStep();
6336		this.end();
6337		this.fireEvent('onTick', this.toPosition(this.step));
6338		return this;
6339	},
6340
6341	clickedElement: function(event){
6342		var position = event.page[this.z] - this.getPos() - this.half;
6343		position = position.limit(-this.options.offset, this.max -this.options.offset);
6344		this.step = this.toStep(position);
6345		this.checkStep();
6346		this.end();
6347		this.fireEvent('onTick', position);
6348	},
6349
6350	draggedKnob: function(){
6351		this.step = this.toStep(this.drag.value.now[this.z]);
6352		this.checkStep();
6353	},
6354
6355	checkStep: function(){
6356		if (this.previousChange != this.step){
6357			this.previousChange = this.step;
6358			this.fireEvent('onChange', this.step);
6359		}
6360	},
6361
6362	end: function(){
6363		if (this.previousEnd !== this.step){
6364			this.previousEnd = this.step;
6365			this.fireEvent('onComplete', this.step + '');
6366		}
6367	},
6368
6369	toStep: function(position){
6370		return Math.round((position + this.options.offset) / this.max * this.options.steps);
6371	},
6372
6373	toPosition: function(step){
6374		return this.max * step / this.options.steps;
6375	}
6376
6377});
6378
6379Slider.implement(new Events);
6380Slider.implement(new Options);
6381
6382/*
6383Script: SmoothScroll.js
6384	Contains <SmoothScroll>
6385
6386License:
6387	MIT-style license.
6388*/
6389
6390/*
6391Class: SmoothScroll
6392	Auto targets all the anchors in a page and display a smooth scrolling effect upon clicking them.
6393
6394Note:
6395	SmoothScroll requires an XHTML doctype.
6396
6397Arguments:
6398	options - the Fx.Scroll options (see: <Fx.Scroll>) plus links, a collection of elements you want your smoothscroll on. Defaults to document.links.
6399
6400Example:
6401	>new SmoothScroll();
6402*/
6403
6404var SmoothScroll = Fx.Scroll.extend({
6405
6406	initialize: function(options){
6407		this.parent(window, options);
6408		this.links = (this.options.links) ? $$(this.options.links) : $$(document.links);
6409		var location = window.location.href.match(/^[^#]*/)[0] + '#';
6410		this.links.each(function(link){
6411			if (link.href.indexOf(location) != 0) return;
6412			var anchor = link.href.substr(location.length);
6413			if (anchor && $(anchor)) this.useLink(link, anchor);
6414		}, this);
6415		if (!window.webkit419) this.addEvent('onComplete', function(){
6416			window.location.hash = this.anchor;
6417		});
6418	},
6419
6420	useLink: function(link, anchor){
6421		link.addEvent('click', function(event){
6422			this.anchor = anchor;
6423			this.toElement(anchor);
6424			event.stop();
6425		}.bindWithEvent(this));
6426	}
6427
6428});
6429
6430/*
6431Script: Sortables.js
6432	Contains <Sortables> Class.
6433
6434License:
6435	MIT-style license.
6436*/
6437
6438/*
6439Class: Sortables
6440	Creates an interface for <Drag.Base> and drop, resorting of a list.
6441	
6442Note:
6443	The Sortables require an XHTML doctype.
6444
6445Arguments:
6446	list - required, the list that will become sortable.
6447	options - an Object, see options below.
6448
6449Options:
6450	handles - a collection of elements to be used for drag handles. defaults to the elements.
6451	onStart - function executed when the item starts dragging
6452	onComplete - function executed when the item ends dragging
6453*/
6454
6455var Sortables = new Class({
6456
6457	options: {
6458		handles: false,
6459		onStart: Class.empty,
6460		onComplete: Class.empty,
6461		ghost: true,
6462		snap: 3,
6463		onDragStart: function(element, ghost){
6464			ghost.setStyle('opacity', 0.7);
6465			element.setStyle('opacity', 0.7);
6466		},
6467		onDragComplete: function(element, ghost){
6468			element.setStyle('opacity', 1);
6469			ghost.remove();
6470			this.trash.remove();
6471		}
6472	},
6473
6474	initialize: function(list, options){
6475		this.setOptions(options);
6476		this.list = $(list);
6477		this.elements = this.list.getChildren();
6478		this.handles = (this.options.handles) ? $$(this.options.handles) : this.elements;
6479		this.bound = {
6480			'start': [],
6481			'moveGhost': this.moveGhost.bindWithEvent(this)
6482		};
6483		for (var i = 0, l = this.handles.length; i < l; i++){
6484			this.bound.start[i] = this.start.bindWithEvent(this, this.elements[i]);
6485		}
6486		this.attach();
6487		if (this.options.initialize) this.options.initialize.call(this);
6488		this.bound.move = this.move.bindWithEvent(this);
6489		this.bound.end = this.end.bind(this);
6490	},
6491	
6492	attach: function(){
6493		this.handles.each(function(handle, i){
6494			handle.addEvent('mousedown', this.bound.start[i]);
6495		}, this);
6496	},
6497
6498	detach: function(){
6499		this.handles.each(function(handle, i){
6500			handle.removeEvent('mousedown', this.bound.start[i]);
6501		}, this);
6502	},
6503
6504	start: function(event, el){
6505		this.active = el;
6506		this.coordinates = this.list.getCoordinates();
6507		if (this.options.ghost){
6508			var position = el.getPosition();
6509			this.offset = event.page.y - position.y;
6510			this.trash = new Element('div').inject(document.body);
6511			this.ghost = el.clone().inject(this.trash).setStyles({
6512				'position': 'absolute',
6513				'left': position.x,
6514				'top': event.page.y - this.offset
6515			});
6516			document.addListener('mousemove', this.bound.moveGhost);
6517			this.fireEvent('onDragStart', [el, this.ghost]);
6518		}
6519		document.addListener('mousemove', this.bound.move);
6520		document.addListener('mouseup', this.bound.end);
6521		this.fireEvent('onStart', el);
6522		event.stop();
6523	},
6524	
6525	moveGhost: function(event){
6526		var value = event.page.y - this.offset;
6527		value = value.limit(this.coordinates.top, this.coordinates.bottom - this.ghost.offsetHeight);
6528		this.ghost.setStyle('top', value);
6529		event.stop();
6530	},
6531
6532	move: function(event){
6533		this.active.active = true;
6534		this.previous = this.previous || event.page.y;
6535		this.now = event.page.y;
6536		var direction = ((this.previous - this.now) <= 0) ? 'down' : 'up';
6537		var prev = this.active.getPrevious();
6538		var next = this.active.getNext();
6539		if (prev && direction == 'up'){
6540			var prevPos = prev.getCoordinates();
6541			if (event.page.y < prevPos.bottom) this.active.injectBefore(prev);
6542		}
6543		if (next && direction == 'down'){
6544			var nextPos = next.getCoordinates();
6545			if (event.page.y > nextPos.top) this.active.injectAfter(next);
6546		}
6547		this.previous = event.page.y;
6548	},
6549
6550	serialize: function(){
6551		var serial = [];
6552		this.list.getChildren().each(function(el, i){
6553			serial[i] = this.elements.indexOf(el);
6554		}, this);
6555		return serial;
6556	},
6557
6558	end: function(){
6559		this.previous = null;
6560		document.removeListener('mousemove', this.bound.move);
6561		document.removeListener('mouseup', this.bound.end);
6562		if (this.options.ghost){
6563			document.removeListener('mousemove', this.bound.moveGhost);
6564			this.fireEvent('onDragComplete', [this.active, this.ghost]);
6565		}
6566		this.fireEvent('onComplete', this.active);
6567	}
6568
6569});
6570
6571Sortables.implement(new Events, new Options);
6572
6573/*
6574Script: Tips.js
6575	Tooltips, BubbleTips, whatever they are, they will appear on mouseover
6576
6577License:
6578	MIT-style license.
6579
6580Credits:
6581	The idea behind Tips.js is based on Bubble Tooltips (<http://web-graphics.com/mtarchive/001717.php>) by Alessandro Fulcitiniti <http://web-graphics.com>
6582*/
6583
6584/*
6585Class: Tips
6586	Display a tip on any element with a title and/or href.
6587
6588Note:
6589	Tips requires an XHTML doctype.
6590
6591Arguments:
6592	elements - a collection of elements to apply the tooltips to on mouseover.
6593	options - an object. See options Below.
6594
6595Options:
6596	maxTitleChars - the maximum number of characters to display in the title of the tip. defaults to 30.
6597
6598	onShow - optionally you can alter the default onShow behaviour with this option (like displaying a fade in effect);
6599	onHide - optionally you can alter the default onHide behaviour with this option (like displaying a fade out effect);
6600
6601	showDelay - the delay the onShow method is called. (defaults to 100 ms)
6602	hideDelay - the delay the onHide method is called. (defaults to 100 ms)
6603
6604	className - the prefix for your tooltip classNames. defaults to 'tool'.
6605
6606		the whole tooltip will have as classname: tool-tip
6607
6608		the title will have as classname: tool-title
6609
6610		the text will have as classname: tool-text
6611
6612	offsets - the distance of your tooltip from the mouse. an Object with x/y properties.
6613	fixed - if set to true, the toolTip will not follow the mouse.
6614
6615Example:
6616	(start code)
6617	<img src="/images/i.png" title="The body of the tooltip is stored in the title" class="toolTipImg"/>
6618	<script>
6619		var myTips = new Tips($$('.toolTipImg'), {
6620			maxTitleChars: 50	//I like my captions a little long
6621		});
6622	</script>
6623	(end)
6624
6625Note:
6626	The title of the element will always be used as the tooltip body. If you put :: on your title, the text before :: will become the tooltip title.
6627*/
6628
6629var Tips = new Class({
6630
6631	options: {
6632		onShow: function(tip){
6633			tip.setStyle('visibility', 'visible');
6634		},
6635		onHide: function(tip){
6636			tip.setStyle('visibility', 'hidden');
6637		},
6638		maxTitleChars: 30,
6639		showDelay: 100,
6640		hideDelay: 100,
6641		className: 'tool',
6642		offsets: {'x': 16, 'y': 16},
6643		fixed: false
6644	},
6645
6646	initialize: function(elements, options){
6647		this.setOptions(options);
6648		this.toolTip = new Element('div', {
6649			'class': this.options.className + '-tip',
6650			'styles': {
6651				'position': 'absolute',
6652				'top': '0',
6653				'left': '0',
6654				'visibility': 'hidden'
6655			}
6656		}).inject(document.body);
6657		this.wrapper = new Element('div').inject(this.toolTip);
6658		$$(elements).each(this.build, this);
6659		if (this.options.initialize) this.options.initialize.call(this);
6660	},
6661
6662	build: function(el){
6663		el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
6664		if (el.title){
6665			var dual = el.title.split('::');
6666			if (dual.length > 1) {
6667				el.$tmp.myTitle = dual[0].trim();
6668				el.$tmp.myText = dual[1].trim();
6669			} else {
6670				el.$tmp.myText = el.title;
6671			}
6672			el.removeAttribute('title');
6673		} else {
6674			el.$tmp.myText = false;
6675		}
6676		if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";
6677		el.addEvent('mouseenter', function(event){
6678			this.start(el);
6679			if (!this.options.fixed) this.locate(event);
6680			else this.position(el);
6681		}.bind(this));
6682		if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this));
6683		var end = this.end.bind(this);
6684		el.addEvent('mouseleave', end);
6685		el.addEvent('trash', end);
6686	},
6687
6688	start: function(el){
6689		this.wrapper.empty();
6690		if (el.$tmp.myTitle){
6691			this.title = new Element('span').inject(
6692				new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)
6693			).setHTML(el.$tmp.myTitle);
6694		}
6695		if (el.$tmp.myText){
6696			this.text = new Element('span').inject(
6697				new Element('div', {'class': this.options.className + '-text'}).inject(this.wrapper)
6698			).setHTML(el.$tmp.myText);
6699		}
6700		$clear(this.timer);
6701		this.timer = this.show.delay(this.options.showDelay, this);
6702	},
6703
6704	end: function(event){
6705		$clear(this.timer);
6706		this.timer = this.hide.delay(this.options.hideDelay, this);
6707	},
6708
6709	position: function(element){
6710		var pos = element.getPosition();
6711		this.toolTip.setStyles({
6712			'left': pos.x + this.options.offsets.x,
6713			'top': pos.y + this.options.offsets.y
6714		});
6715	},
6716
6717	locate: function(event){
6718		var win = {'x': window.getWidth(), 'y': window.getHeight()};
6719		var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
6720		var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
6721		var prop = {'x': 'left', 'y': 'top'};
6722		for (var z in prop){
6723			var pos = event.page[z] + this.options.offsets[z];
6724			if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
6725			this.toolTip.setStyle(prop[z], pos);
6726		};
6727	},
6728
6729	show: function(){
6730		if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this);
6731		this.fireEvent('onShow', [this.toolTip]);
6732	},
6733
6734	hide: function(){
6735		this.fireEvent('onHide', [this.toolTip]);
6736	}
6737
6738});
6739
6740Tips.implement(new Events, new Options);
6741
6742/*
6743Script: Group.js
6744	For Grouping Classes or Elements Events. The Event added to the Group will fire when all of the events of the items of the group are fired.
6745
6746License:
6747	MIT-style license.
6748*/
6749
6750/*
6751Class: Group
6752	An "Utility" Class.
6753
6754Arguments:
6755	List of Class instances
6756
6757Example:
6758	(start code)
6759	xhr1 = new Ajax('data.js', {evalScript: true});
6760	xhr2 = new Ajax('abstraction.js', {evalScript: true});
6761	xhr3 = new Ajax('template.js', {evalScript: true});
6762
6763	var group = new Group(xhr1, xhr2, xhr3);
6764	group.addEvent('onComplete', function(){
6765		alert('All Scripts loaded');
6766	});
6767
6768	xhr1.request();
6769	xhr2.request();
6770	xhr3.request();
6771	(end)
6772
6773*/
6774
6775var Group = new Class({
6776
6777	initialize: function(){
6778		this.instances = $A(arguments);
6779		this.events = {};
6780		this.checker = {};
6781	},
6782
6783	/*
6784	Property: addEvent
6785		adds an event to the stack of events of the Class instances.
6786
6787	Arguments:
6788		type - string; the event name (e.g. 'onComplete')
6789		fn - function to execute when all instances fired this event
6790	*/
6791
6792	addEvent: function(type, fn){
6793		this.checker[type] = this.checker[type] || {};
6794		this.events[type] = this.events[type] || [];
6795		if (this.events[type].contains(fn)) return false;
6796		else this.events[type].push(fn);
6797		this.instances.each(function(instance, i){
6798			instance.addEvent(type, this.check.bind(this, [type, instance, i]));
6799		}, this);
6800		return this;
6801	},
6802
6803	check: function(type, instance, i){
6804		this.checker[type][i] = true;
6805		var every = this.instances.every(function(current, j){
6806			return this.checker[type][j] || false;
6807		}, this);
6808		if (!every) return;
6809		this.instances.each(function(current, j){
6810			this.checker[type][j] = false;
6811		}, this);
6812		this.events[type].each(function(event){
6813			event.call(this, this.instances, instance);
6814		}, this);
6815	}
6816
6817});
6818
6819/*
6820Script: Accordion.js
6821	Contains <Accordion>
6822
6823License:
6824	MIT-style license.
6825*/
6826
6827/*
6828Class: Accordion
6829	The Accordion class creates a group of elements that are toggled when their handles are clicked. When one elements toggles in, the others toggles back.
6830	
6831Note:
6832	The Accordion requires an XHTML doctype.
6833
6834Arguments:
6835	togglers - required, a collection of elements, the elements handlers that will be clickable.
6836	elements - required, a collection of elements the transitions will be applied to.
6837	options - optional, see options below, and <Fx.Base> options.
6838
6839Options:
6840	show - integer, the Index of the element to show at start.
6841	display - integer, the Index of the element to show at start (with a transition). defaults to 0.
6842	fixedHeight - integer, if you want the elements to have a fixed height. defaults to false.
6843	fixedWidth - integer, if you want the elements to have a fixed width. defaults to false.
6844	onActive - function to execute when an element starts to show
6845	onBackground - function to execute when an element starts to hide
6846	height - boolean, will add a height transition to the accordion if true. defaults to true.
6847	opacity - boolean, will add an opacity transition to the accordion if true. defaults to true.
6848	width - boolean, will add a width transition to the accordion if true. defaults to false, css mastery is required to make this work!
6849	alwaysHide - boolean, will allow to hide all elements if true, instead of always keeping one element shown. defaults to false.
6850*/
6851
6852var Accordion = Fx.Elements.extend({
6853
6854	options: {
6855		onActive: Class.empty,
6856		onBackground: Class.empty,
6857		display: 0,
6858		show: false,
6859		height: true,
6860		width: false,
6861		opacity: true,
6862		fixedHeight: false,
6863		fixedWidth: false,
6864		wait: false,
6865		alwaysHide: false
6866	},
6867
6868	initialize: function(){
6869		var options, togglers, elements, container;
6870		$each(arguments, function(argument, i){
6871			switch($type(argument)){
6872				case 'object': options = argument; break;
6873				case 'element': container = $(argument); break;
6874				default:
6875					var temp = $$(argument);
6876					if (!togglers) togglers = temp;
6877					else elements = temp;
6878			}
6879		});
6880		this.togglers = togglers || [];
6881		this.elements = elements || [];
6882		this.container = $(container);
6883		this.setOptions(options);
6884		this.previous = -1;
6885		if (this.options.alwaysHide) this.options.wait = true;
6886		if ($chk(this.options.show)){
6887			this.options.display = false;
6888			this.previous = this.options.show;
6889		}
6890		if (this.options.start){
6891			this.options.display = false;
6892			this.options.show = false;
6893		}
6894		this.effects = {};
6895		if (this.options.opacity) this.effects.opacity = 'fullOpacity';
6896		if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
6897		if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
6898		for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);
6899		this.elements.each(function(el, i){
6900			if (this.options.show === i) this.fireEvent('onActive', [this.togglers[i], el]);
6901			else for (var fx in this.effects) el.setStyle(fx, 0);
6902		}, this);
6903		this.parent(this.elements);
6904		if ($chk(this.options.display)) this.display(this.options.display);
6905	},
6906
6907	addSection: function(toggler, element, pos){
6908		toggler = $(toggler);
6909		element = $(element);
6910		var test = this.togglers.contains(toggler);
6911		var len = this.togglers.length;
6912		this.togglers.include(toggler);
6913		this.elements.include(element);
6914		if (len && (!test || pos)){
6915			pos = $pick(pos, len - 1);
6916			toggler.injectBefore(this.togglers[pos]);
6917			element.injectAfter(toggler);
6918		} else if (this.container && !test){
6919			toggler.inject(this.container);
6920			element.inject(this.container);
6921		}
6922		var idx = this.togglers.indexOf(toggler);
6923		toggler.addEvent('click', this.display.bind(this, idx));
6924		if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
6925		if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
6926		element.fullOpacity = 1;
6927		if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
6928		if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
6929		element.setStyle('overflow', 'hidden');
6930		if (!test) for (var fx in this.effects) element.setStyle(fx, 0);
6931		return this;
6932	},
6933
6934	/*
6935	Property: display
6936		Shows a specific section and hides all others. Useful when triggering an accordion from outside.
6937
6938	Arguments:
6939		index - integer, the index of the item to show, or the actual element to show.
6940	*/
6941
6942	display: function(index){
6943		index = ($type(index) == 'element') ? this.elements.indexOf(index) : index;
6944		if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
6945		this.previous = index;
6946		var obj = {};
6947		this.elements.each(function(el, i){
6948			obj[i] = {};
6949			if ((i != index) || (this.options.alwaysHide && (el.offsetHeight > 0))){
6950				this.fireEvent('onBackground', [this.togglers[i], el]);
6951				for (var fx in this.effects) obj[i][fx] = 0;
6952			} else {
6953				this.fireEvent('onActive', [this.togglers[i], el]);
6954				for (var fx in this.effects) obj[i][fx] = el[this.effects[fx]];
6955			}
6956		}, this);
6957		return this.start(obj);
6958	},
6959
6960	showThisHideOpen: function(index){return this.display(index)}
6961
6962});
6963
6964Fx.Accordion = Accordion;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.