PageSourceSearch

https://www.roncq.fr/media/system/js/mootools.js

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