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