PageSourceSearch

https://lotro-europe.com/js/mootools-core.js

js lotro-europe.com collected 2026-10-02 07:48:04 UTC 96,542 bytes, 3,816 lines download raw bytes

1/*
2Script: Core.js
3	MooTools - My Object Oriented JavaScript Tools.
4
5License:
6	MIT-style license.
7
8Copyright:
9	Copyright (c) 2006-2007 [Valerio Proietti](http://mad4milk.net/).
10
11Code & Documentation:
12	[The MooTools production team](http://mootools.net/developers/).
13
14Inspiration:
15	- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
16	- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
17*/
18
19var MooTools = {
20	'version': '1.2.0',
21	'build': ''
22};
23      
24var Native = function(options){
25	options = options || {};
26
27	var afterImplement = options.afterImplement || function(){};
28	var generics = options.generics;
29	generics = (generics !== false);
30	var legacy = options.legacy;
31	var initialize = options.initialize;
32	var protect = options.protect;
33	var name = options.name;
34
35	var object = initialize || legacy;
36
37	object.constructor = Native;
38	object.$family = {name: 'native'};
39	if (legacy && initialize) object.prototype = legacy.prototype;
40	object.prototype.constructor = object;
41
42	if (name){
43		var family = name.toLowerCase();
44		object.prototype.$family = {name: family};
45		Native.typize(object, family);
46	}
47
48	var add = function(obj, name, method, force){
49		if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
50		if (generics) Native.genericize(obj, name, protect);
51		afterImplement.call(obj, name, method);
52		return obj;
53	};
54	
55	object.implement = function(a1, a2, a3){
56		if (typeof a1 == 'string') return add(this, a1, a2, a3);
57		for (var p in a1) add(this, p, a1[p], a2);
58		return this;
59	};
60	
61	object.alias = function(a1, a2, a3){
62		if (typeof a1 == 'string'){
63			a1 = this.prototype[a1];
64			if (a1) add(this, a2, a1, a3);
65		} else {
66			for (var a in a1) this.alias(a, a1[a], a2);
67		}
68		return this;
69	};
70
71	return object;
72};
73
74Native.implement = function(objects, properties){
75	for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
76};
77
78Native.genericize = function(object, property, check){
79	if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
80		var args = Array.prototype.slice.call(arguments);
81		return object.prototype[property].apply(args.shift(), args);
82	};
83};
84
85Native.typize = function(object, family){
86	if (!object.type) object.type = function(item){
87		return ($type(item) === family);
88	};
89};
90
91Native.alias = function(objects, a1, a2, a3){
92	for (var i = 0, j = objects.length; i < j; i++) objects[i].alias(a1, a2, a3);
93};
94
95(function(objects){
96	for (var name in objects) Native.typize(objects[name], name);
97})({'boolean': Boolean, 'native': Native, 'object': Object});
98
99(function(objects){
100	for (var name in objects) new Native({name: name, initialize: objects[name], protect: true});
101})({'String': String, 'Function': Function, 'Number': Number, 'Array': Array, 'RegExp': RegExp, 'Date': Date});
102
103(function(object, methods){
104	for (var i = methods.length; i--; i) Native.genericize(object, methods[i], true);
105	return arguments.callee;
106})
107(Array, ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 'toString', 'valueOf', 'indexOf', 'lastIndexOf'])
108(String, ['charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'replace', 'search', 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase', 'valueOf']);
109
110function $chk(obj){
111	return !!(obj || obj === 0);
112};
113
114function $clear(timer){
115	clearTimeout(timer);
116	clearInterval(timer);
117	return null;
118};
119
120function $defined(obj){
121	return (obj != undefined);
122};
123
124function $empty(){};
125
126function $arguments(i){
127	return function(){
128		return arguments[i];
129	};
130};
131
132function $lambda(value){
133	return (typeof value == 'function') ? value : function(){
134		return value;
135	};
136};
137
138function $extend(original, extended){
139	for (var key in (extended || {})) original[key] = extended[key];
140	return original;
141};
142
143function $unlink(object){
144	var unlinked;
145	
146	switch ($type(object)){
147		case 'object':
148			unlinked = {};
149			for (var p in object) unlinked[p] = $unlink(object[p]);
150		break;
151		case 'hash':
152			unlinked = $unlink(object.getClean());
153		break;
154		case 'array':
155			unlinked = [];
156			for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
157		break;
158		default: return object;
159	}
160	
161	return unlinked;
162};
163
164function $merge(){
165	var mix = {};
166	for (var i = 0, l = arguments.length; i < l; i++){
167		var object = arguments[i];
168		if ($type(object) != 'object') continue;
169		for (var key in object){
170			var op = object[key], mp = mix[key];
171			mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $merge(mp, op) : $unlink(op);
172		}
173	}
174	return mix;
175};
176
177function $pick(){
178	for (var i = 0, l = arguments.length; i < l; i++){
179		if (arguments[i] != undefined) return arguments[i];
180	}
181	return null;
182};
183
184function $random(min, max){
185	return Math.floor(Math.random() * (max - min + 1) + min);
186};
187
188function $splat(obj){
189	var type = $type(obj);
190	return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
191};
192
193var $time = Date.now || function(){
194	return new Date().getTime();
195};
196
197function $try(){
198	for (var i = 0, l = arguments.length; i < l; i++){
199		try {
200			return arguments[i]();
201		} catch(e){}
202	}
203	return null;
204};
205
206function $type(obj){
207	if (obj == undefined) return false;
208	if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
209	if (obj.nodeName){
210		switch (obj.nodeType){
211			case 1: return 'element';
212			case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
213		}
214	} else if (typeof obj.length == 'number'){
215		if (obj.callee) return 'arguments';
216		else if (obj.item) return 'collection';
217	}
218	return typeof obj;
219};
220
221var Hash = new Native({
222
223	name: 'Hash',
224
225	initialize: function(object){
226		if ($type(object) == 'hash') object = $unlink(object.getClean());
227		for (var key in object) this[key] = object[key];
228		return this;
229	}
230
231});
232
233Hash.implement({
234	
235	getLength: function(){
236		var length = 0;
237		for (var key in this){
238			if (this.hasOwnProperty(key)) length++;
239		}
240		return length;
241	},
242
243	forEach: function(fn, bind){
244		for (var key in this){
245			if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
246		}
247	},
248	
249	getClean: function(){
250		var clean = {};
251		for (var key in this){
252			if (this.hasOwnProperty(key)) clean[key] = this[key];
253		}
254		return clean;
255	}
256
257});
258
259Hash.alias('forEach', 'each');
260
261function $H(object){
262	return new Hash(object);
263};
264
265Array.implement({
266
267	forEach: function(fn, bind){
268		for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
269	}
270
271});
272
273Array.alias('forEach', 'each');
274
275function $A(iterable){
276	if (iterable.item){
277		var array = [];
278		for (var i = 0, l = iterable.length; i < l; i++) array[i] = iterable[i];
279		return array;
280	}
281	return Array.prototype.slice.call(iterable);
282};
283
284function $each(iterable, fn, bind){
285	var type = $type(iterable);
286	((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
287};
288
289
290/*
291Script: Browser.js
292	The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
293
294License:
295	MIT-style license.
296*/
297
298var Browser = new Hash({
299	Engine: {name: 'unknown', version: ''},
300	Platform: {name: (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
301	Features: {xpath: !!(document.evaluate), air: !!(window.runtime)},
302	Plugins: {}
303});
304
305if (window.opera) Browser.Engine = {name: 'presto', version: (document.getElementsByClassName) ? 950 : 925};
306else if (window.ActiveXObject) Browser.Engine = {name: 'trident', version: (window.XMLHttpRequest) ? 5 : 4};
307else if (!navigator.taintEnabled) Browser.Engine = {name: 'webkit', version: (Browser.Features.xpath) ? 420 : 419};
308else if (document.getBoxObjectFor != null) Browser.Engine = {name: 'gecko', version: (document.getElementsByClassName) ? 19 : 18};
309Browser.Engine[Browser.Engine.name] = Browser.Engine[Browser.Engine.name + Browser.Engine.version] = true;
310
311if (window.orientation != undefined) Browser.Platform.name = 'ipod';
312
313Browser.Platform[Browser.Platform.name] = true;
314
315Browser.Request = function(){
316	return $try(function(){
317		return new XMLHttpRequest();
318	}, function(){
319		return new ActiveXObject('MSXML2.XMLHTTP');
320	});
321};
322
323Browser.Features.xhr = !!(Browser.Request());
324
325Browser.Plugins.Flash = (function(){
326	var version = ($try(function(){
327		return navigator.plugins['Shockwave Flash'].description;
328	}, function(){
329		return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
330	}) || '0 r0').match(/\d+/g);
331	return {version: parseInt(version[0] || 0 + '.' + version[1] || 0), build: parseInt(version[2] || 0)};
332})();
333
334function $exec(text){
335	if (!text) return text;
336	if (window.execScript){
337		window.execScript(text);
338	} else {
339		var script = document.createElement('script');
340		script.setAttribute('type', 'text/javascript');
341		script.text = text;
342		document.head.appendChild(script);
343		document.head.removeChild(script);
344	}
345	return text;
346};
347
348Native.UID = 1;
349
350var $uid = (Browser.Engine.trident) ? function(item){
351	return (item.uid || (item.uid = [Native.UID++]))[0];
352} : function(item){
353	return item.uid || (item.uid = Native.UID++);
354};
355
356var Window = new Native({
357
358	name: 'Window',
359
360	legacy: (Browser.Engine.trident) ? null: window.Window,
361
362	initialize: function(win){
363		$uid(win);
364		if (!win.Element){
365			win.Element = $empty;
366			if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2
367			win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {};
368		}
369		return $extend(win, Window.Prototype);
370	},
371
372	afterImplement: function(property, value){
373		window[property] = Window.Prototype[property] = value;
374	}
375
376});
377
378Window.Prototype = {$family: {name: 'window'}};
379
380new Window(window);
381
382var Document = new Native({
383
384	name: 'Document',
385
386	legacy: (Browser.Engine.trident) ? null: window.Document,
387
388	initialize: function(doc){
389		$uid(doc);
390		doc.head = doc.getElementsByTagName('head')[0];
391		doc.html = doc.getElementsByTagName('html')[0];
392		doc.window = doc.defaultView || doc.parentWindow;
393		if (Browser.Engine.trident4) $try(function(){
394			doc.execCommand("BackgroundImageCache", false, true);
395		});
396		return $extend(doc, Document.Prototype);
397	},
398
399	afterImplement: function(property, value){
400		document[property] = Document.Prototype[property] = value;
401	}
402
403});
404
405Document.Prototype = {$family: {name: 'document'}};
406
407new Document(document);
408
409/*
410Script: Array.js
411	Contains Array Prototypes like copy, each, contains, and remove.
412
413License:
414	MIT-style license.
415*/
416
417Array.implement({
418
419	every: function(fn, bind){
420		for (var i = 0, l = this.length; i < l; i++){
421			if (!fn.call(bind, this[i], i, this)) return false;
422		}
423		return true;
424	},
425
426	filter: function(fn, bind){
427		var results = [];
428		for (var i = 0, l = this.length; i < l; i++){
429			if (fn.call(bind, this[i], i, this)) results.push(this[i]);
430		}
431		return results;
432	},
433	
434	clean: function() {
435		return this.filter($defined);
436	},
437
438	indexOf: function(item, from){
439		var len = this.length;
440		for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
441			if (this[i] === item) return i;
442		}
443		return -1;
444	},
445
446	map: function(fn, bind){
447		var results = [];
448		for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
449		return results;
450	},
451
452	some: function(fn, bind){
453		for (var i = 0, l = this.length; i < l; i++){
454			if (fn.call(bind, this[i], i, this)) return true;
455		}
456		return false;
457	},
458
459	associate: function(keys){
460		var obj = {}, length = Math.min(this.length, keys.length);
461		for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
462		return obj;
463	},
464
465	link: function(object){
466		var result = {};
467		for (var i = 0, l = this.length; i < l; i++){
468			for (var key in object){
469				if (object[key](this[i])){
470					result[key] = this[i];
471					delete object[key];
472					break;
473				}
474			}
475		}
476		return result;
477	},
478
479	contains: function(item, from){
480		return this.indexOf(item, from) != -1;
481	},
482
483	extend: function(array){
484		for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
485		return this;
486	},
487
488	getLast: function(){
489		return (this.length) ? this[this.length - 1] : null;
490	},
491
492	getRandom: function(){
493		return (this.length) ? this[$random(0, this.length - 1)] : null;
494	},
495
496	include: function(item){
497		if (!this.contains(item)) this.push(item);
498		return this;
499	},
500
501	combine: function(array){
502		for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
503		return this;
504	},
505
506	erase: function(item){
507		for (var i = this.length; i--; i){
508			if (this[i] === item) this.splice(i, 1);
509		}
510		return this;
511	},
512
513	empty: function(){
514		this.length = 0;
515		return this;
516	},
517
518	flatten: function(){
519		var array = [];
520		for (var i = 0, l = this.length; i < l; i++){
521			var type = $type(this[i]);
522			if (!type) continue;
523			array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]);
524		}
525		return array;
526	},
527
528	hexToRgb: function(array){
529		if (this.length != 3) return null;
530		var rgb = this.map(function(value){
531			if (value.length == 1) value += value;
532			return value.toInt(16);
533		});
534		return (array) ? rgb : 'rgb(' + rgb + ')';
535	},
536
537	rgbToHex: function(array){
538		if (this.length < 3) return null;
539		if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
540		var hex = [];
541		for (var i = 0; i < 3; i++){
542			var bit = (this[i] - 0).toString(16);
543			hex.push((bit.length == 1) ? '0' + bit : bit);
544		}
545		return (array) ? hex : '#' + hex.join('');
546	}
547
548});
549
550/*
551Script: Function.js
552	Contains Function Prototypes like create, bind, pass, and delay.
553
554License:
555	MIT-style license.
556*/
557
558Function.implement({
559
560	extend: function(properties){
561		for (var property in properties) this[property] = properties[property];
562		return this;
563	},
564
565	create: function(options){
566		var self = this;
567		options = options || {};
568		return function(event){
569			var args = options.arguments;
570			args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
571			if (options.event) args = [event || window.event].extend(args);
572			var returns = function(){
573				return self.apply(options.bind || null, args);
574			};
575			if (options.delay) return setTimeout(returns, options.delay);
576			if (options.periodical) return setInterval(returns, options.periodical);
577			if (options.attempt) return $try(returns);
578			return returns();
579		};
580	},
581
582	pass: function(args, bind){
583		return this.create({arguments: args, bind: bind});
584	},
585
586	attempt: function(args, bind){
587		return this.create({arguments: args, bind: bind, attempt: true})();
588	},
589
590	bind: function(bind, args){
591		return this.create({bind: bind, arguments: args});
592	},
593
594	bindWithEvent: function(bind, args){
595		return this.create({bind: bind, event: true, arguments: args});
596	},
597
598	delay: function(delay, bind, args){
599		return this.create({delay: delay, bind: bind, arguments: args})();
600	},
601
602	periodical: function(interval, bind, args){
603		return this.create({periodical: interval, bind: bind, arguments: args})();
604	},
605
606	run: function(args, bind){
607		return this.apply(bind, $splat(args));
608	}
609
610});
611
612/*
613Script: Number.js
614	Contains Number Prototypes like limit, round, times, and ceil.
615
616License:
617	MIT-style license.
618*/
619
620Number.implement({
621
622	limit: function(min, max){
623		return Math.min(max, Math.max(min, this));
624	},
625
626	round: function(precision){
627		precision = Math.pow(10, precision || 0);
628		return Math.round(this * precision) / precision;
629	},
630
631	times: function(fn, bind){
632		for (var i = 0; i < this; i++) fn.call(bind, i, this);
633	},
634
635	toFloat: function(){
636		return parseFloat(this);
637	},
638
639	toInt: function(base){
640		return parseInt(this, base || 10);
641	}
642
643});
644
645Number.alias('times', 'each');
646
647(function(math){
648	var methods = {};
649	math.each(function(name){
650		if (!Number[name]) methods[name] = function(){
651			return Math[name].apply(null, [this].concat($A(arguments)));
652		};
653	});
654	Number.implement(methods);
655})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
656
657/*
658Script: String.js
659	Contains String Prototypes like camelCase, capitalize, test, and toInt.
660
661License:
662	MIT-style license.
663*/
664
665String.implement({
666
667	test: function(regex, params){
668		return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
669	},
670
671	contains: function(string, separator){
672		return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
673	},
674
675	trim: function(){
676		return this.replace(/^\s+|\s+$/g, '');
677	},
678
679	clean: function(){
680		return this.replace(/\s+/g, ' ').trim();
681	},
682
683	camelCase: function(){
684		return this.replace(/-\D/g, function(match){
685			return match.charAt(1).toUpperCase();
686		});
687	},
688
689	hyphenate: function(){
690		return this.replace(/[A-Z]/g, function(match){
691			return ('-' + match.charAt(0).toLowerCase());
692		});
693	},
694
695	capitalize: function(){
696		return this.replace(/\b[a-z]/g, function(match){
697			return match.toUpperCase();
698		});
699	},
700
701	escapeRegExp: function(){
702		return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
703	},
704
705	toInt: function(base){
706		return parseInt(this, base || 10);
707	},
708
709	toFloat: function(){
710		return parseFloat(this);
711	},
712
713	hexToRgb: function(array){
714		var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
715		return (hex) ? hex.slice(1).hexToRgb(array) : null;
716	},
717
718	rgbToHex: function(array){
719		var rgb = this.match(/\d{1,3}/g);
720		return (rgb) ? rgb.rgbToHex(array) : null;
721	},
722
723	stripScripts: function(option){
724		var scripts = '';
725		var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
726			scripts += arguments[1] + '\n';
727			return '';
728		});
729		if (option === true) $exec(scripts);
730		else if ($type(option) == 'function') option(scripts, text);
731		return text;
732	},
733
734	substitute: function(object, regexp){
735		return this.replace(regexp || (/\\?\{([^}]+)\}/g), function(match, name){
736			if (match.charAt(0) == '\\') return match.slice(1);
737			return (object[name] != undefined) ? object[name] : '';
738		});
739	}
740
741});
742
743/*
744Script: Hash.js
745	Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
746
747License:
748	MIT-style license.
749*/
750
751Hash.implement({
752
753	has: Object.prototype.hasOwnProperty,
754
755	keyOf: function(value){
756		for (var key in this){
757			if (this.hasOwnProperty(key) && this[key] === value) return key;
758		}
759		return null;
760	},
761
762	hasValue: function(value){
763		return (Hash.keyOf(this, value) !== null);
764	},
765
766	extend: function(properties){
767		Hash.each(properties, function(value, key){
768			Hash.set(this, key, value);
769		}, this);
770		return this;
771	},
772
773	combine: function(properties){
774		Hash.each(properties, function(value, key){
775			Hash.include(this, key, value);
776		}, this);
777		return this;
778	},
779
780	erase: function(key){
781		if (this.hasOwnProperty(key)) delete this[key];
782		return this;
783	},
784
785	get: function(key){
786		return (this.hasOwnProperty(key)) ? this[key] : null;
787	},
788
789	set: function(key, value){
790		if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
791		return this;
792	},
793
794	empty: function(){
795		Hash.each(this, function(value, key){
796			delete this[key];
797		}, this);
798		return this;
799	},
800
801	include: function(key, value){
802		var k = this[key];
803		if (k == undefined) this[key] = value;
804		return this;
805	},
806
807	map: function(fn, bind){
808		var results = new Hash;
809		Hash.each(this, function(value, key){
810			results.set(key, fn.call(bind, value, key, this));
811		}, this);
812		return results;
813	},
814
815	filter: function(fn, bind){
816		var results = new Hash;
817		Hash.each(this, function(value, key){
818			if (fn.call(bind, value, key, this)) results.set(key, value);
819		}, this);
820		return results;
821	},
822
823	every: function(fn, bind){
824		for (var key in this){
825			if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
826		}
827		return true;
828	},
829
830	some: function(fn, bind){
831		for (var key in this){
832			if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
833		}
834		return false;
835	},
836
837	getKeys: function(){
838		var keys = [];
839		Hash.each(this, function(value, key){
840			keys.push(key);
841		});
842		return keys;
843	},
844
845	getValues: function(){
846		var values = [];
847		Hash.each(this, function(value){
848			values.push(value);
849		});
850		return values;
851	},
852	
853	toQueryString: function(base){
854		var queryString = [];
855		Hash.each(this, function(value, key){
856			if (base) key = base + '[' + key + ']';
857			var result;
858			switch ($type(value)){
859				case 'object': result = Hash.toQueryString(value, key); break;
860				case 'array':
861					var qs = {};
862					value.each(function(val, i){
863						qs[i] = val;
864					});
865					result = Hash.toQueryString(qs, key);
866				break;
867				default: result = key + '=' + encodeURIComponent(value);
868			}
869			if (value != undefined) queryString.push(result);
870		});
871		
872		return queryString.join('&');
873	}
874
875});
876
877Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
878
879/*
880Script: Event.js
881	Contains the Event Native, to make the event object completely crossbrowser.
882
883License:
884	MIT-style license.
885*/
886
887var Event = new Native({
888
889	name: 'Event',
890
891	initialize: function(event, win){
892		win = win || window;
893		var doc = win.document;
894		event = event || win.event;
895		if (event.$extended) return event;
896		this.$extended = true;
897		var type = event.type;
898		var target = event.target || event.srcElement;
899		while (target && target.nodeType == 3) target = target.parentNode;
900		
901		if (type.test(/key/)){
902			var code = event.which || event.keyCode;
903			var key = Event.Keys.keyOf(code);
904			if (type == 'keydown'){
905				var fKey = code - 111;
906				if (fKey > 0 && fKey < 13) key = 'f' + fKey;
907			}
908			key = key || String.fromCharCode(code).toLowerCase();
909		} else if (type.match(/(click|mouse|menu)/i)){
910			doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
911			var page = {
912				x: event.pageX || event.clientX + doc.scrollLeft,
913				y: event.pageY || event.clientY + doc.scrollTop
914			};
915			var client = {
916				x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX,
917				y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY
918			};
919			if (type.match(/DOMMouseScroll|mousewheel/)){
920				var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
921			}
922			var rightClick = (event.which == 3) || (event.button == 2);
923			var related = null;
924			if (type.match(/over|out/)){
925				switch (type){
926					case 'mouseover': related = event.relatedTarget || event.fromElement; break;
927					case 'mouseout': related = event.relatedTarget || event.toElement;
928				}
929				if (!(function(){
930					while (related && related.nodeType == 3) related = related.parentNode;
931					return true;
932				}).create({attempt: Browser.Engine.gecko})()) related = false;
933			}
934		}
935
936		return $extend(this, {
937			event: event,
938			type: type,
939			
940			page: page,
941			client: client,
942			rightClick: rightClick,
943			
944			wheel: wheel,
945			
946			relatedTarget: related,
947			target: target,
948			
949			code: code,
950			key: key,
951			
952			shift: event.shiftKey,
953			control: event.ctrlKey,
954			alt: event.altKey,
955			meta: event.metaKey
956		});
957	}
958
959});
960
961Event.Keys = new Hash({
962	'enter': 13,
963	'up': 38,
964	'down': 40,
965	'left': 37,
966	'right': 39,
967	'esc': 27,
968	'space': 32,
969	'backspace': 8,
970	'tab': 9,
971	'delete': 46
972});
973
974Event.implement({
975
976	stop: function(){
977		return this.stopPropagation().preventDefault();
978	},
979
980	stopPropagation: function(){
981		if (this.event.stopPropagation) this.event.stopPropagation();
982		else this.event.cancelBubble = true;
983		return this;
984	},
985
986	preventDefault: function(){
987		if (this.event.preventDefault) this.event.preventDefault();
988		else this.event.returnValue = false;
989		return this;
990	}
991
992});
993
994/*
995Script: Class.js
996	Contains the Class Function for easily creating, extending, and implementing reusable Classes.
997
998License:
999	MIT-style license.
1000*/
1001
1002var Class = new Native({
1003
1004	name: 'Class',
1005
1006	initialize: function(properties){
1007		properties = properties || {};
1008		var klass = function(empty){
1009			for (var key in this) this[key] = $unlink(this[key]);
1010			for (var mutator in Class.Mutators){
1011				if (!this[mutator]) continue;
1012				Class.Mutators[mutator](this, this[mutator]);
1013				delete this[mutator];
1014			}
1015
1016			this.constructor = klass;
1017			if (empty === $empty) return this;
1018			
1019			var self = (this.initialize) ? this.initialize.apply(this, arguments) : this;
1020			if (this.options && this.options.initialize) this.options.initialize.call(this);
1021			return self;
1022		};
1023
1024		$extend(klass, this);
1025		klass.constructor = Class;
1026		klass.prototype = properties;
1027		return klass;
1028	}
1029
1030});
1031
1032Class.implement({
1033
1034	implement: function(){
1035		Class.Mutators.Implements(this.prototype, Array.slice(arguments));
1036		return this;
1037	}
1038
1039});
1040
1041Class.Mutators = {
1042  
1043  Implements: function(self, klasses){
1044  	$splat(klasses).each(function(klass){
1045  		$extend(self, ($type(klass) == 'class') ? new klass($empty) : klass);
1046  	});
1047  },
1048  
1049  Extends: function(self, klass){
1050  	var instance = new klass($empty);
1051  	delete instance.parent;
1052  	delete instance.parentOf;
1053
1054  	for (var key in instance){
1055  		var current = self[key], previous = instance[key];
1056  		if (current == undefined){
1057  			self[key] = previous;
1058  			continue;
1059  		}
1060
1061  		var ctype = $type(current), ptype = $type(previous);
1062  		if (ctype != ptype) continue;
1063
1064  		switch (ctype){
1065  			case 'function': 
1066  				// this code will be only executed if the current browser does not support function.caller (currently only opera).
1067  				// we replace the function code with brute force. Not pretty, but it will only be executed if function.caller is not supported.
1068
1069  				if (!arguments.callee.caller) self[key] = eval('(' + String(current).replace(/\bthis\.parent\(\s*(\))?/g, function(full, close){
1070  					return 'arguments.callee._parent_.call(this' + (close || ', ');
1071  				}) + ')');
1072
1073  				// end "opera" code
1074  				self[key]._parent_ = previous;
1075  			  break;
1076  			case 'object': self[key] = $merge(previous, current);
1077  		}
1078
1079  	}
1080
1081  	self.parent = function(){
1082  		return arguments.callee.caller._parent_.apply(this, arguments);
1083  	};
1084
1085  	self.parentOf = function(descendant){
1086  		return descendant._parent_.apply(this, Array.slice(arguments, 1));
1087  	};
1088  }
1089  
1090};
1091
1092
1093/*
1094Script: Class.Extras.js
1095	Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1096
1097License:
1098	MIT-style license.
1099*/
1100
1101var Chain = new Class({
1102
1103	chain: function(){
1104		this.$chain = (this.$chain || []).extend(arguments);
1105		return this;
1106	},
1107
1108	callChain: function(){
1109		return (this.$chain && this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1110	},
1111
1112	clearChain: function(){
1113		if (this.$chain) this.$chain.empty();
1114		return this;
1115	}
1116
1117});
1118
1119var Events = new Class({
1120
1121	addEvent: function(type, fn, internal){
1122		type = Events.removeOn(type);
1123		if (fn != $empty){
1124			this.$events = this.$events || {};
1125			this.$events[type] = this.$events[type] || [];
1126			this.$events[type].include(fn);
1127			if (internal) fn.internal = true;
1128		}
1129		return this;
1130	},
1131
1132	addEvents: function(events){
1133		for (var type in events) this.addEvent(type, events[type]);
1134		return this;
1135	},
1136
1137	fireEvent: function(type, args, delay){
1138		type = Events.removeOn(type);
1139		if (!this.$events || !this.$events[type]) return this;
1140		this.$events[type].each(function(fn){
1141			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
1142		}, this);
1143		return this;
1144	},
1145
1146	removeEvent: function(type, fn){
1147		type = Events.removeOn(type);
1148		if (!this.$events || !this.$events[type]) return this;
1149		if (!fn.internal) this.$events[type].erase(fn);
1150		return this;
1151	},
1152
1153	removeEvents: function(type){
1154		for (var e in this.$events){
1155			if (type && type != e) continue;
1156			var fns = this.$events[e];
1157			for (var i = fns.length; i--; i) this.removeEvent(e, fns[i]);
1158		}
1159		return this;
1160	}
1161
1162});
1163
1164Events.removeOn = function(string){
1165	return string.replace(/^on([A-Z])/, function(full, first) {
1166		return first.toLowerCase();
1167	});
1168};
1169
1170var Options = new Class({
1171
1172	setOptions: function(){
1173		this.options = $merge.run([this.options].extend(arguments));
1174		if (!this.addEvent) return this;
1175		for (var option in this.options){
1176			if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1177			this.addEvent(option, this.options[option]);
1178			delete this.options[option];
1179		}
1180		return this;
1181	}
1182
1183});
1184
1185/*
1186Script: Element.js
1187	One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser,
1188	time-saver methods to let you easily work with HTML Elements.
1189
1190License:
1191	MIT-style license.
1192*/
1193
1194Document.implement({
1195
1196	newElement: function(tag, props){
1197		if (Browser.Engine.trident && props){
1198			['name', 'type', 'checked'].each(function(attribute){
1199				if (!props[attribute]) return;
1200				tag += ' ' + attribute + '="' + props[attribute] + '"';
1201				if (attribute != 'checked') delete props[attribute];
1202			});
1203			tag = '<' + tag + '>';
1204		}
1205		return $.element(this.createElement(tag)).set(props);
1206	},
1207
1208	newTextNode: function(text){
1209		return this.createTextNode(text);
1210	},
1211
1212	getDocument: function(){
1213		return this;
1214	},
1215
1216	getWindow: function(){
1217		return this.defaultView || this.parentWindow;
1218	},
1219
1220	purge: function(){
1221		var elements = this.getElementsByTagName('*');
1222		for (var i = 0, l = elements.length; i < l; i++) Browser.freeMem(elements[i]);
1223	}
1224
1225});
1226
1227var Element = new Native({
1228
1229	name: 'Element',
1230
1231	legacy: window.Element,
1232
1233	initialize: function(tag, props){
1234		var konstructor = Element.Constructors.get(tag);
1235		if (konstructor) return konstructor(props);
1236		if (typeof tag == 'string') return document.newElement(tag, props);
1237		return $(tag).set(props);
1238	},
1239
1240	afterImplement: function(key, value){
1241		if (!Array[key]) Elements.implement(key, Elements.multi(key));
1242		Element.Prototype[key] = value;
1243	}
1244
1245});
1246
1247Element.Prototype = {$family: {name: 'element'}};
1248
1249Element.Constructors = new Hash;
1250
1251var IFrame = new Native({
1252
1253	name: 'IFrame',
1254
1255	generics: false,
1256
1257	initialize: function(){
1258		var params = Array.link(arguments, {properties: Object.type, iframe: $defined});
1259		var props = params.properties || {};
1260		var iframe = $(params.iframe) || false;
1261		var onload = props.onload || $empty;
1262		delete props.onload;
1263		props.id = props.name = $pick(props.id, props.name, iframe.id, iframe.name, 'IFrame_' + $time());
1264		iframe = new Element(iframe || 'iframe', props);
1265		var onFrameLoad = function(){
1266			var host = $try(function(){
1267				return iframe.contentWindow.location.host;
1268			});
1269			if (host && host == window.location.host){
1270				var win = new Window(iframe.contentWindow);
1271				var doc = new Document(iframe.contentWindow.document);
1272				$extend(win.Element.prototype, Element.Prototype);
1273			}
1274			onload.call(iframe.contentWindow, iframe.contentWindow.document);
1275		};
1276		(!window.frames[props.id]) ? iframe.addListener('load', onFrameLoad) : onFrameLoad();
1277		return iframe;
1278	}
1279
1280});
1281
1282var Elements = new Native({
1283
1284	initialize: function(elements, options){
1285		options = $extend({ddup: true, cash: true}, options);
1286		elements = elements || [];
1287		if (options.ddup || options.cash){
1288			var uniques = {}, returned = [];
1289			for (var i = 0, l = elements.length; i < l; i++){
1290				var el = $.element(elements[i], !options.cash);
1291				if (options.ddup){
1292					if (uniques[el.uid]) continue;
1293					uniques[el.uid] = true;
1294				}
1295				returned.push(el);
1296			}
1297			elements = returned;
1298		}
1299		return (options.cash) ? $extend(elements, this) : elements;
1300	}
1301
1302});
1303
1304Elements.implement({
1305
1306	filter: function(filter, bind){
1307		if (!filter) return this;
1308		return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){
1309			return item.match(filter);
1310		} : filter, bind));
1311	}
1312
1313});
1314
1315Elements.multi = function(property){
1316	return function(){
1317		var items = [];
1318		var elements = true;
1319		for (var i = 0, j = this.length; i < j; i++){
1320			var returns = this[i][property].apply(this[i], arguments);
1321			items.push(returns);
1322			if (elements) elements = ($type(returns) == 'element');
1323		}
1324		return (elements) ? new Elements(items) : items;
1325	};
1326};
1327
1328Window.implement({
1329
1330	$: function(el, nocash){
1331		if (el && el.$family && el.uid) return el;
1332		var type = $type(el);
1333		return ($[type]) ? $[type](el, nocash, this.document) : null;
1334	},
1335
1336	$$: function(selector){
1337		if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector);
1338		var elements = [];
1339		var args = Array.flatten(arguments);
1340		for (var i = 0, l = args.length; i < l; i++){
1341			var item = args[i];
1342			switch ($type(item)){
1343				case 'element': item = [item]; break;
1344				case 'string': item = this.document.getElements(item, true); break;
1345				default: item = false;
1346			}
1347			if (item) elements.extend(item);
1348		}
1349		return new Elements(elements);
1350	},
1351
1352	getDocument: function(){
1353		return this.document;
1354	},
1355
1356	getWindow: function(){
1357		return this;
1358	}
1359
1360});
1361
1362$.string = function(id, nocash, doc){
1363	id = doc.getElementById(id);
1364	return (id) ? $.element(id, nocash) : null;
1365};
1366
1367$.element = function(el, nocash){
1368	$uid(el);
1369	if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
1370		var proto = Element.Prototype;
1371		for (var p in proto) el[p] = proto[p];
1372	};
1373	return el;
1374};
1375
1376$.object = function(obj, nocash, doc){
1377	if (obj.toElement) return $.element(obj.toElement(doc), nocash);
1378	return null;
1379};
1380
1381$.textnode = $.whitespace = $.window = $.document = $arguments(0);
1382
1383Native.implement([Element, Document], {
1384
1385	getElement: function(selector, nocash){
1386		return $(this.getElements(selector, true)[0] || null, nocash);
1387	},
1388
1389	getElements: function(tags, nocash){
1390		tags = tags.split(',');
1391		var elements = [];
1392		var ddup = (tags.length > 1);
1393		tags.each(function(tag){
1394			var partial = this.getElementsByTagName(tag.trim());
1395			(ddup) ? elements.extend(partial) : elements = partial;
1396		}, this);
1397		return new Elements(elements, {ddup: ddup, cash: !nocash});
1398	}
1399
1400});
1401
1402Element.Storage = {
1403
1404	get: function(uid){
1405		return (this[uid] || (this[uid] = {}));
1406	}
1407
1408};
1409
1410Element.Inserters = new Hash({
1411
1412	before: function(context, element){
1413		if (element.parentNode) element.parentNode.insertBefore(context, element);
1414	},
1415
1416	after: function(context, element){
1417		if (!element.parentNode) return;
1418		var next = element.nextSibling;
1419		(next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
1420	},
1421
1422	bottom: function(context, element){
1423		element.appendChild(context);
1424	},
1425
1426	top: function(context, element){
1427		var first = element.firstChild;
1428		(first) ? element.insertBefore(context, first) : element.appendChild(context);
1429	}
1430
1431});
1432
1433Element.Inserters.inside = Element.Inserters.bottom;
1434
1435Element.Inserters.each(function(value, key){
1436
1437	var Key = key.capitalize();
1438
1439	Element.implement('inject' + Key, function(el){
1440		value(this, $(el, true));
1441		return this;
1442	});
1443
1444	Element.implement('grab' + Key, function(el){
1445		value($(el, true), this);
1446		return this;
1447	});
1448
1449});
1450
1451Element.implement({
1452
1453	getDocument: function(){
1454		return this.ownerDocument;
1455	},
1456
1457	getWindow: function(){
1458		return this.ownerDocument.getWindow();
1459	},
1460
1461	getElementById: function(id, nocash){
1462		var el = this.ownerDocument.getElementById(id);
1463		if (!el) return null;
1464		for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
1465			if (!parent) return null;
1466		}
1467		return $.element(el, nocash);
1468	},
1469
1470	set: function(prop, value){
1471		switch ($type(prop)){
1472			case 'object':
1473				for (var p in prop) this.set(p, prop[p]);
1474				break;
1475			case 'string':
1476				var property = Element.Properties.get(prop);
1477				(property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
1478		}
1479		return this;
1480	},
1481
1482	get: function(prop){
1483		var property = Element.Properties.get(prop);
1484		return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop);
1485	},
1486
1487	erase: function(prop){
1488		var property = Element.Properties.get(prop);
1489		(property && property.erase) ? property.erase.apply(this, Array.slice(arguments, 1)) : this.removeProperty(prop);
1490		return this;
1491	},
1492
1493	match: function(tag){
1494		return (!tag || Element.get(this, 'tag') == tag);
1495	},
1496
1497	inject: function(el, where){
1498		Element.Inserters.get(where || 'bottom')(this, $(el, true));
1499		return this;
1500	},
1501
1502	wraps: function(el, where){
1503		el = $(el, true);
1504		return this.replaces(el).grab(el, where);
1505	},
1506
1507	grab: function(el, where){
1508		Element.Inserters.get(where || 'bottom')($(el, true), this);
1509		return this;
1510	},
1511
1512	appendText: function(text, where){
1513		return this.grab(this.getDocument().newTextNode(text), where);
1514	},
1515
1516	adopt: function(){
1517		Array.flatten(arguments).each(function(element){
1518			element = $(element, true);
1519			if (element) this.appendChild(element);
1520		}, this);
1521		return this;
1522	},
1523
1524	dispose: function(){
1525		return (this.parentNode) ? this.parentNode.removeChild(this) : this;
1526	},
1527
1528	clone: function(contents, keepid){
1529		switch ($type(this)){
1530			case 'element':
1531				var attributes = {};
1532				for (var j = 0, l = this.attributes.length; j < l; j++){
1533					var attribute = this.attributes[j], key = attribute.nodeName.toLowerCase();
1534					if (Browser.Engine.trident && (/input/i).test(this.tagName) && (/width|height/).test(key)) continue;
1535					var value = (key == 'style' && this.style) ? this.style.cssText : attribute.nodeValue;
1536					if (!$chk(value) || key == 'uid' || (key == 'id' && !keepid)) continue;
1537					if (value != 'inherit' && ['string', 'number'].contains($type(value))) attributes[key] = value;
1538				}
1539				var element = new Element(this.nodeName.toLowerCase(), attributes);
1540				if (contents !== false){
1541					for (var i = 0, k = this.childNodes.length; i < k; i++){
1542						var child = Element.clone(this.childNodes[i], true, keepid);
1543						if (child) element.grab(child);
1544					}
1545				}
1546				return element;
1547			case 'textnode': return document.newTextNode(this.nodeValue);
1548		}
1549		return null;
1550	},
1551
1552	replaces: function(el){
1553		el = $(el, true);
1554		el.parentNode.replaceChild(this, el);
1555		return this;
1556	},
1557
1558	hasClass: function(className){
1559		return this.className.contains(className, ' ');
1560	},
1561
1562	addClass: function(className){
1563		if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
1564		return this;
1565	},
1566
1567	removeClass: function(className){
1568		this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean();
1569		return this;
1570	},
1571
1572	toggleClass: function(className){
1573		return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
1574	},
1575
1576	getComputedStyle: function(property){
1577		if (this.currentStyle) return this.currentStyle[property.camelCase()];
1578		var computed = this.getWindow().getComputedStyle(this, null);
1579		return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
1580	},
1581
1582	empty: function(){
1583		$A(this.childNodes).each(function(node){
1584			Browser.freeMem(node);
1585			Element.empty(node);
1586			Element.dispose(node);
1587		}, this);
1588		return this;
1589	},
1590
1591	destroy: function(){
1592		Browser.freeMem(this.empty().dispose());
1593		return null;
1594	},
1595
1596	getSelected: function(){
1597		return new Elements($A(this.options).filter(function(option){
1598			return option.selected;
1599		}));
1600	},
1601
1602	toQueryString: function(){
1603		var queryString = [];
1604		this.getElements('input, select, textarea').each(function(el){
1605			if (!el.name || el.disabled) return;
1606			var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){
1607				return opt.value;
1608			}) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value;
1609			$splat(value).each(function(val){
1610				if (val) queryString.push(el.name + '=' + encodeURIComponent(val));
1611			});
1612		});
1613		return queryString.join('&');
1614	},
1615
1616	getProperty: function(attribute){
1617		var EA = Element.Attributes, key = EA.Props[attribute];
1618		var value = (key) ? this[key] : this.getAttribute(attribute, 2);
1619		return (EA.Bools[attribute]) ? !!value : (key) ? value : value || null;
1620	},
1621
1622	getProperties: function(){
1623		var args = $A(arguments);
1624		return args.map(function(attr){
1625			return this.getProperty(attr);
1626		}, this).associate(args);
1627	},
1628
1629	setProperty: function(attribute, value){
1630		var EA = Element.Attributes, key = EA.Props[attribute], hasValue = $defined(value);
1631		if (key && EA.Bools[attribute]) value = (value || !hasValue) ? true : false;
1632		else if (!hasValue) return this.removeProperty(attribute);
1633		(key) ? this[key] = value : this.setAttribute(attribute, value);
1634		return this;
1635	},
1636
1637	setProperties: function(attributes){
1638		for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
1639		return this;
1640	},
1641
1642	removeProperty: function(attribute){
1643		var EA = Element.Attributes, key = EA.Props[attribute], isBool = (key && EA.Bools[attribute]);
1644		(key) ? this[key] = (isBool) ? false : '' : this.removeAttribute(attribute);
1645		return this;
1646	},
1647
1648	removeProperties: function(){
1649		Array.each(arguments, this.removeProperty, this);
1650		return this;
1651	}
1652
1653});
1654
1655(function(){
1656
1657var walk = function(element, walk, start, match, all, nocash){
1658	var el = element[start || walk];
1659	var elements = [];
1660	while (el){
1661		if (el.nodeType == 1 && (!match || Element.match(el, match))){
1662			elements.push(el);
1663			if (!all) break;
1664		}
1665		el = el[walk];
1666	}
1667	return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : $(elements[0], nocash);
1668};
1669
1670Element.implement({
1671
1672	getPrevious: function(match, nocash){
1673		return walk(this, 'previousSibling', null, match, false, nocash);
1674	},
1675
1676	getAllPrevious: function(match, nocash){
1677		return walk(this, 'previousSibling', null, match, true, nocash);
1678	},
1679
1680	getNext: function(match, nocash){
1681		return walk(this, 'nextSibling', null, match, false, nocash);
1682	},
1683
1684	getAllNext: function(match, nocash){
1685		return walk(this, 'nextSibling', null, match, true, nocash);
1686	},
1687
1688	getFirst: function(match, nocash){
1689		return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
1690	},
1691
1692	getLast: function(match, nocash){
1693		return walk(this, 'previousSibling', 'lastChild', match, false, nocash);
1694	},
1695
1696	getParent: function(match, nocash){
1697		return walk(this, 'parentNode', null, match, false, nocash);
1698	},
1699
1700	getParents: function(match, nocash){
1701		return walk(this, 'parentNode', null, match, true, nocash);
1702	},
1703
1704	getChildren: function(match, nocash){
1705		return walk(this, 'nextSibling', 'firstChild', match, true, nocash);
1706	},
1707
1708	hasChild: function(el){
1709		el = $(el, true);
1710		return (!!el && $A(this.getElementsByTagName(el.tagName)).contains(el));
1711	}
1712
1713});
1714
1715})();
1716
1717Element.Properties = new Hash;
1718
1719Element.Properties.style = {
1720
1721	set: function(style){
1722		this.style.cssText = style;
1723	},
1724
1725	get: function(){
1726		return this.style.cssText;
1727	},
1728
1729	erase: function(){
1730		this.style.cssText = '';
1731	}
1732
1733};
1734
1735Element.Properties.tag = {get: function(){
1736	return this.tagName.toLowerCase();
1737}};
1738
1739Element.Properties.href = {get: function(){
1740	return (!this.href) ? null : this.href.replace(new RegExp('^' + document.location.protocol + '\/\/' + document.location.host), '');
1741}};
1742
1743Element.Properties.html = {set: function(){
1744	return this.innerHTML = Array.flatten(arguments).join('');
1745}};
1746
1747Native.implement([Element, Window, Document], {
1748
1749	addListener: function(type, fn){
1750		if (this.addEventListener) this.addEventListener(type, fn, false);
1751		else this.attachEvent('on' + type, fn);
1752		return this;
1753	},
1754
1755	removeListener: function(type, fn){
1756		if (this.removeEventListener) this.removeEventListener(type, fn, false);
1757		else this.detachEvent('on' + type, fn);
1758		return this;
1759	},
1760
1761	retrieve: function(property, dflt){
1762		var storage = Element.Storage.get(this.uid);
1763		var prop = storage[property];
1764		if ($defined(dflt) && !$defined(prop)) prop = storage[property] = dflt;
1765		return $pick(prop);
1766	},
1767
1768	store: function(property, value){
1769		var storage = Element.Storage.get(this.uid);
1770		storage[property] = value;
1771		return this;
1772	},
1773
1774	eliminate: function(property){
1775		var storage = Element.Storage.get(this.uid);
1776		delete storage[property];
1777		return this;
1778	}
1779
1780});
1781
1782Element.Attributes = new Hash({
1783	Props: {'html': 'innerHTML', 'class': 'className', 'for': 'htmlFor', 'text': (Browser.Engine.trident) ? 'innerText' : 'textContent'},
1784	Bools: ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'],
1785	Camels: ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']
1786});
1787
1788Browser.freeMem = function(item){
1789	if (!item) return;
1790	if (Browser.Engine.trident && (/object/i).test(item.tagName)){
1791		for (var p in item){
1792			if (typeof item[p] == 'function') item[p] = $empty;
1793		}
1794		Element.dispose(item);
1795	}
1796	if (item.uid && item.removeEvents) item.removeEvents();
1797};
1798
1799(function(EA){
1800
1801	var EAB = EA.Bools, EAC = EA.Camels;
1802	EA.Bools = EAB = EAB.associate(EAB);
1803	Hash.extend(Hash.combine(EA.Props, EAB), EAC.associate(EAC.map(function(v){
1804		return v.toLowerCase();
1805	})));
1806	EA.erase('Camels');
1807
1808})(Element.Attributes);
1809
1810window.addListener('unload', function(){
1811	window.removeListener('unload', arguments.callee);
1812	document.purge();
1813	if (Browser.Engine.trident) CollectGarbage();
1814});
1815
1816/*
1817Script: Element.Event.js
1818	Contains Element methods for dealing with events, and custom Events.
1819
1820License:
1821	MIT-style license.
1822*/
1823
1824Element.Properties.events = {set: function(events){
1825	this.addEvents(events);
1826}};
1827
1828Native.implement([Element, Window, Document], {
1829
1830	addEvent: function(type, fn){
1831		var events = this.retrieve('events', {});
1832		events[type] = events[type] || {'keys': [], 'values': []};
1833		if (events[type].keys.contains(fn)) return this;
1834		events[type].keys.push(fn);
1835		var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
1836		if (custom){
1837			if (custom.onAdd) custom.onAdd.call(this, fn);
1838			if (custom.condition){
1839				condition = function(event){
1840					if (custom.condition.call(this, event)) return fn.call(this, event);
1841					return false;
1842				};
1843			}
1844			realType = custom.base || realType;
1845		}
1846		var defn = function(){
1847			return fn.call(self);
1848		};
1849		var nativeEvent = Element.NativeEvents[realType] || 0;
1850		if (nativeEvent){
1851			if (nativeEvent == 2){
1852				defn = function(event){
1853					event = new Event(event, self.getWindow());
1854					if (condition.call(self, event) === false) event.stop();
1855				};
1856			}
1857			this.addListener(realType, defn);
1858		}
1859		events[type].values.push(defn);
1860		return this;
1861	},
1862
1863	removeEvent: function(type, fn){
1864		var events = this.retrieve('events');
1865		if (!events || !events[type]) return this;
1866		var pos = events[type].keys.indexOf(fn);
1867		if (pos == -1) return this;
1868		var key = events[type].keys.splice(pos, 1)[0];
1869		var value = events[type].values.splice(pos, 1)[0];
1870		var custom = Element.Events.get(type);
1871		if (custom){
1872			if (custom.onRemove) custom.onRemove.call(this, fn);
1873			type = custom.base || type;
1874		}
1875		return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
1876	},
1877
1878	addEvents: function(events){
1879		for (var event in events) this.addEvent(event, events[event]);
1880		return this;
1881	},
1882
1883	removeEvents: function(type){
1884		var events = this.retrieve('events');
1885		if (!events) return this;
1886		if (!type){
1887			for (var evType in events) this.removeEvents(evType);
1888			events = null;
1889		} else if (events[type]){
1890			while (events[type].keys[0]) this.removeEvent(type, events[type].keys[0]);
1891			events[type] = null;
1892		}
1893		return this;
1894	},
1895
1896	fireEvent: function(type, args, delay){
1897		var events = this.retrieve('events');
1898		if (!events || !events[type]) return this;
1899		events[type].keys.each(function(fn){
1900			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
1901		}, this);
1902		return this;
1903	},
1904
1905	cloneEvents: function(from, type){
1906		from = $(from);
1907		var fevents = from.retrieve('events');
1908		if (!fevents) return this;
1909		if (!type){
1910			for (var evType in fevents) this.cloneEvents(from, evType);
1911		} else if (fevents[type]){
1912			fevents[type].keys.each(function(fn){
1913				this.addEvent(type, fn);
1914			}, this);
1915		}
1916		return this;
1917	}
1918
1919});
1920
1921Element.NativeEvents = {
1922	click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
1923	mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
1924	mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
1925	keydown: 2, keypress: 2, keyup: 2, //keyboard
1926	focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
1927	load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
1928	error: 1, abort: 1, scroll: 1 //misc
1929};
1930
1931(function(){
1932
1933var $check = function(event){
1934	var related = event.relatedTarget;
1935	if (related == undefined) return true;
1936	if (related === false) return false;
1937	return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
1938};
1939
1940Element.Events = new Hash({
1941
1942	mouseenter: {
1943		base: 'mouseover',
1944		condition: $check
1945	},
1946
1947	mouseleave: {
1948		base: 'mouseout',
1949		condition: $check
1950	},
1951
1952	mousewheel: {
1953		base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
1954	}
1955
1956});
1957
1958})();
1959
1960/*
1961Script: Element.Style.js
1962	Contains methods for interacting with the styles of Elements in a fashionable way.
1963
1964License:
1965	MIT-style license.
1966*/
1967
1968Element.Properties.styles = {set: function(styles){
1969	this.setStyles(styles);
1970}};
1971
1972Element.Properties.opacity = {
1973
1974	set: function(opacity, novisibility){
1975		if (!novisibility){
1976			if (opacity == 0){
1977				if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
1978			} else {
1979				if (this.style.visibility != 'visible') this.style.visibility = 'visible';
1980			}
1981		}
1982		if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
1983		if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
1984		this.style.opacity = opacity;
1985		this.store('opacity', opacity);
1986	},
1987
1988	get: function(){
1989		return this.retrieve('opacity', 1);
1990	}
1991
1992};
1993
1994Element.implement({
1995	
1996	setOpacity: function(value){
1997		return this.set('opacity', value, true);
1998	},
1999	
2000	getOpacity: function(){
2001		return this.get('opacity');
2002	},
2003
2004	setStyle: function(property, value){
2005		switch (property){
2006			case 'opacity': return this.set('opacity', parseFloat(value));
2007			case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
2008		}
2009		property = property.camelCase();
2010		if ($type(value) != 'string'){
2011			var map = (Element.Styles.get(property) || '@').split(' ');
2012			value = $splat(value).map(function(val, i){
2013				if (!map[i]) return '';
2014				return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
2015			}).join(' ');
2016		} else if (value == String(Number(value))){
2017			value = Math.round(value);
2018		}
2019		this.style[property] = value;
2020		return this;
2021	},
2022
2023	getStyle: function(property){
2024		switch (property){
2025			case 'opacity': return this.get('opacity');
2026			case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
2027		}
2028		property = property.camelCase();
2029		var result = this.style[property];
2030		if (!$chk(result)){
2031			result = [];
2032			for (var style in Element.ShortStyles){
2033				if (property != style) continue;
2034				for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
2035				return result.join(' ');
2036			}
2037			result = this.getComputedStyle(property);
2038		}
2039		if (result){
2040			result = String(result);
2041			var color = result.match(/rgba?\([\d\s,]+\)/);
2042			if (color) result = result.replace(color[0], color[0].rgbToHex());
2043		}
2044		if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result)))){
2045			if (property.test(/^(height|width)$/)){
2046				var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
2047				values.each(function(value){
2048					size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
2049				}, this);
2050				return this['offset' + property.capitalize()] - size + 'px';
2051			}
2052			if (Browser.Engine.presto && String(result).test('px')) return result;
2053			if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
2054		}
2055		return result;
2056	},
2057
2058	setStyles: function(styles){
2059		for (var style in styles) this.setStyle(style, styles[style]);
2060		return this;
2061	},
2062
2063	getStyles: function(){
2064		var result = {};
2065		Array.each(arguments, function(key){
2066			result[key] = this.getStyle(key);
2067		}, this);
2068		return result;
2069	}
2070
2071});
2072
2073Element.Styles = new Hash({
2074	left: '@px', top: '@px', bottom: '@px', right: '@px',
2075	width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
2076	backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
2077	fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
2078	margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
2079	borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
2080	zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
2081});
2082
2083Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
2084
2085['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
2086	var Short = Element.ShortStyles;
2087	var All = Element.Styles;
2088	['margin', 'padding'].each(function(style){
2089		var sd = style + direction;
2090		Short[style][sd] = All[sd] = '@px';
2091	});
2092	var bd = 'border' + direction;
2093	Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
2094	var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
2095	Short[bd] = {};
2096	Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
2097	Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
2098	Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
2099});
2100
2101
2102/*
2103Script: Element.Dimensions.js
2104	Contains methods to work with size, scroll, or positioning of Elements and the window object.
2105
2106License:
2107	MIT-style license.
2108
2109Credits:
2110	- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
2111	- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
2112*/
2113
2114(function(){
2115
2116Element.implement({
2117
2118	scrollTo: function(x, y){
2119		if (isBody(this)){
2120			this.getWindow().scrollTo(x, y);
2121		} else {
2122			this.scrollLeft = x;
2123			this.scrollTop = y;
2124		}
2125		return this;
2126	},
2127
2128	getSize: function(){
2129		if (isBody(this)) return this.getWindow().getSize();
2130		return {x: this.offsetWidth, y: this.offsetHeight};
2131	},
2132
2133	getScrollSize: function(){
2134		if (isBody(this)) return this.getWindow().getScrollSize();
2135		return {x: this.scrollWidth, y: this.scrollHeight};
2136	},
2137
2138	getScroll: function(){
2139		if (isBody(this)) return this.getWindow().getScroll();
2140		return {x: this.scrollLeft, y: this.scrollTop};
2141	},
2142
2143	getScrolls: function(){
2144		var element = this, position = {x: 0, y: 0};
2145		while (element && !isBody(element)){
2146			position.x += element.scrollLeft;
2147			position.y += element.scrollTop;
2148			element = element.parentNode;
2149		}
2150		return position;
2151	},
2152	
2153	getOffsetParent: function(){
2154		var element = this;
2155		if (isBody(element)) return null; 
2156		if (!Browser.Engine.trident) return element.offsetParent;
2157		while ((element = element.parentNode) && !isBody(element)){ 
2158			if (styleString(element, 'position') != 'static') return element;
2159		} 
2160		return null;
2161	},
2162
2163	getOffsets: function(){
2164		var element = this, position = {x: 0, y: 0};
2165		if (isBody(this)) return position;
2166
2167		while (element && !isBody(element)){
2168			position.x += element.offsetLeft;
2169			position.y += element.offsetTop;
2170
2171			if (Browser.Engine.gecko){
2172				if (!borderBox(element)){
2173					position.x += leftBorder(element);
2174					position.y += topBorder(element);
2175				}
2176				var parent = element.parentNode;
2177				if (parent && styleString(parent, 'overflow') != 'visible'){
2178					position.x += leftBorder(parent);
2179					position.y += topBorder(parent);
2180				}
2181			} else if (element != this && (Browser.Engine.trident || Browser.Engine.webkit)){
2182				position.x += leftBorder(element);
2183				position.y += topBorder(element);
2184			}
2185
2186			element = element.offsetParent;
2187			if (Browser.Engine.trident){
2188				while (element && !element.currentStyle.hasLayout) element = element.offsetParent;
2189			}
2190		}
2191		if (Browser.Engine.gecko && !borderBox(this)){
2192			position.x -= leftBorder(this);
2193			position.y -= topBorder(this);
2194		}
2195		return position;
2196	},
2197
2198	getPosition: function(relative){
2199		if (isBody(this)) return {x: 0, y: 0};
2200		var offset = this.getOffsets(), scroll = this.getScrolls();
2201		var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
2202		var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
2203		return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
2204	},
2205
2206	getCoordinates: function(element){
2207		if (isBody(this)) return this.getWindow().getCoordinates();
2208		var position = this.getPosition(element), size = this.getSize();
2209		var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
2210		obj.right = obj.left + obj.width;
2211		obj.bottom = obj.top + obj.height;
2212		return obj;
2213	},
2214
2215	computePosition: function(obj){
2216		return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
2217	},
2218
2219	position: function(obj){
2220		return this.setStyles(this.computePosition(obj));
2221	}
2222
2223});
2224
2225Native.implement([Document, Window], {
2226
2227	getSize: function(){
2228		var win = this.getWindow();
2229		if (Browser.Engine.presto || Browser.Engine.webkit) return {x: win.innerWidth, y: win.innerHeight};
2230		var doc = getCompatElement(this);
2231		return {x: doc.clientWidth, y: doc.clientHeight};
2232	},
2233
2234	getScroll: function(){
2235		var win = this.getWindow();
2236		var doc = getCompatElement(this);
2237		return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
2238	},
2239
2240	getScrollSize: function(){
2241		var doc = getCompatElement(this);
2242		var min = this.getSize();
2243		return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
2244	},
2245
2246	getPosition: function(){
2247		return {x: 0, y: 0};
2248	},
2249
2250	getCoordinates: function(){
2251		var size = this.getSize();
2252		return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
2253	}
2254
2255});
2256
2257// private methods
2258
2259var styleString = Element.getComputedStyle;
2260
2261function styleNumber(element, style){
2262	return styleString(element, style).toInt() || 0;
2263};
2264
2265function borderBox(element){
2266	return styleString(element, '-moz-box-sizing') == 'border-box';
2267};
2268
2269function topBorder(element){
2270	return styleNumber(element, 'border-top-width');
2271};
2272
2273function leftBorder(element){
2274	return styleNumber(element, 'border-left-width');
2275};
2276
2277function isBody(element){
2278	return (/^(?:body|html)$/i).test(element.tagName);
2279};
2280
2281function getCompatElement(element){
2282	var doc = element.getDocument();
2283	return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
2284};
2285
2286})();
2287
2288//aliases
2289
2290Native.implement([Window, Document, Element], {
2291
2292	getHeight: function(){
2293		return this.getSize().y;
2294	},
2295
2296	getWidth: function(){
2297		return this.getSize().x;
2298	},
2299
2300	getScrollTop: function(){
2301		return this.getScroll().y;
2302	},
2303
2304	getScrollLeft: function(){
2305		return this.getScroll().x;
2306	},
2307
2308	getScrollHeight: function(){
2309		return this.getScrollSize().y;
2310	},
2311
2312	getScrollWidth: function(){
2313		return this.getScrollSize().x;
2314	},
2315
2316	getTop: function(){
2317		return this.getPosition().y;
2318	},
2319
2320	getLeft: function(){
2321		return this.getPosition().x;
2322	}
2323
2324});
2325
2326/*
2327Script: Selectors.js
2328	Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.
2329
2330License:
2331	MIT-style license.
2332*/
2333
2334Native.implement([Document, Element], {
2335	
2336	getElements: function(expression, nocash){
2337		expression = expression.split(',');
2338		var items, local = {};
2339		for (var i = 0, l = expression.length; i < l; i++){
2340			var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
2341			if (i != 0 && elements.item) elements = $A(elements);
2342			items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
2343		}
2344		return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
2345	}
2346	
2347});
2348
2349Element.implement({
2350	
2351	match: function(selector){
2352		if (!selector) return true;
2353		var tagid = Selectors.Utils.parseTagAndID(selector);
2354		var tag = tagid[0], id = tagid[1];
2355		if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
2356		var parsed = Selectors.Utils.parseSelector(selector);
2357		return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;
2358	}
2359	
2360});
2361
2362var Selectors = {Cache: {nth: {}, parsed: {}}};
2363
2364Selectors.RegExps = {
2365	id: (/#([\w-]+)/),
2366	tag: (/^(\w+|\*)/),
2367	quick: (/^(\w+|\*)$/),
2368	splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
2369	combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)["']?(.*?)["']?)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
2370};
2371
2372Selectors.Utils = {
2373	
2374	chk: function(item, uniques){
2375		if (!uniques) return true;
2376		var uid = $uid(item);
2377		if (!uniques[uid]) return uniques[uid] = true;
2378		return false;
2379	},
2380	
2381	parseNthArgument: function(argument){
2382		if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
2383		var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
2384		if (!parsed) return false;
2385		var inta = parseInt(parsed[1]);
2386		var a = (inta || inta === 0) ? inta : 1;
2387		var special = parsed[2] || false;
2388		var b = parseInt(parsed[3]) || 0;
2389		if (a != 0){
2390			b--;
2391			while (b < 1) b += a;
2392			while (b >= a) b -= a;
2393		} else {
2394			a = b;
2395			special = 'index';
2396		}
2397		switch (special){
2398			case 'n': parsed = {a: a, b: b, special: 'n'}; break;
2399			case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break;
2400			case 'even': parsed =  {a: 2, b: 1, special: 'n'}; break;
2401			case 'first': parsed = {a: 0, special: 'index'}; break;
2402			case 'last': parsed = {special: 'last-child'}; break;
2403			case 'only': parsed = {special: 'only-child'}; break;
2404			default: parsed = {a: (a - 1), special: 'index'};
2405		}
2406		
2407		return Selectors.Cache.nth[argument] = parsed;
2408	},
2409	
2410	parseSelector: function(selector){
2411		if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
2412		var m, parsed = {classes: [], pseudos: [], attributes: []};
2413		while ((m = Selectors.RegExps.combined.exec(selector))){
2414			var cn = m[1], an = m[2], ao = m[3], av = m[4], pn = m[5], pa = m[6];
2415			if (cn){
2416				parsed.classes.push(cn);
2417			} else if (pn){
2418				var parser = Selectors.Pseudo.get(pn);
2419				if (parser) parsed.pseudos.push({parser: parser, argument: pa});
2420				else parsed.attributes.push({name: pn, operator: '=', value: pa});
2421			} else if (an){
2422				parsed.attributes.push({name: an, operator: ao, value: av});
2423			}
2424		}
2425		if (!parsed.classes.length) delete parsed.classes;
2426		if (!parsed.attributes.length) delete parsed.attributes;
2427		if (!parsed.pseudos.length) delete parsed.pseudos;
2428		if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
2429		return Selectors.Cache.parsed[selector] = parsed;
2430	},
2431	
2432	parseTagAndID: function(selector){
2433		var tag = selector.match(Selectors.RegExps.tag);
2434		var id = selector.match(Selectors.RegExps.id);
2435		return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
2436	},
2437	
2438	filter: function(item, parsed, local){
2439		var i;
2440		if (parsed.classes){
2441			for (i = parsed.classes.length; i--; i){
2442				var cn = parsed.classes[i];
2443				if (!Selectors.Filters.byClass(item, cn)) return false;
2444			}
2445		}
2446		if (parsed.attributes){
2447			for (i = parsed.attributes.length; i--; i){
2448				var att = parsed.attributes[i];
2449				if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
2450			}
2451		}
2452		if (parsed.pseudos){
2453			for (i = parsed.pseudos.length; i--; i){
2454				var psd = parsed.pseudos[i];
2455				if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
2456			}
2457		}
2458		return true;
2459	},
2460	
2461	getByTagAndID: function(ctx, tag, id){
2462		if (id){
2463			var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true);
2464			return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
2465		} else {
2466			return ctx.getElementsByTagName(tag);
2467		}
2468	},
2469	
2470	search: function(self, expression, local){
2471		var splitters = [];
2472		
2473		var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
2474			splitters.push(m1);
2475			return ':)' + m2;
2476		}).split(':)');
2477		
2478		var items, match, filtered, item;
2479		
2480		for (var i = 0, l = selectors.length; i < l; i++){
2481			
2482			var selector = selectors[i];
2483			
2484			if (i == 0 && Selectors.RegExps.quick.test(selector)){
2485				items = self.getElementsByTagName(selector);
2486				continue;
2487			}
2488			
2489			var splitter = splitters[i - 1];
2490			
2491			var tagid = Selectors.Utils.parseTagAndID(selector);
2492			var tag = tagid[0], id = tagid[1];
2493
2494			if (i == 0){
2495				items = Selectors.Utils.getByTagAndID(self, tag, id);
2496			} else {
2497				var uniques = {}, found = [];
2498				for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
2499				items = found;
2500			}
2501			
2502			var parsed = Selectors.Utils.parseSelector(selector);
2503			
2504			if (parsed){
2505				filtered = [];
2506				for (var m = 0, n = items.length; m < n; m++){
2507					item = items[m];
2508					if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
2509				}
2510				items = filtered;
2511			}
2512			
2513		}
2514		
2515		return items;
2516		
2517	}
2518	
2519};
2520
2521Selectors.Getters = {
2522	
2523	' ': function(found, self, tag, id, uniques){
2524		var items = Selectors.Utils.getByTagAndID(self, tag, id);
2525		for (var i = 0, l = items.length; i < l; i++){
2526			var item = items[i];
2527			if (Selectors.Utils.chk(item, uniques)) found.push(item);
2528		}
2529		return found;
2530	},
2531	
2532	'>': function(found, self, tag, id, uniques){
2533		var children = Selectors.Utils.getByTagAndID(self, tag, id);
2534		for (var i = 0, l = children.length; i < l; i++){
2535			var child = children[i];
2536			if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
2537		}
2538		return found;
2539	},
2540	
2541	'+': function(found, self, tag, id, uniques){
2542		while ((self = self.nextSibling)){
2543			if (self.nodeType == 1){
2544				if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
2545				break;
2546			}
2547		}
2548		return found;
2549	},
2550	
2551	'~': function(found, self, tag, id, uniques){
2552		
2553		while ((self = self.nextSibling)){
2554			if (self.nodeType == 1){
2555				if (!Selectors.Utils.chk(self, uniques)) break;
2556				if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
2557			} 
2558		}
2559		return found;
2560	}
2561	
2562};
2563
2564Selectors.Filters = {
2565	
2566	byTag: function(self, tag){
2567		return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
2568	},
2569	
2570	byID: function(self, id){
2571		return (!id || (self.id && self.id == id));
2572	},
2573	
2574	byClass: function(self, klass){
2575		return (self.className && self.className.contains(klass, ' '));
2576	},
2577	
2578	byPseudo: function(self, parser, argument, local){
2579		return parser.call(self, argument, local);
2580	},
2581	
2582	byAttribute: function(self, name, operator, value){
2583		var result = Element.prototype.getProperty.call(self, name);
2584		if (!result) return false;
2585		if (!operator || value == undefined) return true;
2586		switch (operator){
2587			case '=': return (result == value);
2588			case '*=': return (result.contains(value));
2589			case '^=': return (result.substr(0, value.length) == value);
2590			case '$=': return (result.substr(result.length - value.length) == value);
2591			case '!=': return (result != value);
2592			case '~=': return result.contains(value, ' ');
2593			case '|=': return result.contains(value, '-');
2594		}
2595		return false;
2596	}
2597	
2598};
2599
2600Selectors.Pseudo = new Hash({
2601	
2602	// w3c pseudo selectors
2603	
2604	empty: function(){
2605		return !(this.innerText || this.textContent || '').length;
2606	},
2607	
2608	not: function(selector){
2609		return !Element.match(this, selector);
2610	},
2611	
2612	contains: function(text){
2613		return (this.innerText || this.textContent || '').contains(text);
2614	},
2615	
2616	'first-child': function(){
2617		return Selectors.Pseudo.index.call(this, 0);
2618	},
2619	
2620	'last-child': function(){
2621		var element = this;
2622		while ((element = element.nextSibling)){
2623			if (element.nodeType == 1) return false;
2624		}
2625		return true;
2626	},
2627	
2628	'only-child': function(){
2629		var prev = this;
2630		while ((prev = prev.previousSibling)){
2631			if (prev.nodeType == 1) return false;
2632		}
2633		var next = this;
2634		while ((next = next.nextSibling)){
2635			if (next.nodeType == 1) return false;
2636		}
2637		return true;
2638	},
2639	
2640	'nth-child': function(argument, local){
2641		argument = (argument == undefined) ? 'n' : argument;
2642		var parsed = Selectors.Utils.parseNthArgument(argument);
2643		if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
2644		var count = 0;
2645		local.positions = local.positions || {};
2646		var uid = $uid(this);
2647		if (!local.positions[uid]){
2648			var self = this;
2649			while ((self = self.previousSibling)){
2650				if (self.nodeType != 1) continue;
2651				count ++;
2652				var position = local.positions[$uid(self)];
2653				if (position != undefined){
2654					count = position + count;
2655					break;
2656				}
2657			}
2658			local.positions[uid] = count;
2659		}
2660		return (local.positions[uid] % parsed.a == parsed.b);
2661	},
2662	
2663	// custom pseudo selectors
2664	
2665	index: function(index){
2666		var element = this, count = 0;
2667		while ((element = element.previousSibling)){
2668			if (element.nodeType == 1 && ++count > index) return false;
2669		}
2670		return (count == index);
2671	},
2672	
2673	even: function(argument, local){
2674		return Selectors.Pseudo['nth-child'].call(this, '2n+1', local);
2675	},
2676
2677	odd: function(argument, local){
2678		return Selectors.Pseudo['nth-child'].call(this, '2n', local);
2679	}
2680	
2681});
2682
2683/*
2684Script: Domready.js
2685	Contains the domready custom event.
2686
2687License:
2688	MIT-style license.
2689*/
2690
2691Element.Events.domready = {
2692
2693	onAdd: function(fn){
2694		if (Browser.loaded) fn.call(this);
2695	}
2696
2697};
2698
2699(function(){
2700	
2701	var domready = function(){
2702		if (Browser.loaded) return;
2703		Browser.loaded = true;
2704		window.fireEvent('domready');
2705		document.fireEvent('domready');
2706	};
2707	
2708	switch (Browser.Engine.name){
2709
2710		case 'webkit': (function(){
2711			(['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);
2712		})(); break;
2713
2714		case 'trident':
2715			var temp = document.createElement('div');
2716			(function(){
2717				($try(function(){
2718					temp.doScroll('left');
2719					return $(temp).inject(document.body).set('html', 'temp').dispose();
2720				})) ? domready() : arguments.callee.delay(50);
2721			})();
2722		break;
2723		
2724		default:
2725			window.addEvent('load', domready);
2726			document.addEvent('DOMContentLoaded', domready);
2727
2728	}
2729	
2730})();
2731
2732/*
2733Script: JSON.js
2734	JSON encoder and decoder.
2735
2736License:
2737	MIT-style license.
2738
2739See Also:
2740	<http://www.json.org/>
2741*/
2742
2743var JSON = new Hash({
2744
2745	encode: function(obj){
2746		switch ($type(obj)){
2747			case 'string':
2748				return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"';
2749			case 'array':
2750				return '[' + String(obj.map(JSON.encode).filter($defined)) + ']';
2751			case 'object': case 'hash':
2752				var string = [];
2753				Hash.each(obj, function(value, key){
2754					var json = JSON.encode(value);
2755					if (json) string.push(JSON.encode(key) + ':' + json);
2756				});
2757				return '{' + string + '}';
2758			case 'number': case 'boolean': return String(obj);
2759			case false: return 'null';
2760		}
2761		return null;
2762	},
2763
2764	$specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
2765
2766	$replaceChars: function(chr){
2767		return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
2768	},
2769
2770	decode: function(string, secure){
2771		if ($type(string) != 'string' || !string.length) return null;
2772		if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
2773		return eval('(' + string + ')');
2774	}
2775
2776});
2777
2778Native.implement([Hash, Array, String, Number], {
2779
2780	toJSON: function(){
2781		return JSON.encode(this);
2782	}
2783
2784});
2785
2786
2787/*
2788Script: Cookie.js
2789	Class for creating, loading, and saving browser Cookies.
2790
2791License:
2792	MIT-style license.
2793
2794Credits:
2795	Based on the functions by Peter-Paul Koch (http://quirksmode.org).
2796*/
2797
2798var Cookie = new Class({
2799
2800	Implements: Options,
2801
2802	options: {
2803		path: false,
2804		domain: false,
2805		duration: false,
2806		secure: false,
2807		document: document
2808	},
2809
2810	initialize: function(key, options){
2811		this.key = key;
2812		this.setOptions(options);
2813	},
2814
2815	write: function(value){
2816		value = encodeURIComponent(value);
2817		if (this.options.domain) value += '; domain=' + this.options.domain;
2818		if (this.options.path) value += '; path=' + this.options.path;
2819		if (this.options.duration){
2820			var date = new Date();
2821			date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
2822			value += '; expires=' + date.toGMTString();
2823		}
2824		if (this.options.secure) value += '; secure';
2825		this.options.document.cookie = this.key + '=' + value;
2826		return this;
2827	},
2828
2829	read: function(){
2830		var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
2831		return (value) ? decodeURIComponent(value[1]) : null;
2832	},
2833
2834	dispose: function(){
2835		new Cookie(this.key, $merge(this.options, {duration: -1})).write('');
2836		return this;
2837	}
2838
2839});
2840
2841Cookie.write = function(key, value, options){
2842	return new Cookie(key, options).write(value);
2843};
2844
2845Cookie.read = function(key){
2846	return new Cookie(key).read();
2847};
2848
2849Cookie.dispose = function(key, options){
2850	return new Cookie(key, options).dispose();
2851};
2852
2853/*
2854Script: Swiff.js
2855	Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication.
2856
2857License:
2858	MIT-style license.
2859
2860Credits:
2861	Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
2862*/
2863
2864var Swiff = new Class({
2865
2866	Implements: [Options],
2867
2868	options: {
2869		id: null,
2870		height: 1,
2871		width: 1,
2872		container: null,
2873		properties: {},
2874		params: {
2875			quality: 'high',
2876			allowScriptAccess: 'always',
2877			wMode: 'transparent',
2878			swLiveConnect: true
2879		},
2880		callBacks: {},
2881		vars: {}
2882	},
2883
2884	toElement: function(){
2885		return this.object;
2886	},
2887
2888	initialize: function(path, options){
2889		this.instance = 'Swiff_' + $time();
2890
2891		this.setOptions(options);
2892		options = this.options;
2893		var id = this.id = options.id || this.instance;
2894		var container = $(options.container);
2895
2896		Swiff.CallBacks[this.instance] = {};
2897
2898		var params = options.params, vars = options.vars, callBacks = options.callBacks;
2899		var properties = $extend({height: options.height, width: options.width}, options.properties);
2900
2901		var self = this;
2902
2903		for (var callBack in callBacks){
2904			Swiff.CallBacks[this.instance][callBack] = (function(option){
2905				return function(){
2906					return option.apply(self.object, arguments);
2907				};
2908			})(callBacks[callBack]);
2909			vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
2910		}
2911
2912		params.flashVars = Hash.toQueryString(vars);
2913		if (Browser.Engine.trident){
2914			properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
2915			params.movie = path;
2916		} else {
2917			properties.type = 'application/x-shockwave-flash';
2918			properties.data = path;
2919		}
2920		var build = '<object id="' + id + '"';
2921		for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
2922		build += '>';
2923		for (var param in params){
2924			if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
2925		}
2926		build += '</object>';
2927		this.object =  ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
2928	},
2929
2930	replaces: function(element){
2931		element = $(element, true);
2932		element.parentNode.replaceChild(this.toElement(), element);
2933		return this;
2934	},
2935
2936	inject: function(element){
2937		$(element, true).appendChild(this.toElement());
2938		return this;
2939	},
2940
2941	remote: function(){
2942		return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments));
2943	}
2944
2945});
2946
2947Swiff.CallBacks = {};
2948
2949Swiff.remote = function(obj, fn){
2950	var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
2951	return eval(rs);
2952};
2953
2954/*
2955Script: Fx.js
2956	Contains the basic animation logic to be extended by all other Fx Classes.
2957
2958License:
2959	MIT-style license.
2960*/
2961
2962var Fx = new Class({
2963
2964	Implements: [Chain, Events, Options],
2965
2966	options: {
2967		/*
2968		onStart: $empty,
2969		onCancel: $empty,
2970		onComplete: $empty,
2971		*/
2972		fps: 50,
2973		unit: false,
2974		duration: 500,
2975		link: 'ignore',
2976		transition: function(p){
2977			return -(Math.cos(Math.PI * p) - 1) / 2;
2978		}
2979	},
2980
2981	initialize: function(options){
2982		this.subject = this.subject || this;
2983		this.setOptions(options);
2984		this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
2985		var wait = this.options.wait;
2986		if (wait === false) this.options.link = 'cancel';
2987	},
2988
2989	step: function(){
2990		var time = $time();
2991		if (time < this.time + this.options.duration){
2992			var delta = this.options.transition((time - this.time) / this.options.duration);
2993			this.set(this.compute(this.from, this.to, delta));
2994		} else {
2995			this.set(this.compute(this.from, this.to, 1));
2996			this.complete();
2997		}
2998	},
2999
3000	set: function(now){
3001		return now;
3002	},
3003
3004	compute: function(from, to, delta){
3005		return Fx.compute(from, to, delta);
3006	},
3007
3008	check: function(caller){
3009		if (!this.timer) return true;
3010		switch (this.options.link){
3011			case 'cancel': this.cancel(); return true;
3012			case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false;
3013		}
3014		return false;
3015	},
3016
3017	start: function(from, to){
3018		if (!this.check(arguments.callee, from, to)) return this;
3019		this.from = from;
3020		this.to = to;
3021		this.time = 0;
3022		this.startTimer();
3023		this.onStart();
3024		return this;
3025	},
3026
3027	complete: function(){
3028		if (this.stopTimer()) this.onComplete();
3029		return this;
3030	},
3031
3032	cancel: function(){
3033		if (this.stopTimer()) this.onCancel();
3034		return this;
3035	},
3036
3037	onStart: function(){
3038		this.fireEvent('start', this.subject);
3039	},
3040
3041	onComplete: function(){
3042		this.fireEvent('complete', this.subject);
3043		if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
3044	},
3045
3046	onCancel: function(){
3047		this.fireEvent('cancel', this.subject).clearChain();
3048	},
3049
3050	pause: function(){
3051		this.stopTimer();
3052		return this;
3053	},
3054
3055	resume: function(){
3056		this.startTimer();
3057		return this;
3058	},
3059
3060	stopTimer: function(){
3061		if (!this.timer) return false;
3062		this.time = $time() - this.time;
3063		this.timer = $clear(this.timer);
3064		return true;
3065	},
3066
3067	startTimer: function(){
3068		if (this.timer) return false;
3069		this.time = $time() - this.time;
3070		this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
3071		return true;
3072	}
3073
3074});
3075
3076Fx.compute = function(from, to, delta){
3077	return (to - from) * delta + from;
3078};
3079
3080Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
3081
3082
3083/*
3084Script: Fx.CSS.js
3085	Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
3086
3087License:
3088	MIT-style license.
3089*/
3090
3091Fx.CSS = new Class({
3092
3093	Extends: Fx,
3094
3095	//prepares the base from/to object
3096
3097	prepare: function(element, property, values){
3098		values = $splat(values);
3099		var values1 = values[1];
3100		if (!$chk(values1)){
3101			values[1] = values[0];
3102			values[0] = element.getStyle(property);
3103		}
3104		var parsed = values.map(this.parse);
3105		return {from: parsed[0], to: parsed[1]};
3106	},
3107
3108	//parses a value into an array
3109
3110	parse: function(value){
3111		value = $lambda(value)();
3112		value = (typeof value == 'string') ? value.split(' ') : $splat(value);
3113		return value.map(function(val){
3114			val = String(val);
3115			var found = false;
3116			Fx.CSS.Parsers.each(function(parser, key){
3117				if (found) return;
3118				var parsed = parser.parse(val);
3119				if ($chk(parsed)) found = {value: parsed, parser: parser};
3120			});
3121			found = found || {value: val, parser: Fx.CSS.Parsers.String};
3122			return found;
3123		});
3124	},
3125
3126	//computes by a from and to prepared objects, using their parsers.
3127
3128	compute: function(from, to, delta){
3129		var computed = [];
3130		(Math.min(from.length, to.length)).times(function(i){
3131			computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
3132		});
3133		computed.$family = {name: 'fx:css:value'};
3134		return computed;
3135	},
3136
3137	//serves the value as settable
3138
3139	serve: function(value, unit){
3140		if ($type(value) != 'fx:css:value') value = this.parse(value);
3141		var returned = [];
3142		value.each(function(bit){
3143			returned = returned.concat(bit.parser.serve(bit.value, unit));
3144		});
3145		return returned;
3146	},
3147
3148	//renders the change to an element
3149
3150	render: function(element, property, value, unit){
3151		element.setStyle(property, this.serve(value, unit));
3152	},
3153
3154	//searches inside the page css to find the values for a selector
3155
3156	search: function(selector){
3157		if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
3158		var to = {};
3159		Array.each(document.styleSheets, function(sheet, j){
3160			var href = sheet.href;
3161			if (href && href.contains('://') && !href.contains(document.domain)) return;
3162			var rules = sheet.rules || sheet.cssRules;
3163			Array.each(rules, function(rule, i){
3164				if (!rule.style) return;
3165				var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
3166					return m.toLowerCase();
3167				}) : null;
3168				if (!selectorText || !selectorText.test('^' + selector + '$')) return;
3169				Element.Styles.each(function(value, style){
3170					if (!rule.style[style] || Element.ShortStyles[style]) return;
3171					value = String(rule.style[style]);
3172					to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value;
3173				});
3174			});
3175		});
3176		return Fx.CSS.Cache[selector] = to;
3177	}
3178
3179});
3180
3181Fx.CSS.Cache = {};
3182
3183Fx.CSS.Parsers = new Hash({
3184
3185	Color: {
3186		parse: function(value){
3187			if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
3188			return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
3189		},
3190		compute: function(from, to, delta){
3191			return from.map(function(value, i){
3192				return Math.round(Fx.compute(from[i], to[i], delta));
3193			});
3194		},
3195		serve: function(value){
3196			return value.map(Number);
3197		}
3198	},
3199
3200	Number: {
3201		parse: parseFloat,
3202		compute: Fx.compute,
3203		serve: function(value, unit){
3204			return (unit) ? value + unit : value;
3205		}
3206	},
3207
3208	String: {
3209		parse: $lambda(false),
3210		compute: $arguments(1),
3211		serve: $arguments(0)
3212	}
3213
3214});
3215
3216
3217/*
3218Script: Fx.Tween.js
3219	Formerly Fx.Style, effect to transition any CSS property for an element.
3220
3221License:
3222	MIT-style license.
3223*/
3224
3225Fx.Tween = new Class({
3226
3227	Extends: Fx.CSS,
3228
3229	initialize: function(element, options){
3230		this.element = this.subject = $(element);
3231		this.parent(options);
3232	},
3233
3234	set: function(property, now){
3235		if (arguments.length == 1){
3236			now = property;
3237			property = this.property || this.options.property;
3238		}
3239		this.render(this.element, property, now, this.options.unit);
3240		return this;
3241	},
3242
3243	start: function(property, from, to){
3244		if (!this.check(arguments.callee, property, from, to)) return this;
3245		var args = Array.flatten(arguments);
3246		this.property = this.options.property || args.shift();
3247		var parsed = this.prepare(this.element, this.property, args);
3248		return this.parent(parsed.from, parsed.to);
3249	}
3250
3251});
3252
3253Element.Properties.tween = {
3254
3255	set: function(options){
3256		var tween = this.retrieve('tween');
3257		if (tween) tween.cancel();
3258		return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options));
3259	},
3260
3261	get: function(options){
3262		if (options || !this.retrieve('tween')){
3263			if (options || !this.retrieve('tween:options')) this.set('tween', options);
3264			this.store('tween', new Fx.Tween(this, this.retrieve('tween:options')));
3265		}
3266		return this.retrieve('tween');
3267	}
3268
3269};
3270
3271Element.implement({
3272
3273	tween: function(property, from, to){
3274		this.get('tween').start(arguments);
3275		return this;
3276	},
3277
3278	fade: function(how){
3279		var fade = this.get('tween'), o = 'opacity', toggle;
3280		how = $pick(how, 'toggle');
3281		switch (how){
3282			case 'in': fade.start(o, 1); break;
3283			case 'out': fade.start(o, 0); break;
3284			case 'show': fade.set(o, 1); break;
3285			case 'hide': fade.set(o, 0); break;
3286			case 'toggle':
3287				var flag = this.retrieve('fade:flag', this.get('opacity') == 1);
3288				fade.start(o, (flag) ? 0 : 1);
3289				this.store('fade:flag', !flag);
3290				toggle = true;
3291			break;
3292			default: fade.start(o, arguments);
3293		}
3294		if (!toggle) this.eliminate('fade:flag');
3295		return this;
3296	},
3297
3298	highlight: function(start, end){
3299		if (!end){
3300			end = this.retrieve('highlight:original', this.getStyle('background-color'));
3301			end = (end == 'transparent') ? '#fff' : end;
3302		}
3303		var tween = this.get('tween');
3304		tween.start('background-color', start || '#ffff88', end).chain(function(){
3305			this.setStyle('background-color', this.retrieve('highlight:original'));
3306			tween.callChain();
3307		}.bind(this));
3308		return this;
3309	}
3310
3311});
3312
3313
3314/*
3315Script: Fx.Morph.js
3316	Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
3317
3318License:
3319	MIT-style license.
3320*/
3321
3322Fx.Morph = new Class({
3323
3324	Extends: Fx.CSS,
3325
3326	initialize: function(element, options){
3327		this.element = this.subject = $(element);
3328		this.parent(options);
3329	},
3330
3331	set: function(now){
3332		if (typeof now == 'string') now = this.search(now);
3333		for (var p in now) this.render(this.element, p, now[p], this.options.unit);
3334		return this;
3335	},
3336
3337	compute: function(from, to, delta){
3338		var now = {};
3339		for (var p in from) now[p] = this.parent(from[p], to[p], delta);
3340		return now;
3341	},
3342
3343	start: function(properties){
3344		if (!this.check(arguments.callee, properties)) return this;
3345		if (typeof properties == 'string') properties = this.search(properties);
3346		var from = {}, to = {};
3347		for (var p in properties){
3348			var parsed = this.prepare(this.element, p, properties[p]);
3349			from[p] = parsed.from;
3350			to[p] = parsed.to;
3351		}
3352		return this.parent(from, to);
3353	}
3354
3355});
3356
3357Element.Properties.morph = {
3358
3359	set: function(options){
3360		var morph = this.retrieve('morph');
3361		if (morph) morph.cancel();
3362		return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options));
3363	},
3364
3365	get: function(options){
3366		if (options || !this.retrieve('morph')){
3367			if (options || !this.retrieve('morph:options')) this.set('morph', options);
3368			this.store('morph', new Fx.Morph(this, this.retrieve('morph:options')));
3369		}
3370		return this.retrieve('morph');
3371	}
3372
3373};
3374
3375Element.implement({
3376
3377	morph: function(props){
3378		this.get('morph').start(props);
3379		return this;
3380	}
3381
3382});
3383
3384/*
3385Script: Fx.Transitions.js
3386	Contains a set of advanced transitions to be used with any of the Fx Classes.
3387
3388License:
3389	MIT-style license.
3390
3391Credits:
3392	Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
3393*/
3394
3395(function(){
3396
3397	var old = Fx.prototype.initialize;
3398
3399	Fx.prototype.initialize = function(options){
3400		old.call(this, options);
3401		var trans = this.options.transition;
3402		if (typeof trans == 'string' && (trans = trans.split(':'))){
3403			var base = Fx.Transitions;
3404			base = base[trans[0]] || base[trans[0].capitalize()];
3405			if (trans[1]) base = base['ease' + trans[1].capitalize() + (trans[2] ? trans[2].capitalize() : '')];
3406			this.options.transition = base;
3407		}
3408	};
3409
3410})();
3411
3412Fx.Transition = function(transition, params){
3413	params = $splat(params);
3414	return $extend(transition, {
3415		easeIn: function(pos){
3416			return transition(pos, params);
3417		},
3418		easeOut: function(pos){
3419			return 1 - transition(1 - pos, params);
3420		},
3421		easeInOut: function(pos){
3422			return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
3423		}
3424	});
3425};
3426
3427Fx.Transitions = new Hash({
3428
3429	linear: $arguments(0)
3430
3431});
3432
3433Fx.Transitions.extend = function(transitions){
3434	for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
3435};
3436
3437Fx.Transitions.extend({
3438
3439	Pow: function(p, x){
3440		return Math.pow(p, x[0] || 6);
3441	},
3442
3443	Expo: function(p){
3444		return Math.pow(2, 8 * (p - 1));
3445	},
3446
3447	Circ: function(p){
3448		return 1 - Math.sin(Math.acos(p));
3449	},
3450
3451	Sine: function(p){
3452		return 1 - Math.sin((1 - p) * Math.PI / 2);
3453	},
3454
3455	Back: function(p, x){
3456		x = x[0] || 1.618;
3457		return Math.pow(p, 2) * ((x + 1) * p - x);
3458	},
3459
3460	Bounce: function(p){
3461		var value;
3462		for (var a = 0, b = 1; 1; a += b, b /= 2){
3463			if (p >= (7 - 4 * a) / 11){
3464				value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
3465				break;
3466			}
3467		}
3468		return value;
3469	},
3470
3471	Elastic: function(p, x){
3472		return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
3473	}
3474
3475});
3476
3477['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
3478	Fx.Transitions[transition] = new Fx.Transition(function(p){
3479		return Math.pow(p, [i + 2]);
3480	});
3481});
3482
3483
3484/*
3485Script: Request.js
3486	Powerful all purpose Request Class. Uses XMLHTTPRequest.
3487
3488License:
3489	MIT-style license.
3490*/
3491
3492var Request = new Class({
3493
3494	Implements: [Chain, Events, Options],
3495
3496	options: {
3497		/*onRequest: $empty,
3498		onSuccess: $empty,
3499		onFailure: $empty,
3500		onException: $empty,*/
3501		url: '',
3502		data: '',
3503		headers: {
3504			'X-Requested-With': 'XMLHttpRequest',
3505			'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
3506		},
3507		async: true,
3508		format: false,
3509		method: 'post',
3510		link: 'ignore',
3511		isSuccess: null,
3512		emulation: true,
3513		urlEncoded: true,
3514		encoding: 'utf-8',
3515		evalScripts: false,
3516		evalResponse: false
3517	},
3518
3519	initialize: function(options){
3520		this.xhr = new Browser.Request();
3521		this.setOptions(options);
3522		this.options.isSuccess = this.options.isSuccess || this.isSuccess;
3523		this.headers = new Hash(this.options.headers);
3524	},
3525
3526	onStateChange: function(){
3527		if (this.xhr.readyState != 4 || !this.running) return;
3528		this.running = false;
3529		this.status = 0;
3530		$try(function(){
3531			this.status = this.xhr.status;
3532		}.bind(this));
3533		if (this.options.isSuccess.call(this, this.status)){
3534			this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
3535			this.success(this.response.text, this.response.xml);
3536		} else {
3537			this.response = {text: null, xml: null};
3538			this.failure();
3539		}
3540		this.xhr.onreadystatechange = $empty;
3541	},
3542
3543	isSuccess: function(){
3544		return ((this.status >= 200) && (this.status < 300));
3545	},
3546
3547	processScripts: function(text){
3548		if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
3549		return text.stripScripts(this.options.evalScripts);
3550	},
3551
3552	success: function(text, xml){
3553		this.onSuccess(this.processScripts(text), xml);
3554	},
3555	
3556	onSuccess: function(){
3557		this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
3558	},
3559	
3560	failure: function(){
3561		this.onFailure();
3562	},
3563
3564	onFailure: function(){
3565		this.fireEvent('complete').fireEvent('failure', this.xhr);
3566	},
3567
3568	setHeader: function(name, value){
3569		this.headers.set(name, value);
3570		return this;
3571	},
3572
3573	getHeader: function(name){
3574		return $try(function(){
3575			return this.xhr.getResponseHeader(name);
3576		}.bind(this));
3577	},
3578
3579	check: function(caller){
3580		if (!this.running) return true;
3581		switch (this.options.link){
3582			case 'cancel': this.cancel(); return true;
3583			case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false;
3584		}
3585		return false;
3586	},
3587
3588	send: function(options){
3589		if (!this.check(arguments.callee, options)) return this;
3590		this.running = true;
3591
3592		var type = $type(options);
3593		if (type == 'string' || type == 'element') options = {data: options};
3594
3595		var old = this.options;
3596		options = $extend({data: old.data, url: old.url, method: old.method}, options);
3597		var data = options.data, url = options.url, method = options.method;
3598
3599		switch ($type(data)){
3600			case 'element': data = $(data).toQueryString(); break;
3601			case 'object': case 'hash': data = Hash.toQueryString(data);
3602		}
3603
3604		if (this.options.format){
3605			var format = 'format=' + this.options.format;
3606			data = (data) ? format + '&' + data : format;
3607		}
3608
3609		if (this.options.emulation && ['put', 'delete'].contains(method)){
3610			var _method = '_method=' + method;
3611			data = (data) ? _method + '&' + data : _method;
3612			method = 'post';
3613		}
3614
3615		if (this.options.urlEncoded && method == 'post'){
3616			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
3617			this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
3618		}
3619
3620		if (data && method == 'get'){
3621			url = url + (url.contains('?') ? '&' : '?') + data;
3622			data = null;
3623		}
3624
3625		this.xhr.open(method.toUpperCase(), url, this.options.async);
3626
3627		this.xhr.onreadystatechange = this.onStateChange.bind(this);
3628
3629		this.headers.each(function(value, key){
3630			if (!$try(function(){
3631				this.xhr.setRequestHeader(key, value);
3632				return true;
3633			}.bind(this))) this.fireEvent('exception', [key, value]);
3634		}, this);
3635
3636		this.fireEvent('request');
3637		this.xhr.send(data);
3638		if (!this.options.async) this.onStateChange();
3639		return this;
3640	},
3641
3642	cancel: function(){
3643		if (!this.running) return this;
3644		this.running = false;
3645		this.xhr.abort();
3646		this.xhr.onreadystatechange = $empty;
3647		this.xhr = new Browser.Request();
3648		this.fireEvent('cancel');
3649		return this;
3650	}
3651
3652});
3653
3654(function(){
3655
3656var methods = {};
3657['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
3658	methods[method] = function(){
3659		var params = Array.link(arguments, {url: String.type, data: $defined});
3660		return this.send($extend(params, {method: method.toLowerCase()}));
3661	};
3662});
3663
3664Request.implement(methods);
3665
3666})();
3667
3668Element.Properties.send = {
3669	
3670	set: function(options){
3671		var send = this.retrieve('send');
3672		if (send) send.cancel();
3673		return this.eliminate('send').store('send:options', $extend({
3674			data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
3675		}, options));
3676	},
3677
3678	get: function(options){
3679		if (options || !this.retrieve('send')){
3680			if (options || !this.retrieve('send:options')) this.set('send', options);
3681			this.store('send', new Request(this.retrieve('send:options')));
3682		}
3683		return this.retrieve('send');
3684	}
3685
3686};
3687
3688Element.implement({
3689
3690	send: function(url){
3691		var sender = this.get('send');
3692		sender.send({data: this, url: url || sender.options.url});
3693		return this;
3694	}
3695
3696});
3697
3698
3699/*
3700Script: Request.HTML.js
3701	Extends the basic Request Class with additional methods for interacting with HTML responses.
3702
3703License:
3704	MIT-style license.
3705*/
3706
3707Request.HTML = new Class({
3708
3709	Extends: Request,
3710
3711	options: {
3712		update: false,
3713		evalScripts: true,
3714		filter: false
3715	},
3716
3717	processHTML: function(text){
3718		var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
3719		text = (match) ? match[1] : text;
3720		
3721		var container = new Element('div');
3722		
3723		return $try(function(){
3724			var root = '<root>' + text + '</root>', doc;
3725			if (Browser.Engine.trident){
3726				doc = new ActiveXObject('Microsoft.XMLDOM');
3727				doc.async = false;
3728				doc.loadXML(root);
3729			} else {
3730				doc = new DOMParser().parseFromString(root, 'text/xml');
3731			}
3732			root = doc.getElementsByTagName('root')[0];
3733			for (var i = 0, k = root.childNodes.length; i < k; i++){
3734				var child = Element.clone(root.childNodes[i], true, true);
3735				if (child) container.grab(child);
3736			}
3737			return container;
3738		}) || container.set('html', text);
3739	},
3740
3741	success: function(text){
3742		var options = this.options, response = this.response;
3743		
3744		response.html = text.stripScripts(function(script){
3745			response.javascript = script;
3746		});
3747		
3748		var temp = this.processHTML(response.html);
3749		
3750		response.tree = temp.childNodes;
3751		response.elements = temp.getElements('*');
3752		
3753		if (options.filter) response.tree = response.elements.filter(options.filter);
3754		if (options.update) $(options.update).empty().adopt(response.tree);
3755		if (options.evalScripts) $exec(response.javascript);
3756		
3757		this.onSuccess(response.tree, response.elements, response.html, response.javascript);
3758	}
3759
3760});
3761
3762Element.Properties.load = {
3763	
3764	set: function(options){
3765		var load = this.retrieve('load');
3766		if (load) send.cancel();
3767		return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options));
3768	},
3769
3770	get: function(options){
3771		if (options || ! this.retrieve('load')){
3772			if (options || !this.retrieve('load:options')) this.set('load', options);
3773			this.store('load', new Request.HTML(this.retrieve('load:options')));
3774		}
3775		return this.retrieve('load');
3776	}
3777
3778};
3779
3780Element.implement({
3781	
3782	load: function(){
3783		this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type}));
3784		return this;
3785	}
3786
3787});
3788
3789
3790/*
3791Script: Request.JSON.js
3792	Extends the basic Request Class with additional methods for sending and receiving JSON data.
3793
3794License:
3795	MIT-style license.
3796*/
3797
3798Request.JSON = new Class({
3799
3800	Extends: Request,
3801
3802	options: {
3803		secure: true
3804	},
3805
3806	initialize: function(options){
3807		this.parent(options);
3808		this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
3809	},
3810
3811	success: function(text){
3812		this.response.json = JSON.decode(text, this.options.secure);
3813		this.onSuccess(this.response.json, text);
3814	}
3815
3816});

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.