Home | History | Annotate | Download | only in test
      1 /*
      2 ---
      3 MooTools: the javascript framework
      4 
      5 web build:
      6  - http://mootools.net/core/8423c12ffd6a6bfcde9ea22554aec795
      7 
      8 packager build:
      9  - packager build Core/Core Core/Array Core/String Core/Number Core/Function Core/Object Core/Event Core/Browser Core/Class Core/Class.Extras Core/Slick.Parser Core/Slick.Finder Core/Element Core/Element.Style Core/Element.Event Core/Element.Delegation Core/Element.Dimensions Core/Fx Core/Fx.CSS Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/Request Core/Request.HTML Core/Request.JSON Core/Cookie Core/JSON Core/DOMReady
     10 
     11 ...
     12 */
     13 
     14 /*
     15 ---
     16 
     17 name: Core
     18 
     19 description: The heart of MooTools.
     20 
     21 license: MIT-style license.
     22 
     23 copyright: Copyright (c) 2006-2014 [Valerio Proietti](http://mad4milk.net/).
     24 
     25 authors: The MooTools production team (http://mootools.net/developers/)
     26 
     27 inspiration:
     28   - 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)
     29   - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
     30 
     31 provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
     32 
     33 ...
     34 */
     35 
     36 (function(){
     37 
     38 this.MooTools = {
     39 	version: '1.5.0',
     40 	build: '0f7b690afee9349b15909f33016a25d2e4d9f4e3'
     41 };
     42 
     43 // typeOf, instanceOf
     44 
     45 var typeOf = this.typeOf = function(item){
     46 	if (item == null) return 'null';
     47 	if (item.$family != null) return item.$family();
     48 
     49 	if (item.nodeName){
     50 		if (item.nodeType == 1) return 'element';
     51 		if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
     52 	} else if (typeof item.length == 'number'){
     53 		if ('callee' in item) return 'arguments';
     54 		if ('item' in item) return 'collection';
     55 	}
     56 
     57 	return typeof item;
     58 };
     59 
     60 var instanceOf = this.instanceOf = function(item, object){
     61 	if (item == null) return false;
     62 	var constructor = item.$constructor || item.constructor;
     63 	while (constructor){
     64 		if (constructor === object) return true;
     65 		constructor = constructor.parent;
     66 	}
     67 	/*<ltIE8>*/
     68 	if (!item.hasOwnProperty) return false;
     69 	/*</ltIE8>*/
     70 	return item instanceof object;
     71 };
     72 
     73 // Function overloading
     74 
     75 var Function = this.Function;
     76 
     77 var enumerables = true;
     78 for (var i in {toString: 1}) enumerables = null;
     79 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
     80 
     81 Function.prototype.overloadSetter = function(usePlural){
     82 	var self = this;
     83 	return function(a, b){
     84 		if (a == null) return this;
     85 		if (usePlural || typeof a != 'string'){
     86 			for (var k in a) self.call(this, k, a[k]);
     87 			if (enumerables) for (var i = enumerables.length; i--;){
     88 				k = enumerables[i];
     89 				if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
     90 			}
     91 		} else {
     92 			self.call(this, a, b);
     93 		}
     94 		return this;
     95 	};
     96 };
     97 
     98 Function.prototype.overloadGetter = function(usePlural){
     99 	var self = this;
    100 	return function(a){
    101 		var args, result;
    102 		if (typeof a != 'string') args = a;
    103 		else if (arguments.length > 1) args = arguments;
    104 		else if (usePlural) args = [a];
    105 		if (args){
    106 			result = {};
    107 			for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
    108 		} else {
    109 			result = self.call(this, a);
    110 		}
    111 		return result;
    112 	};
    113 };
    114 
    115 Function.prototype.extend = function(key, value){
    116 	this[key] = value;
    117 }.overloadSetter();
    118 
    119 Function.prototype.implement = function(key, value){
    120 	this.prototype[key] = value;
    121 }.overloadSetter();
    122 
    123 // From
    124 
    125 var slice = Array.prototype.slice;
    126 
    127 Function.from = function(item){
    128 	return (typeOf(item) == 'function') ? item : function(){
    129 		return item;
    130 	};
    131 };
    132 
    133 Array.from = function(item){
    134 	if (item == null) return [];
    135 	return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
    136 };
    137 
    138 Number.from = function(item){
    139 	var number = parseFloat(item);
    140 	return isFinite(number) ? number : null;
    141 };
    142 
    143 String.from = function(item){
    144 	return item + '';
    145 };
    146 
    147 // hide, protect
    148 
    149 Function.implement({
    150 
    151 	hide: function(){
    152 		this.$hidden = true;
    153 		return this;
    154 	},
    155 
    156 	protect: function(){
    157 		this.$protected = true;
    158 		return this;
    159 	}
    160 
    161 });
    162 
    163 // Type
    164 
    165 var Type = this.Type = function(name, object){
    166 	if (name){
    167 		var lower = name.toLowerCase();
    168 		var typeCheck = function(item){
    169 			return (typeOf(item) == lower);
    170 		};
    171 
    172 		Type['is' + name] = typeCheck;
    173 		if (object != null){
    174 			object.prototype.$family = (function(){
    175 				return lower;
    176 			}).hide();
    177 
    178 		}
    179 	}
    180 
    181 	if (object == null) return null;
    182 
    183 	object.extend(this);
    184 	object.$constructor = Type;
    185 	object.prototype.$constructor = object;
    186 
    187 	return object;
    188 };
    189 
    190 var toString = Object.prototype.toString;
    191 
    192 Type.isEnumerable = function(item){
    193 	return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
    194 };
    195 
    196 var hooks = {};
    197 
    198 var hooksOf = function(object){
    199 	var type = typeOf(object.prototype);
    200 	return hooks[type] || (hooks[type] = []);
    201 };
    202 
    203 var implement = function(name, method){
    204 	if (method && method.$hidden) return;
    205 
    206 	var hooks = hooksOf(this);
    207 
    208 	for (var i = 0; i < hooks.length; i++){
    209 		var hook = hooks[i];
    210 		if (typeOf(hook) == 'type') implement.call(hook, name, method);
    211 		else hook.call(this, name, method);
    212 	}
    213 
    214 	var previous = this.prototype[name];
    215 	if (previous == null || !previous.$protected) this.prototype[name] = method;
    216 
    217 	if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
    218 		return method.apply(item, slice.call(arguments, 1));
    219 	});
    220 };
    221 
    222 var extend = function(name, method){
    223 	if (method && method.$hidden) return;
    224 	var previous = this[name];
    225 	if (previous == null || !previous.$protected) this[name] = method;
    226 };
    227 
    228 Type.implement({
    229 
    230 	implement: implement.overloadSetter(),
    231 
    232 	extend: extend.overloadSetter(),
    233 
    234 	alias: function(name, existing){
    235 		implement.call(this, name, this.prototype[existing]);
    236 	}.overloadSetter(),
    237 
    238 	mirror: function(hook){
    239 		hooksOf(this).push(hook);
    240 		return this;
    241 	}
    242 
    243 });
    244 
    245 new Type('Type', Type);
    246 
    247 // Default Types
    248 
    249 var force = function(name, object, methods){
    250 	var isType = (object != Object),
    251 		prototype = object.prototype;
    252 
    253 	if (isType) object = new Type(name, object);
    254 
    255 	for (var i = 0, l = methods.length; i < l; i++){
    256 		var key = methods[i],
    257 			generic = object[key],
    258 			proto = prototype[key];
    259 
    260 		if (generic) generic.protect();
    261 		if (isType && proto) object.implement(key, proto.protect());
    262 	}
    263 
    264 	if (isType){
    265 		var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
    266 		object.forEachMethod = function(fn){
    267 			if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
    268 				fn.call(prototype, prototype[methods[i]], methods[i]);
    269 			}
    270 			for (var key in prototype) fn.call(prototype, prototype[key], key);
    271 		};
    272 	}
    273 
    274 	return force;
    275 };
    276 
    277 force('String', String, [
    278 	'charAt', 'charCodeAt', 'concat', 'contains', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
    279 	'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
    280 ])('Array', Array, [
    281 	'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
    282 	'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
    283 ])('Number', Number, [
    284 	'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
    285 ])('Function', Function, [
    286 	'apply', 'call', 'bind'
    287 ])('RegExp', RegExp, [
    288 	'exec', 'test'
    289 ])('Object', Object, [
    290 	'create', 'defineProperty', 'defineProperties', 'keys',
    291 	'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
    292 	'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
    293 ])('Date', Date, ['now']);
    294 
    295 Object.extend = extend.overloadSetter();
    296 
    297 Date.extend('now', function(){
    298 	return +(new Date);
    299 });
    300 
    301 new Type('Boolean', Boolean);
    302 
    303 // fixes NaN returning as Number
    304 
    305 Number.prototype.$family = function(){
    306 	return isFinite(this) ? 'number' : 'null';
    307 }.hide();
    308 
    309 // Number.random
    310 
    311 Number.extend('random', function(min, max){
    312 	return Math.floor(Math.random() * (max - min + 1) + min);
    313 });
    314 
    315 // forEach, each
    316 
    317 var hasOwnProperty = Object.prototype.hasOwnProperty;
    318 Object.extend('forEach', function(object, fn, bind){
    319 	for (var key in object){
    320 		if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
    321 	}
    322 });
    323 
    324 Object.each = Object.forEach;
    325 
    326 Array.implement({
    327 
    328 	/*<!ES5>*/
    329 	forEach: function(fn, bind){
    330 		for (var i = 0, l = this.length; i < l; i++){
    331 			if (i in this) fn.call(bind, this[i], i, this);
    332 		}
    333 	},
    334 	/*</!ES5>*/
    335 
    336 	each: function(fn, bind){
    337 		Array.forEach(this, fn, bind);
    338 		return this;
    339 	}
    340 
    341 });
    342 
    343 // Array & Object cloning, Object merging and appending
    344 
    345 var cloneOf = function(item){
    346 	switch (typeOf(item)){
    347 		case 'array': return item.clone();
    348 		case 'object': return Object.clone(item);
    349 		default: return item;
    350 	}
    351 };
    352 
    353 Array.implement('clone', function(){
    354 	var i = this.length, clone = new Array(i);
    355 	while (i--) clone[i] = cloneOf(this[i]);
    356 	return clone;
    357 });
    358 
    359 var mergeOne = function(source, key, current){
    360 	switch (typeOf(current)){
    361 		case 'object':
    362 			if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
    363 			else source[key] = Object.clone(current);
    364 		break;
    365 		case 'array': source[key] = current.clone(); break;
    366 		default: source[key] = current;
    367 	}
    368 	return source;
    369 };
    370 
    371 Object.extend({
    372 
    373 	merge: function(source, k, v){
    374 		if (typeOf(k) == 'string') return mergeOne(source, k, v);
    375 		for (var i = 1, l = arguments.length; i < l; i++){
    376 			var object = arguments[i];
    377 			for (var key in object) mergeOne(source, key, object[key]);
    378 		}
    379 		return source;
    380 	},
    381 
    382 	clone: function(object){
    383 		var clone = {};
    384 		for (var key in object) clone[key] = cloneOf(object[key]);
    385 		return clone;
    386 	},
    387 
    388 	append: function(original){
    389 		for (var i = 1, l = arguments.length; i < l; i++){
    390 			var extended = arguments[i] || {};
    391 			for (var key in extended) original[key] = extended[key];
    392 		}
    393 		return original;
    394 	}
    395 
    396 });
    397 
    398 // Object-less types
    399 
    400 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
    401 	new Type(name);
    402 });
    403 
    404 // Unique ID
    405 
    406 var UID = Date.now();
    407 
    408 String.extend('uniqueID', function(){
    409 	return (UID++).toString(36);
    410 });
    411 
    412 
    413 
    414 })();
    415 
    416 
    417 /*
    418 ---
    419 
    420 name: Array
    421 
    422 description: Contains Array Prototypes like each, contains, and erase.
    423 
    424 license: MIT-style license.
    425 
    426 requires: [Type]
    427 
    428 provides: Array
    429 
    430 ...
    431 */
    432 
    433 Array.implement({
    434 
    435 	/*<!ES5>*/
    436 	every: function(fn, bind){
    437 		for (var i = 0, l = this.length >>> 0; i < l; i++){
    438 			if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
    439 		}
    440 		return true;
    441 	},
    442 
    443 	filter: function(fn, bind){
    444 		var results = [];
    445 		for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
    446 			value = this[i];
    447 			if (fn.call(bind, value, i, this)) results.push(value);
    448 		}
    449 		return results;
    450 	},
    451 
    452 	indexOf: function(item, from){
    453 		var length = this.length >>> 0;
    454 		for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
    455 			if (this[i] === item) return i;
    456 		}
    457 		return -1;
    458 	},
    459 
    460 	map: function(fn, bind){
    461 		var length = this.length >>> 0, results = Array(length);
    462 		for (var i = 0; i < length; i++){
    463 			if (i in this) results[i] = fn.call(bind, this[i], i, this);
    464 		}
    465 		return results;
    466 	},
    467 
    468 	some: function(fn, bind){
    469 		for (var i = 0, l = this.length >>> 0; i < l; i++){
    470 			if ((i in this) && fn.call(bind, this[i], i, this)) return true;
    471 		}
    472 		return false;
    473 	},
    474 	/*</!ES5>*/
    475 
    476 	clean: function(){
    477 		return this.filter(function(item){
    478 			return item != null;
    479 		});
    480 	},
    481 
    482 	invoke: function(methodName){
    483 		var args = Array.slice(arguments, 1);
    484 		return this.map(function(item){
    485 			return item[methodName].apply(item, args);
    486 		});
    487 	},
    488 
    489 	associate: function(keys){
    490 		var obj = {}, length = Math.min(this.length, keys.length);
    491 		for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
    492 		return obj;
    493 	},
    494 
    495 	link: function(object){
    496 		var result = {};
    497 		for (var i = 0, l = this.length; i < l; i++){
    498 			for (var key in object){
    499 				if (object[key](this[i])){
    500 					result[key] = this[i];
    501 					delete object[key];
    502 					break;
    503 				}
    504 			}
    505 		}
    506 		return result;
    507 	},
    508 
    509 	contains: function(item, from){
    510 		return this.indexOf(item, from) != -1;
    511 	},
    512 
    513 	append: function(array){
    514 		this.push.apply(this, array);
    515 		return this;
    516 	},
    517 
    518 	getLast: function(){
    519 		return (this.length) ? this[this.length - 1] : null;
    520 	},
    521 
    522 	getRandom: function(){
    523 		return (this.length) ? this[Number.random(0, this.length - 1)] : null;
    524 	},
    525 
    526 	include: function(item){
    527 		if (!this.contains(item)) this.push(item);
    528 		return this;
    529 	},
    530 
    531 	combine: function(array){
    532 		for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
    533 		return this;
    534 	},
    535 
    536 	erase: function(item){
    537 		for (var i = this.length; i--;){
    538 			if (this[i] === item) this.splice(i, 1);
    539 		}
    540 		return this;
    541 	},
    542 
    543 	empty: function(){
    544 		this.length = 0;
    545 		return this;
    546 	},
    547 
    548 	flatten: function(){
    549 		var array = [];
    550 		for (var i = 0, l = this.length; i < l; i++){
    551 			var type = typeOf(this[i]);
    552 			if (type == 'null') continue;
    553 			array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
    554 		}
    555 		return array;
    556 	},
    557 
    558 	pick: function(){
    559 		for (var i = 0, l = this.length; i < l; i++){
    560 			if (this[i] != null) return this[i];
    561 		}
    562 		return null;
    563 	},
    564 
    565 	hexToRgb: function(array){
    566 		if (this.length != 3) return null;
    567 		var rgb = this.map(function(value){
    568 			if (value.length == 1) value += value;
    569 			return parseInt(value, 16);
    570 		});
    571 		return (array) ? rgb : 'rgb(' + rgb + ')';
    572 	},
    573 
    574 	rgbToHex: function(array){
    575 		if (this.length < 3) return null;
    576 		if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
    577 		var hex = [];
    578 		for (var i = 0; i < 3; i++){
    579 			var bit = (this[i] - 0).toString(16);
    580 			hex.push((bit.length == 1) ? '0' + bit : bit);
    581 		}
    582 		return (array) ? hex : '#' + hex.join('');
    583 	}
    584 
    585 });
    586 
    587 
    588 
    589 
    590 /*
    591 ---
    592 
    593 name: String
    594 
    595 description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
    596 
    597 license: MIT-style license.
    598 
    599 requires: [Type, Array]
    600 
    601 provides: String
    602 
    603 ...
    604 */
    605 
    606 String.implement({
    607 
    608 	//<!ES6>
    609 	contains: function(string, index){
    610 		return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1;
    611 	},
    612 	//</!ES6>
    613 
    614 	test: function(regex, params){
    615 		return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
    616 	},
    617 
    618 	trim: function(){
    619 		return String(this).replace(/^\s+|\s+$/g, '');
    620 	},
    621 
    622 	clean: function(){
    623 		return String(this).replace(/\s+/g, ' ').trim();
    624 	},
    625 
    626 	camelCase: function(){
    627 		return String(this).replace(/-\D/g, function(match){
    628 			return match.charAt(1).toUpperCase();
    629 		});
    630 	},
    631 
    632 	hyphenate: function(){
    633 		return String(this).replace(/[A-Z]/g, function(match){
    634 			return ('-' + match.charAt(0).toLowerCase());
    635 		});
    636 	},
    637 
    638 	capitalize: function(){
    639 		return String(this).replace(/\b[a-z]/g, function(match){
    640 			return match.toUpperCase();
    641 		});
    642 	},
    643 
    644 	escapeRegExp: function(){
    645 		return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
    646 	},
    647 
    648 	toInt: function(base){
    649 		return parseInt(this, base || 10);
    650 	},
    651 
    652 	toFloat: function(){
    653 		return parseFloat(this);
    654 	},
    655 
    656 	hexToRgb: function(array){
    657 		var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
    658 		return (hex) ? hex.slice(1).hexToRgb(array) : null;
    659 	},
    660 
    661 	rgbToHex: function(array){
    662 		var rgb = String(this).match(/\d{1,3}/g);
    663 		return (rgb) ? rgb.rgbToHex(array) : null;
    664 	},
    665 
    666 	substitute: function(object, regexp){
    667 		return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
    668 			if (match.charAt(0) == '\\') return match.slice(1);
    669 			return (object[name] != null) ? object[name] : '';
    670 		});
    671 	}
    672 
    673 });
    674 
    675 
    676 
    677 
    678 /*
    679 ---
    680 
    681 name: Number
    682 
    683 description: Contains Number Prototypes like limit, round, times, and ceil.
    684 
    685 license: MIT-style license.
    686 
    687 requires: Type
    688 
    689 provides: Number
    690 
    691 ...
    692 */
    693 
    694 Number.implement({
    695 
    696 	limit: function(min, max){
    697 		return Math.min(max, Math.max(min, this));
    698 	},
    699 
    700 	round: function(precision){
    701 		precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
    702 		return Math.round(this * precision) / precision;
    703 	},
    704 
    705 	times: function(fn, bind){
    706 		for (var i = 0; i < this; i++) fn.call(bind, i, this);
    707 	},
    708 
    709 	toFloat: function(){
    710 		return parseFloat(this);
    711 	},
    712 
    713 	toInt: function(base){
    714 		return parseInt(this, base || 10);
    715 	}
    716 
    717 });
    718 
    719 Number.alias('each', 'times');
    720 
    721 (function(math){
    722 	var methods = {};
    723 	math.each(function(name){
    724 		if (!Number[name]) methods[name] = function(){
    725 			return Math[name].apply(null, [this].concat(Array.from(arguments)));
    726 		};
    727 	});
    728 	Number.implement(methods);
    729 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
    730 
    731 
    732 /*
    733 ---
    734 
    735 name: Function
    736 
    737 description: Contains Function Prototypes like create, bind, pass, and delay.
    738 
    739 license: MIT-style license.
    740 
    741 requires: Type
    742 
    743 provides: Function
    744 
    745 ...
    746 */
    747 
    748 Function.extend({
    749 
    750 	attempt: function(){
    751 		for (var i = 0, l = arguments.length; i < l; i++){
    752 			try {
    753 				return arguments[i]();
    754 			} catch (e){}
    755 		}
    756 		return null;
    757 	}
    758 
    759 });
    760 
    761 Function.implement({
    762 
    763 	attempt: function(args, bind){
    764 		try {
    765 			return this.apply(bind, Array.from(args));
    766 		} catch (e){}
    767 
    768 		return null;
    769 	},
    770 
    771 	/*<!ES5-bind>*/
    772 	bind: function(that){
    773 		var self = this,
    774 			args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
    775 			F = function(){};
    776 
    777 		var bound = function(){
    778 			var context = that, length = arguments.length;
    779 			if (this instanceof bound){
    780 				F.prototype = self.prototype;
    781 				context = new F;
    782 			}
    783 			var result = (!args && !length)
    784 				? self.call(context)
    785 				: self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
    786 			return context == that ? result : context;
    787 		};
    788 		return bound;
    789 	},
    790 	/*</!ES5-bind>*/
    791 
    792 	pass: function(args, bind){
    793 		var self = this;
    794 		if (args != null) args = Array.from(args);
    795 		return function(){
    796 			return self.apply(bind, args || arguments);
    797 		};
    798 	},
    799 
    800 	delay: function(delay, bind, args){
    801 		return setTimeout(this.pass((args == null ? [] : args), bind), delay);
    802 	},
    803 
    804 	periodical: function(periodical, bind, args){
    805 		return setInterval(this.pass((args == null ? [] : args), bind), periodical);
    806 	}
    807 
    808 });
    809 
    810 
    811 
    812 
    813 /*
    814 ---
    815 
    816 name: Object
    817 
    818 description: Object generic methods
    819 
    820 license: MIT-style license.
    821 
    822 requires: Type
    823 
    824 provides: [Object, Hash]
    825 
    826 ...
    827 */
    828 
    829 (function(){
    830 
    831 var hasOwnProperty = Object.prototype.hasOwnProperty;
    832 
    833 Object.extend({
    834 
    835 	subset: function(object, keys){
    836 		var results = {};
    837 		for (var i = 0, l = keys.length; i < l; i++){
    838 			var k = keys[i];
    839 			if (k in object) results[k] = object[k];
    840 		}
    841 		return results;
    842 	},
    843 
    844 	map: function(object, fn, bind){
    845 		var results = {};
    846 		for (var key in object){
    847 			if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
    848 		}
    849 		return results;
    850 	},
    851 
    852 	filter: function(object, fn, bind){
    853 		var results = {};
    854 		for (var key in object){
    855 			var value = object[key];
    856 			if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
    857 		}
    858 		return results;
    859 	},
    860 
    861 	every: function(object, fn, bind){
    862 		for (var key in object){
    863 			if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
    864 		}
    865 		return true;
    866 	},
    867 
    868 	some: function(object, fn, bind){
    869 		for (var key in object){
    870 			if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
    871 		}
    872 		return false;
    873 	},
    874 
    875 	keys: function(object){
    876 		var keys = [];
    877 		for (var key in object){
    878 			if (hasOwnProperty.call(object, key)) keys.push(key);
    879 		}
    880 		return keys;
    881 	},
    882 
    883 	values: function(object){
    884 		var values = [];
    885 		for (var key in object){
    886 			if (hasOwnProperty.call(object, key)) values.push(object[key]);
    887 		}
    888 		return values;
    889 	},
    890 
    891 	getLength: function(object){
    892 		return Object.keys(object).length;
    893 	},
    894 
    895 	keyOf: function(object, value){
    896 		for (var key in object){
    897 			if (hasOwnProperty.call(object, key) && object[key] === value) return key;
    898 		}
    899 		return null;
    900 	},
    901 
    902 	contains: function(object, value){
    903 		return Object.keyOf(object, value) != null;
    904 	},
    905 
    906 	toQueryString: function(object, base){
    907 		var queryString = [];
    908 
    909 		Object.each(object, function(value, key){
    910 			if (base) key = base + '[' + key + ']';
    911 			var result;
    912 			switch (typeOf(value)){
    913 				case 'object': result = Object.toQueryString(value, key); break;
    914 				case 'array':
    915 					var qs = {};
    916 					value.each(function(val, i){
    917 						qs[i] = val;
    918 					});
    919 					result = Object.toQueryString(qs, key);
    920 				break;
    921 				default: result = key + '=' + encodeURIComponent(value);
    922 			}
    923 			if (value != null) queryString.push(result);
    924 		});
    925 
    926 		return queryString.join('&');
    927 	}
    928 
    929 });
    930 
    931 })();
    932 
    933 
    934 
    935 
    936 /*
    937 ---
    938 
    939 name: Browser
    940 
    941 description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
    942 
    943 license: MIT-style license.
    944 
    945 requires: [Array, Function, Number, String]
    946 
    947 provides: [Browser, Window, Document]
    948 
    949 ...
    950 */
    951 
    952 (function(){
    953 
    954 var document = this.document;
    955 var window = document.window = this;
    956 
    957 var parse = function(ua, platform){
    958 	ua = ua.toLowerCase();
    959 	platform = (platform ? platform.toLowerCase() : '');
    960 
    961 	var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0];
    962 
    963 	if (UA[1] == 'trident'){
    964 		UA[1] = 'ie';
    965 		if (UA[4]) UA[2] = UA[4];
    966 	} else if (UA[1] == 'crios') {
    967 		UA[1] = 'chrome';
    968 	}
    969 
    970 	var platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0];
    971 	if (platform == 'win') platform = 'windows';
    972 
    973 	return {
    974 		extend: Function.prototype.extend,
    975 		name: (UA[1] == 'version') ? UA[3] : UA[1],
    976 		version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
    977 		platform: platform
    978 	};
    979 };
    980 
    981 var Browser = this.Browser = parse(navigator.userAgent, navigator.platform);
    982 
    983 if (Browser.ie){
    984 	Browser.version = document.documentMode;
    985 }
    986 
    987 Browser.extend({
    988 	Features: {
    989 		xpath: !!(document.evaluate),
    990 		air: !!(window.runtime),
    991 		query: !!(document.querySelector),
    992 		json: !!(window.JSON)
    993 	},
    994 	parseUA: parse
    995 });
    996 
    997 
    998 
    999 // Request
   1000 
   1001 Browser.Request = (function(){
   1002 
   1003 	var XMLHTTP = function(){
   1004 		return new XMLHttpRequest();
   1005 	};
   1006 
   1007 	var MSXML2 = function(){
   1008 		return new ActiveXObject('MSXML2.XMLHTTP');
   1009 	};
   1010 
   1011 	var MSXML = function(){
   1012 		return new ActiveXObject('Microsoft.XMLHTTP');
   1013 	};
   1014 
   1015 	return Function.attempt(function(){
   1016 		XMLHTTP();
   1017 		return XMLHTTP;
   1018 	}, function(){
   1019 		MSXML2();
   1020 		return MSXML2;
   1021 	}, function(){
   1022 		MSXML();
   1023 		return MSXML;
   1024 	});
   1025 
   1026 })();
   1027 
   1028 Browser.Features.xhr = !!(Browser.Request);
   1029 
   1030 
   1031 
   1032 // String scripts
   1033 
   1034 Browser.exec = function(text){
   1035 	if (!text) return text;
   1036 	if (window.execScript){
   1037 		window.execScript(text);
   1038 	} else {
   1039 		var script = document.createElement('script');
   1040 		script.setAttribute('type', 'text/javascript');
   1041 		script.text = text;
   1042 		document.head.appendChild(script);
   1043 		document.head.removeChild(script);
   1044 	}
   1045 	return text;
   1046 };
   1047 
   1048 String.implement('stripScripts', function(exec){
   1049 	var scripts = '';
   1050 	var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
   1051 		scripts += code + '\n';
   1052 		return '';
   1053 	});
   1054 	if (exec === true) Browser.exec(scripts);
   1055 	else if (typeOf(exec) == 'function') exec(scripts, text);
   1056 	return text;
   1057 });
   1058 
   1059 // Window, Document
   1060 
   1061 Browser.extend({
   1062 	Document: this.Document,
   1063 	Window: this.Window,
   1064 	Element: this.Element,
   1065 	Event: this.Event
   1066 });
   1067 
   1068 this.Window = this.$constructor = new Type('Window', function(){});
   1069 
   1070 this.$family = Function.from('window').hide();
   1071 
   1072 Window.mirror(function(name, method){
   1073 	window[name] = method;
   1074 });
   1075 
   1076 this.Document = document.$constructor = new Type('Document', function(){});
   1077 
   1078 document.$family = Function.from('document').hide();
   1079 
   1080 Document.mirror(function(name, method){
   1081 	document[name] = method;
   1082 });
   1083 
   1084 document.html = document.documentElement;
   1085 if (!document.head) document.head = document.getElementsByTagName('head')[0];
   1086 
   1087 if (document.execCommand) try {
   1088 	document.execCommand("BackgroundImageCache", false, true);
   1089 } catch (e){}
   1090 
   1091 /*<ltIE9>*/
   1092 if (this.attachEvent && !this.addEventListener){
   1093 	var unloadEvent = function(){
   1094 		this.detachEvent('onunload', unloadEvent);
   1095 		document.head = document.html = document.window = null;
   1096 	};
   1097 	this.attachEvent('onunload', unloadEvent);
   1098 }
   1099 
   1100 // IE fails on collections and <select>.options (refers to <select>)
   1101 var arrayFrom = Array.from;
   1102 try {
   1103 	arrayFrom(document.html.childNodes);
   1104 } catch(e){
   1105 	Array.from = function(item){
   1106 		if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
   1107 			var i = item.length, array = new Array(i);
   1108 			while (i--) array[i] = item[i];
   1109 			return array;
   1110 		}
   1111 		return arrayFrom(item);
   1112 	};
   1113 
   1114 	var prototype = Array.prototype,
   1115 		slice = prototype.slice;
   1116 	['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
   1117 		var method = prototype[name];
   1118 		Array[name] = function(item){
   1119 			return method.apply(Array.from(item), slice.call(arguments, 1));
   1120 		};
   1121 	});
   1122 }
   1123 /*</ltIE9>*/
   1124 
   1125 
   1126 
   1127 })();
   1128 
   1129 
   1130 /*
   1131 ---
   1132 
   1133 name: Event
   1134 
   1135 description: Contains the Event Type, to make the event object cross-browser.
   1136 
   1137 license: MIT-style license.
   1138 
   1139 requires: [Window, Document, Array, Function, String, Object]
   1140 
   1141 provides: Event
   1142 
   1143 ...
   1144 */
   1145 
   1146 (function() {
   1147 
   1148 var _keys = {};
   1149 
   1150 var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){
   1151 	if (!win) win = window;
   1152 	event = event || win.event;
   1153 	if (event.$extended) return event;
   1154 	this.event = event;
   1155 	this.$extended = true;
   1156 	this.shift = event.shiftKey;
   1157 	this.control = event.ctrlKey;
   1158 	this.alt = event.altKey;
   1159 	this.meta = event.metaKey;
   1160 	var type = this.type = event.type;
   1161 	var target = event.target || event.srcElement;
   1162 	while (target && target.nodeType == 3) target = target.parentNode;
   1163 	this.target = document.id(target);
   1164 
   1165 	if (type.indexOf('key') == 0){
   1166 		var code = this.code = (event.which || event.keyCode);
   1167 		this.key = _keys[code];
   1168 		if (type == 'keydown' || type == 'keyup'){
   1169 			if (code > 111 && code < 124) this.key = 'f' + (code - 111);
   1170 			else if (code > 95 && code < 106) this.key = code - 96;
   1171 		}
   1172 		if (this.key == null) this.key = String.fromCharCode(code).toLowerCase();
   1173 	} else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){
   1174 		var doc = win.document;
   1175 		doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
   1176 		this.page = {
   1177 			x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
   1178 			y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop
   1179 		};
   1180 		this.client = {
   1181 			x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
   1182 			y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
   1183 		};
   1184 		if (type == 'DOMMouseScroll' || type == 'mousewheel')
   1185 			this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
   1186 
   1187 		this.rightClick = (event.which == 3 || event.button == 2);
   1188 		if (type == 'mouseover' || type == 'mouseout'){
   1189 			var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
   1190 			while (related && related.nodeType == 3) related = related.parentNode;
   1191 			this.relatedTarget = document.id(related);
   1192 		}
   1193 	} else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){
   1194 		this.rotation = event.rotation;
   1195 		this.scale = event.scale;
   1196 		this.targetTouches = event.targetTouches;
   1197 		this.changedTouches = event.changedTouches;
   1198 		var touches = this.touches = event.touches;
   1199 		if (touches && touches[0]){
   1200 			var touch = touches[0];
   1201 			this.page = {x: touch.pageX, y: touch.pageY};
   1202 			this.client = {x: touch.clientX, y: touch.clientY};
   1203 		}
   1204 	}
   1205 
   1206 	if (!this.client) this.client = {};
   1207 	if (!this.page) this.page = {};
   1208 });
   1209 
   1210 DOMEvent.implement({
   1211 
   1212 	stop: function(){
   1213 		return this.preventDefault().stopPropagation();
   1214 	},
   1215 
   1216 	stopPropagation: function(){
   1217 		if (this.event.stopPropagation) this.event.stopPropagation();
   1218 		else this.event.cancelBubble = true;
   1219 		return this;
   1220 	},
   1221 
   1222 	preventDefault: function(){
   1223 		if (this.event.preventDefault) this.event.preventDefault();
   1224 		else this.event.returnValue = false;
   1225 		return this;
   1226 	}
   1227 
   1228 });
   1229 
   1230 DOMEvent.defineKey = function(code, key){
   1231 	_keys[code] = key;
   1232 	return this;
   1233 };
   1234 
   1235 DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true);
   1236 
   1237 DOMEvent.defineKeys({
   1238 	'38': 'up', '40': 'down', '37': 'left', '39': 'right',
   1239 	'27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab',
   1240 	'46': 'delete', '13': 'enter'
   1241 });
   1242 
   1243 })();
   1244 
   1245 
   1246 
   1247 
   1248 
   1249 
   1250 /*
   1251 ---
   1252 
   1253 name: Class
   1254 
   1255 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
   1256 
   1257 license: MIT-style license.
   1258 
   1259 requires: [Array, String, Function, Number]
   1260 
   1261 provides: Class
   1262 
   1263 ...
   1264 */
   1265 
   1266 (function(){
   1267 
   1268 var Class = this.Class = new Type('Class', function(params){
   1269 	if (instanceOf(params, Function)) params = {initialize: params};
   1270 
   1271 	var newClass = function(){
   1272 		reset(this);
   1273 		if (newClass.$prototyping) return this;
   1274 		this.$caller = null;
   1275 		var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
   1276 		this.$caller = this.caller = null;
   1277 		return value;
   1278 	}.extend(this).implement(params);
   1279 
   1280 	newClass.$constructor = Class;
   1281 	newClass.prototype.$constructor = newClass;
   1282 	newClass.prototype.parent = parent;
   1283 
   1284 	return newClass;
   1285 });
   1286 
   1287 var parent = function(){
   1288 	if (!this.$caller) throw new Error('The method "parent" cannot be called.');
   1289 	var name = this.$caller.$name,
   1290 		parent = this.$caller.$owner.parent,
   1291 		previous = (parent) ? parent.prototype[name] : null;
   1292 	if (!previous) throw new Error('The method "' + name + '" has no parent.');
   1293 	return previous.apply(this, arguments);
   1294 };
   1295 
   1296 var reset = function(object){
   1297 	for (var key in object){
   1298 		var value = object[key];
   1299 		switch (typeOf(value)){
   1300 			case 'object':
   1301 				var F = function(){};
   1302 				F.prototype = value;
   1303 				object[key] = reset(new F);
   1304 			break;
   1305 			case 'array': object[key] = value.clone(); break;
   1306 		}
   1307 	}
   1308 	return object;
   1309 };
   1310 
   1311 var wrap = function(self, key, method){
   1312 	if (method.$origin) method = method.$origin;
   1313 	var wrapper = function(){
   1314 		if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
   1315 		var caller = this.caller, current = this.$caller;
   1316 		this.caller = current; this.$caller = wrapper;
   1317 		var result = method.apply(this, arguments);
   1318 		this.$caller = current; this.caller = caller;
   1319 		return result;
   1320 	}.extend({$owner: self, $origin: method, $name: key});
   1321 	return wrapper;
   1322 };
   1323 
   1324 var implement = function(key, value, retain){
   1325 	if (Class.Mutators.hasOwnProperty(key)){
   1326 		value = Class.Mutators[key].call(this, value);
   1327 		if (value == null) return this;
   1328 	}
   1329 
   1330 	if (typeOf(value) == 'function'){
   1331 		if (value.$hidden) return this;
   1332 		this.prototype[key] = (retain) ? value : wrap(this, key, value);
   1333 	} else {
   1334 		Object.merge(this.prototype, key, value);
   1335 	}
   1336 
   1337 	return this;
   1338 };
   1339 
   1340 var getInstance = function(klass){
   1341 	klass.$prototyping = true;
   1342 	var proto = new klass;
   1343 	delete klass.$prototyping;
   1344 	return proto;
   1345 };
   1346 
   1347 Class.implement('implement', implement.overloadSetter());
   1348 
   1349 Class.Mutators = {
   1350 
   1351 	Extends: function(parent){
   1352 		this.parent = parent;
   1353 		this.prototype = getInstance(parent);
   1354 	},
   1355 
   1356 	Implements: function(items){
   1357 		Array.from(items).each(function(item){
   1358 			var instance = new item;
   1359 			for (var key in instance) implement.call(this, key, instance[key], true);
   1360 		}, this);
   1361 	}
   1362 };
   1363 
   1364 })();
   1365 
   1366 
   1367 /*
   1368 ---
   1369 
   1370 name: Class.Extras
   1371 
   1372 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
   1373 
   1374 license: MIT-style license.
   1375 
   1376 requires: Class
   1377 
   1378 provides: [Class.Extras, Chain, Events, Options]
   1379 
   1380 ...
   1381 */
   1382 
   1383 (function(){
   1384 
   1385 this.Chain = new Class({
   1386 
   1387 	$chain: [],
   1388 
   1389 	chain: function(){
   1390 		this.$chain.append(Array.flatten(arguments));
   1391 		return this;
   1392 	},
   1393 
   1394 	callChain: function(){
   1395 		return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
   1396 	},
   1397 
   1398 	clearChain: function(){
   1399 		this.$chain.empty();
   1400 		return this;
   1401 	}
   1402 
   1403 });
   1404 
   1405 var removeOn = function(string){
   1406 	return string.replace(/^on([A-Z])/, function(full, first){
   1407 		return first.toLowerCase();
   1408 	});
   1409 };
   1410 
   1411 this.Events = new Class({
   1412 
   1413 	$events: {},
   1414 
   1415 	addEvent: function(type, fn, internal){
   1416 		type = removeOn(type);
   1417 
   1418 
   1419 
   1420 		this.$events[type] = (this.$events[type] || []).include(fn);
   1421 		if (internal) fn.internal = true;
   1422 		return this;
   1423 	},
   1424 
   1425 	addEvents: function(events){
   1426 		for (var type in events) this.addEvent(type, events[type]);
   1427 		return this;
   1428 	},
   1429 
   1430 	fireEvent: function(type, args, delay){
   1431 		type = removeOn(type);
   1432 		var events = this.$events[type];
   1433 		if (!events) return this;
   1434 		args = Array.from(args);
   1435 		events.each(function(fn){
   1436 			if (delay) fn.delay(delay, this, args);
   1437 			else fn.apply(this, args);
   1438 		}, this);
   1439 		return this;
   1440 	},
   1441 
   1442 	removeEvent: function(type, fn){
   1443 		type = removeOn(type);
   1444 		var events = this.$events[type];
   1445 		if (events && !fn.internal){
   1446 			var index =  events.indexOf(fn);
   1447 			if (index != -1) delete events[index];
   1448 		}
   1449 		return this;
   1450 	},
   1451 
   1452 	removeEvents: function(events){
   1453 		var type;
   1454 		if (typeOf(events) == 'object'){
   1455 			for (type in events) this.removeEvent(type, events[type]);
   1456 			return this;
   1457 		}
   1458 		if (events) events = removeOn(events);
   1459 		for (type in this.$events){
   1460 			if (events && events != type) continue;
   1461 			var fns = this.$events[type];
   1462 			for (var i = fns.length; i--;) if (i in fns){
   1463 				this.removeEvent(type, fns[i]);
   1464 			}
   1465 		}
   1466 		return this;
   1467 	}
   1468 
   1469 });
   1470 
   1471 this.Options = new Class({
   1472 
   1473 	setOptions: function(){
   1474 		var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
   1475 		if (this.addEvent) for (var option in options){
   1476 			if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
   1477 			this.addEvent(option, options[option]);
   1478 			delete options[option];
   1479 		}
   1480 		return this;
   1481 	}
   1482 
   1483 });
   1484 
   1485 })();
   1486 
   1487 
   1488 /*
   1489 ---
   1490 name: Slick.Parser
   1491 description: Standalone CSS3 Selector parser
   1492 provides: Slick.Parser
   1493 ...
   1494 */
   1495 
   1496 ;(function(){
   1497 
   1498 var parsed,
   1499 	separatorIndex,
   1500 	combinatorIndex,
   1501 	reversed,
   1502 	cache = {},
   1503 	reverseCache = {},
   1504 	reUnescape = /\\/g;
   1505 
   1506 var parse = function(expression, isReversed){
   1507 	if (expression == null) return null;
   1508 	if (expression.Slick === true) return expression;
   1509 	expression = ('' + expression).replace(/^\s+|\s+$/g, '');
   1510 	reversed = !!isReversed;
   1511 	var currentCache = (reversed) ? reverseCache : cache;
   1512 	if (currentCache[expression]) return currentCache[expression];
   1513 	parsed = {
   1514 		Slick: true,
   1515 		expressions: [],
   1516 		raw: expression,
   1517 		reverse: function(){
   1518 			return parse(this.raw, true);
   1519 		}
   1520 	};
   1521 	separatorIndex = -1;
   1522 	while (expression != (expression = expression.replace(regexp, parser)));
   1523 	parsed.length = parsed.expressions.length;
   1524 	return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
   1525 };
   1526 
   1527 var reverseCombinator = function(combinator){
   1528 	if (combinator === '!') return ' ';
   1529 	else if (combinator === ' ') return '!';
   1530 	else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
   1531 	else return '!' + combinator;
   1532 };
   1533 
   1534 var reverse = function(expression){
   1535 	var expressions = expression.expressions;
   1536 	for (var i = 0; i < expressions.length; i++){
   1537 		var exp = expressions[i];
   1538 		var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
   1539 
   1540 		for (var j = 0; j < exp.length; j++){
   1541 			var cexp = exp[j];
   1542 			if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
   1543 			cexp.combinator = cexp.reverseCombinator;
   1544 			delete cexp.reverseCombinator;
   1545 		}
   1546 
   1547 		exp.reverse().push(last);
   1548 	}
   1549 	return expression;
   1550 };
   1551 
   1552 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
   1553 	return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
   1554 		return '\\' + match;
   1555 	});
   1556 };
   1557 
   1558 var regexp = new RegExp(
   1559 /*
   1560 #!/usr/bin/env ruby
   1561 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
   1562 __END__
   1563 	"(?x)^(?:\
   1564 	  \\s* ( , ) \\s*               # Separator          \n\
   1565 	| \\s* ( <combinator>+ ) \\s*   # Combinator         \n\
   1566 	|      ( \\s+ )                 # CombinatorChildren \n\
   1567 	|      ( <unicode>+ | \\* )     # Tag                \n\
   1568 	| \\#  ( <unicode>+       )     # ID                 \n\
   1569 	| \\.  ( <unicode>+       )     # ClassName          \n\
   1570 	|                               # Attribute          \n\
   1571 	\\[  \
   1572 		\\s* (<unicode1>+)  (?:  \
   1573 			\\s* ([*^$!~|]?=)  (?:  \
   1574 				\\s* (?:\
   1575 					([\"']?)(.*?)\\9 \
   1576 				)\
   1577 			)  \
   1578 		)?  \\s*  \
   1579 	\\](?!\\]) \n\
   1580 	|   :+ ( <unicode>+ )(?:\
   1581 	\\( (?:\
   1582 		(?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
   1583 	) \\)\
   1584 	)?\
   1585 	)"
   1586 */
   1587 	"^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
   1588 	.replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
   1589 	.replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
   1590 	.replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
   1591 );
   1592 
   1593 function parser(
   1594 	rawMatch,
   1595 
   1596 	separator,
   1597 	combinator,
   1598 	combinatorChildren,
   1599 
   1600 	tagName,
   1601 	id,
   1602 	className,
   1603 
   1604 	attributeKey,
   1605 	attributeOperator,
   1606 	attributeQuote,
   1607 	attributeValue,
   1608 
   1609 	pseudoMarker,
   1610 	pseudoClass,
   1611 	pseudoQuote,
   1612 	pseudoClassQuotedValue,
   1613 	pseudoClassValue
   1614 ){
   1615 	if (separator || separatorIndex === -1){
   1616 		parsed.expressions[++separatorIndex] = [];
   1617 		combinatorIndex = -1;
   1618 		if (separator) return '';
   1619 	}
   1620 
   1621 	if (combinator || combinatorChildren || combinatorIndex === -1){
   1622 		combinator = combinator || ' ';
   1623 		var currentSeparator = parsed.expressions[separatorIndex];
   1624 		if (reversed && currentSeparator[combinatorIndex])
   1625 			currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
   1626 		currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
   1627 	}
   1628 
   1629 	var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
   1630 
   1631 	if (tagName){
   1632 		currentParsed.tag = tagName.replace(reUnescape, '');
   1633 
   1634 	} else if (id){
   1635 		currentParsed.id = id.replace(reUnescape, '');
   1636 
   1637 	} else if (className){
   1638 		className = className.replace(reUnescape, '');
   1639 
   1640 		if (!currentParsed.classList) currentParsed.classList = [];
   1641 		if (!currentParsed.classes) currentParsed.classes = [];
   1642 		currentParsed.classList.push(className);
   1643 		currentParsed.classes.push({
   1644 			value: className,
   1645 			regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
   1646 		});
   1647 
   1648 	} else if (pseudoClass){
   1649 		pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
   1650 		pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
   1651 
   1652 		if (!currentParsed.pseudos) currentParsed.pseudos = [];
   1653 		currentParsed.pseudos.push({
   1654 			key: pseudoClass.replace(reUnescape, ''),
   1655 			value: pseudoClassValue,
   1656 			type: pseudoMarker.length == 1 ? 'class' : 'element'
   1657 		});
   1658 
   1659 	} else if (attributeKey){
   1660 		attributeKey = attributeKey.replace(reUnescape, '');
   1661 		attributeValue = (attributeValue || '').replace(reUnescape, '');
   1662 
   1663 		var test, regexp;
   1664 
   1665 		switch (attributeOperator){
   1666 			case '^=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue)            ); break;
   1667 			case '$=' : regexp = new RegExp(            escapeRegExp(attributeValue) +'$'       ); break;
   1668 			case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
   1669 			case '|=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue) +'(-|$)'   ); break;
   1670 			case  '=' : test = function(value){
   1671 				return attributeValue == value;
   1672 			}; break;
   1673 			case '*=' : test = function(value){
   1674 				return value && value.indexOf(attributeValue) > -1;
   1675 			}; break;
   1676 			case '!=' : test = function(value){
   1677 				return attributeValue != value;
   1678 			}; break;
   1679 			default   : test = function(value){
   1680 				return !!value;
   1681 			};
   1682 		}
   1683 
   1684 		if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
   1685 			return false;
   1686 		};
   1687 
   1688 		if (!test) test = function(value){
   1689 			return value && regexp.test(value);
   1690 		};
   1691 
   1692 		if (!currentParsed.attributes) currentParsed.attributes = [];
   1693 		currentParsed.attributes.push({
   1694 			key: attributeKey,
   1695 			operator: attributeOperator,
   1696 			value: attributeValue,
   1697 			test: test
   1698 		});
   1699 
   1700 	}
   1701 
   1702 	return '';
   1703 };
   1704 
   1705 // Slick NS
   1706 
   1707 var Slick = (this.Slick || {});
   1708 
   1709 Slick.parse = function(expression){
   1710 	return parse(expression);
   1711 };
   1712 
   1713 Slick.escapeRegExp = escapeRegExp;
   1714 
   1715 if (!this.Slick) this.Slick = Slick;
   1716 
   1717 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
   1718 
   1719 
   1720 /*
   1721 ---
   1722 name: Slick.Finder
   1723 description: The new, superfast css selector engine.
   1724 provides: Slick.Finder
   1725 requires: Slick.Parser
   1726 ...
   1727 */
   1728 
   1729 ;(function(){
   1730 
   1731 var local = {},
   1732 	featuresCache = {},
   1733 	toString = Object.prototype.toString;
   1734 
   1735 // Feature / Bug detection
   1736 
   1737 local.isNativeCode = function(fn){
   1738 	return (/\{\s*\[native code\]\s*\}/).test('' + fn);
   1739 };
   1740 
   1741 local.isXML = function(document){
   1742 	return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') ||
   1743 	(document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
   1744 };
   1745 
   1746 local.setDocument = function(document){
   1747 
   1748 	// convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
   1749 	var nodeType = document.nodeType;
   1750 	if (nodeType == 9); // document
   1751 	else if (nodeType) document = document.ownerDocument; // node
   1752 	else if (document.navigator) document = document.document; // window
   1753 	else return;
   1754 
   1755 	// check if it's the old document
   1756 
   1757 	if (this.document === document) return;
   1758 	this.document = document;
   1759 
   1760 	// check if we have done feature detection on this document before
   1761 
   1762 	var root = document.documentElement,
   1763 		rootUid = this.getUIDXML(root),
   1764 		features = featuresCache[rootUid],
   1765 		feature;
   1766 
   1767 	if (features){
   1768 		for (feature in features){
   1769 			this[feature] = features[feature];
   1770 		}
   1771 		return;
   1772 	}
   1773 
   1774 	features = featuresCache[rootUid] = {};
   1775 
   1776 	features.root = root;
   1777 	features.isXMLDocument = this.isXML(document);
   1778 
   1779 	features.brokenStarGEBTN
   1780 	= features.starSelectsClosedQSA
   1781 	= features.idGetsName
   1782 	= features.brokenMixedCaseQSA
   1783 	= features.brokenGEBCN
   1784 	= features.brokenCheckedQSA
   1785 	= features.brokenEmptyAttributeQSA
   1786 	= features.isHTMLDocument
   1787 	= features.nativeMatchesSelector
   1788 	= false;
   1789 
   1790 	var starSelectsClosed, starSelectsComments,
   1791 		brokenSecondClassNameGEBCN, cachedGetElementsByClassName,
   1792 		brokenFormAttributeGetter;
   1793 
   1794 	var selected, id = 'slick_uniqueid';
   1795 	var testNode = document.createElement('div');
   1796 
   1797 	var testRoot = document.body || document.getElementsByTagName('body')[0] || root;
   1798 	testRoot.appendChild(testNode);
   1799 
   1800 	// on non-HTML documents innerHTML and getElementsById doesnt work properly
   1801 	try {
   1802 		testNode.innerHTML = '<a id="'+id+'"></a>';
   1803 		features.isHTMLDocument = !!document.getElementById(id);
   1804 	} catch(e){};
   1805 
   1806 	if (features.isHTMLDocument){
   1807 
   1808 		testNode.style.display = 'none';
   1809 
   1810 		// IE returns comment nodes for getElementsByTagName('*') for some documents
   1811 		testNode.appendChild(document.createComment(''));
   1812 		starSelectsComments = (testNode.getElementsByTagName('*').length > 1);
   1813 
   1814 		// IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
   1815 		try {
   1816 			testNode.innerHTML = 'foo</foo>';
   1817 			selected = testNode.getElementsByTagName('*');
   1818 			starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
   1819 		} catch(e){};
   1820 
   1821 		features.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
   1822 
   1823 		// IE returns elements with the name instead of just id for getElementsById for some documents
   1824 		try {
   1825 			testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>';
   1826 			features.idGetsName = document.getElementById(id) === testNode.firstChild;
   1827 		} catch(e){};
   1828 
   1829 		if (testNode.getElementsByClassName){
   1830 
   1831 			// Safari 3.2 getElementsByClassName caches results
   1832 			try {
   1833 				testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
   1834 				testNode.getElementsByClassName('b').length;
   1835 				testNode.firstChild.className = 'b';
   1836 				cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
   1837 			} catch(e){};
   1838 
   1839 			// Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
   1840 			try {
   1841 				testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
   1842 				brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
   1843 			} catch(e){};
   1844 
   1845 			features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
   1846 		}
   1847 
   1848 		if (testNode.querySelectorAll){
   1849 			// IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
   1850 			try {
   1851 				testNode.innerHTML = 'foo</foo>';
   1852 				selected = testNode.querySelectorAll('*');
   1853 				features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
   1854 			} catch(e){};
   1855 
   1856 			// Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
   1857 			try {
   1858 				testNode.innerHTML = '<a class="MiX"></a>';
   1859 				features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length;
   1860 			} catch(e){};
   1861 
   1862 			// Webkit and Opera dont return selected options on querySelectorAll
   1863 			try {
   1864 				testNode.innerHTML = '<select><option selected="selected">a</option></select>';
   1865 				features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
   1866 			} catch(e){};
   1867 
   1868 			// IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
   1869 			try {
   1870 				testNode.innerHTML = '<a class=""></a>';
   1871 				features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
   1872 			} catch(e){};
   1873 
   1874 		}
   1875 
   1876 		// IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input
   1877 		try {
   1878 			testNode.innerHTML = '<form action="s"><input id="action"/></form>';
   1879 			brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's');
   1880 		} catch(e){};
   1881 
   1882 		// native matchesSelector function
   1883 
   1884 		features.nativeMatchesSelector = root.matches || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
   1885 		if (features.nativeMatchesSelector) try {
   1886 			// if matchesSelector trows errors on incorrect sintaxes we can use it
   1887 			features.nativeMatchesSelector.call(root, ':slick');
   1888 			features.nativeMatchesSelector = null;
   1889 		} catch(e){};
   1890 
   1891 	}
   1892 
   1893 	try {
   1894 		root.slick_expando = 1;
   1895 		delete root.slick_expando;
   1896 		features.getUID = this.getUIDHTML;
   1897 	} catch(e) {
   1898 		features.getUID = this.getUIDXML;
   1899 	}
   1900 
   1901 	testRoot.removeChild(testNode);
   1902 	testNode = selected = testRoot = null;
   1903 
   1904 	// getAttribute
   1905 
   1906 	features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){
   1907 		var method = this.attributeGetters[name];
   1908 		if (method) return method.call(node);
   1909 		var attributeNode = node.getAttributeNode(name);
   1910 		return (attributeNode) ? attributeNode.nodeValue : null;
   1911 	} : function(node, name){
   1912 		var method = this.attributeGetters[name];
   1913 		return (method) ? method.call(node) : node.getAttribute(name);
   1914 	};
   1915 
   1916 	// hasAttribute
   1917 
   1918 	features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
   1919 		return node.hasAttribute(attribute);
   1920 	} : function(node, attribute) {
   1921 		node = node.getAttributeNode(attribute);
   1922 		return !!(node && (node.specified || node.nodeValue));
   1923 	};
   1924 
   1925 	// contains
   1926 	// FIXME: Add specs: local.contains should be different for xml and html documents?
   1927 	var nativeRootContains = root && this.isNativeCode(root.contains),
   1928 		nativeDocumentContains = document && this.isNativeCode(document.contains);
   1929 
   1930 	features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){
   1931 		return context.contains(node);
   1932 	} : (nativeRootContains && !nativeDocumentContains) ? function(context, node){
   1933 		// IE8 does not have .contains on document.
   1934 		return context === node || ((context === document) ? document.documentElement : context).contains(node);
   1935 	} : (root && root.compareDocumentPosition) ? function(context, node){
   1936 		return context === node || !!(context.compareDocumentPosition(node) & 16);
   1937 	} : function(context, node){
   1938 		if (node) do {
   1939 			if (node === context) return true;
   1940 		} while ((node = node.parentNode));
   1941 		return false;
   1942 	};
   1943 
   1944 	// document order sorting
   1945 	// credits to Sizzle (http://sizzlejs.com/)
   1946 
   1947 	features.documentSorter = (root.compareDocumentPosition) ? function(a, b){
   1948 		if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
   1949 		return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
   1950 	} : ('sourceIndex' in root) ? function(a, b){
   1951 		if (!a.sourceIndex || !b.sourceIndex) return 0;
   1952 		return a.sourceIndex - b.sourceIndex;
   1953 	} : (document.createRange) ? function(a, b){
   1954 		if (!a.ownerDocument || !b.ownerDocument) return 0;
   1955 		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
   1956 		aRange.setStart(a, 0);
   1957 		aRange.setEnd(a, 0);
   1958 		bRange.setStart(b, 0);
   1959 		bRange.setEnd(b, 0);
   1960 		return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
   1961 	} : null ;
   1962 
   1963 	root = null;
   1964 
   1965 	for (feature in features){
   1966 		this[feature] = features[feature];
   1967 	}
   1968 };
   1969 
   1970 // Main Method
   1971 
   1972 var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/,
   1973 	reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/,
   1974 	qsaFailExpCache = {};
   1975 
   1976 local.search = function(context, expression, append, first){
   1977 
   1978 	var found = this.found = (first) ? null : (append || []);
   1979 
   1980 	if (!context) return found;
   1981 	else if (context.navigator) context = context.document; // Convert the node from a window to a document
   1982 	else if (!context.nodeType) return found;
   1983 
   1984 	// setup
   1985 
   1986 	var parsed, i,
   1987 		uniques = this.uniques = {},
   1988 		hasOthers = !!(append && append.length),
   1989 		contextIsDocument = (context.nodeType == 9);
   1990 
   1991 	if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context);
   1992 
   1993 	// avoid duplicating items already in the append array
   1994 	if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true;
   1995 
   1996 	// expression checks
   1997 
   1998 	if (typeof expression == 'string'){ // expression is a string
   1999 
   2000 		/*<simple-selectors-override>*/
   2001 		var simpleSelector = expression.match(reSimpleSelector);
   2002 		simpleSelectors: if (simpleSelector) {
   2003 
   2004 			var symbol = simpleSelector[1],
   2005 				name = simpleSelector[2],
   2006 				node, nodes;
   2007 
   2008 			if (!symbol){
   2009 
   2010 				if (name == '*' && this.brokenStarGEBTN) break simpleSelectors;
   2011 				nodes = context.getElementsByTagName(name);
   2012 				if (first) return nodes[0] || null;
   2013 				for (i = 0; node = nodes[i++];){
   2014 					if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
   2015 				}
   2016 
   2017 			} else if (symbol == '#'){
   2018 
   2019 				if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors;
   2020 				node = context.getElementById(name);
   2021 				if (!node) return found;
   2022 				if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors;
   2023 				if (first) return node || null;
   2024 				if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
   2025 
   2026 			} else if (symbol == '.'){
   2027 
   2028 				if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors;
   2029 				if (context.getElementsByClassName && !this.brokenGEBCN){
   2030 					nodes = context.getElementsByClassName(name);
   2031 					if (first) return nodes[0] || null;
   2032 					for (i = 0; node = nodes[i++];){
   2033 						if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
   2034 					}
   2035 				} else {
   2036 					var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)');
   2037 					nodes = context.getElementsByTagName('*');
   2038 					for (i = 0; node = nodes[i++];){
   2039 						className = node.className;
   2040 						if (!(className && matchClass.test(className))) continue;
   2041 						if (first) return node;
   2042 						if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
   2043 					}
   2044 				}
   2045 
   2046 			}
   2047 
   2048 			if (hasOthers) this.sort(found);
   2049 			return (first) ? null : found;
   2050 
   2051 		}
   2052 		/*</simple-selectors-override>*/
   2053 
   2054 		/*<query-selector-override>*/
   2055 		querySelector: if (context.querySelectorAll) {
   2056 
   2057 			if (!this.isHTMLDocument
   2058 				|| qsaFailExpCache[expression]
   2059 				//TODO: only skip when expression is actually mixed case
   2060 				|| this.brokenMixedCaseQSA
   2061 				|| (this.brokenCheckedQSA && expression.indexOf(':checked') > -1)
   2062 				|| (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression))
   2063 				|| (!contextIsDocument //Abort when !contextIsDocument and...
   2064 					//  there are multiple expressions in the selector
   2065 					//  since we currently only fix non-document rooted QSA for single expression selectors
   2066 					&& expression.indexOf(',') > -1
   2067 				)
   2068 				|| Slick.disableQSA
   2069 			) break querySelector;
   2070 
   2071 			var _expression = expression, _context = context;
   2072 			if (!contextIsDocument){
   2073 				// non-document rooted QSA
   2074 				// credits to Andrew Dupont
   2075 				var currentId = _context.getAttribute('id'), slickid = 'slickid__';
   2076 				_context.setAttribute('id', slickid);
   2077 				_expression = '#' + slickid + ' ' + _expression;
   2078 				context = _context.parentNode;
   2079 			}
   2080 
   2081 			try {
   2082 				if (first) return context.querySelector(_expression) || null;
   2083 				else nodes = context.querySelectorAll(_expression);
   2084 			} catch(e) {
   2085 				qsaFailExpCache[expression] = 1;
   2086 				break querySelector;
   2087 			} finally {
   2088 				if (!contextIsDocument){
   2089 					if (currentId) _context.setAttribute('id', currentId);
   2090 					else _context.removeAttribute('id');
   2091 					context = _context;
   2092 				}
   2093 			}
   2094 
   2095 			if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
   2096 				if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node);
   2097 			} else for (i = 0; node = nodes[i++];){
   2098 				if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
   2099 			}
   2100 
   2101 			if (hasOthers) this.sort(found);
   2102 			return found;
   2103 
   2104 		}
   2105 		/*</query-selector-override>*/
   2106 
   2107 		parsed = this.Slick.parse(expression);
   2108 		if (!parsed.length) return found;
   2109 	} else if (expression == null){ // there is no expression
   2110 		return found;
   2111 	} else if (expression.Slick){ // expression is a parsed Slick object
   2112 		parsed = expression;
   2113 	} else if (this.contains(context.documentElement || context, expression)){ // expression is a node
   2114 		(found) ? found.push(expression) : found = expression;
   2115 		return found;
   2116 	} else { // other junk
   2117 		return found;
   2118 	}
   2119 
   2120 	/*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
   2121 
   2122 	// cache elements for the nth selectors
   2123 
   2124 	this.posNTH = {};
   2125 	this.posNTHLast = {};
   2126 	this.posNTHType = {};
   2127 	this.posNTHTypeLast = {};
   2128 
   2129 	/*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
   2130 
   2131 	// if append is null and there is only a single selector with one expression use pushArray, else use pushUID
   2132 	this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
   2133 
   2134 	if (found == null) found = [];
   2135 
   2136 	// default engine
   2137 
   2138 	var j, m, n;
   2139 	var combinator, tag, id, classList, classes, attributes, pseudos;
   2140 	var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;
   2141 
   2142 	search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){
   2143 
   2144 		combinator = 'combinator:' + currentBit.combinator;
   2145 		if (!this[combinator]) continue search;
   2146 
   2147 		tag        = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
   2148 		id         = currentBit.id;
   2149 		classList  = currentBit.classList;
   2150 		classes    = currentBit.classes;
   2151 		attributes = currentBit.attributes;
   2152 		pseudos    = currentBit.pseudos;
   2153 		lastBit    = (j === (currentExpression.length - 1));
   2154 
   2155 		this.bitUniques = {};
   2156 
   2157 		if (lastBit){
   2158 			this.uniques = uniques;
   2159 			this.found = found;
   2160 		} else {
   2161 			this.uniques = {};
   2162 			this.found = [];
   2163 		}
   2164 
   2165 		if (j === 0){
   2166 			this[combinator](context, tag, id, classes, attributes, pseudos, classList);
   2167 			if (first && lastBit && found.length) break search;
   2168 		} else {
   2169 			if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
   2170 				this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
   2171 				if (found.length) break search;
   2172 			} else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
   2173 		}
   2174 
   2175 		currentItems = this.found;
   2176 	}
   2177 
   2178 	// should sort if there are nodes in append and if you pass multiple expressions.
   2179 	if (hasOthers || (parsed.expressions.length > 1)) this.sort(found);
   2180 
   2181 	return (first) ? (found[0] || null) : found;
   2182 };
   2183 
   2184 // Utils
   2185 
   2186 local.uidx = 1;
   2187 local.uidk = 'slick-uniqueid';
   2188 
   2189 local.getUIDXML = function(node){
   2190 	var uid = node.getAttribute(this.uidk);
   2191 	if (!uid){
   2192 		uid = this.uidx++;
   2193 		node.setAttribute(this.uidk, uid);
   2194 	}
   2195 	return uid;
   2196 };
   2197 
   2198 local.getUIDHTML = function(node){
   2199 	return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
   2200 };
   2201 
   2202 // sort based on the setDocument documentSorter method.
   2203 
   2204 local.sort = function(results){
   2205 	if (!this.documentSorter) return results;
   2206 	results.sort(this.documentSorter);
   2207 	return results;
   2208 };
   2209 
   2210 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
   2211 
   2212 local.cacheNTH = {};
   2213 
   2214 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;
   2215 
   2216 local.parseNTHArgument = function(argument){
   2217 	var parsed = argument.match(this.matchNTH);
   2218 	if (!parsed) return false;
   2219 	var special = parsed[2] || false;
   2220 	var a = parsed[1] || 1;
   2221 	if (a == '-') a = -1;
   2222 	var b = +parsed[3] || 0;
   2223 	parsed =
   2224 		(special == 'n')	? {a: a, b: b} :
   2225 		(special == 'odd')	? {a: 2, b: 1} :
   2226 		(special == 'even')	? {a: 2, b: 0} : {a: 0, b: a};
   2227 
   2228 	return (this.cacheNTH[argument] = parsed);
   2229 };
   2230 
   2231 local.createNTHPseudo = function(child, sibling, positions, ofType){
   2232 	return function(node, argument){
   2233 		var uid = this.getUID(node);
   2234 		if (!this[positions][uid]){
   2235 			var parent = node.parentNode;
   2236 			if (!parent) return false;
   2237 			var el = parent[child], count = 1;
   2238 			if (ofType){
   2239 				var nodeName = node.nodeName;
   2240 				do {
   2241 					if (el.nodeName != nodeName) continue;
   2242 					this[positions][this.getUID(el)] = count++;
   2243 				} while ((el = el[sibling]));
   2244 			} else {
   2245 				do {
   2246 					if (el.nodeType != 1) continue;
   2247 					this[positions][this.getUID(el)] = count++;
   2248 				} while ((el = el[sibling]));
   2249 			}
   2250 		}
   2251 		argument = argument || 'n';
   2252 		var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
   2253 		if (!parsed) return false;
   2254 		var a = parsed.a, b = parsed.b, pos = this[positions][uid];
   2255 		if (a == 0) return b == pos;
   2256 		if (a > 0){
   2257 			if (pos < b) return false;
   2258 		} else {
   2259 			if (b < pos) return false;
   2260 		}
   2261 		return ((pos - b) % a) == 0;
   2262 	};
   2263 };
   2264 
   2265 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
   2266 
   2267 local.pushArray = function(node, tag, id, classes, attributes, pseudos){
   2268 	if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
   2269 };
   2270 
   2271 local.pushUID = function(node, tag, id, classes, attributes, pseudos){
   2272 	var uid = this.getUID(node);
   2273 	if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
   2274 		this.uniques[uid] = true;
   2275 		this.found.push(node);
   2276 	}
   2277 };
   2278 
   2279 local.matchNode = function(node, selector){
   2280 	if (this.isHTMLDocument && this.nativeMatchesSelector){
   2281 		try {
   2282 			return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
   2283 		} catch(matchError) {}
   2284 	}
   2285 
   2286 	var parsed = this.Slick.parse(selector);
   2287 	if (!parsed) return true;
   2288 
   2289 	// simple (single) selectors
   2290 	var expressions = parsed.expressions, simpleExpCounter = 0, i;
   2291 	for (i = 0; (currentExpression = expressions[i]); i++){
   2292 		if (currentExpression.length == 1){
   2293 			var exp = currentExpression[0];
   2294 			if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true;
   2295 			simpleExpCounter++;
   2296 		}
   2297 	}
   2298 
   2299 	if (simpleExpCounter == parsed.length) return false;
   2300 
   2301 	var nodes = this.search(this.document, parsed), item;
   2302 	for (i = 0; item = nodes[i++];){
   2303 		if (item === node) return true;
   2304 	}
   2305 	return false;
   2306 };
   2307 
   2308 local.matchPseudo = function(node, name, argument){
   2309 	var pseudoName = 'pseudo:' + name;
   2310 	if (this[pseudoName]) return this[pseudoName](node, argument);
   2311 	var attribute = this.getAttribute(node, name);
   2312 	return (argument) ? argument == attribute : !!attribute;
   2313 };
   2314 
   2315 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
   2316 	if (tag){
   2317 		var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase();
   2318 		if (tag == '*'){
   2319 			if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
   2320 		} else {
   2321 			if (nodeName != tag) return false;
   2322 		}
   2323 	}
   2324 
   2325 	if (id && node.getAttribute('id') != id) return false;
   2326 
   2327 	var i, part, cls;
   2328 	if (classes) for (i = classes.length; i--;){
   2329 		cls = this.getAttribute(node, 'class');
   2330 		if (!(cls && classes[i].regexp.test(cls))) return false;
   2331 	}
   2332 	if (attributes) for (i = attributes.length; i--;){
   2333 		part = attributes[i];
   2334 		if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
   2335 	}
   2336 	if (pseudos) for (i = pseudos.length; i--;){
   2337 		part = pseudos[i];
   2338 		if (!this.matchPseudo(node, part.key, part.value)) return false;
   2339 	}
   2340 	return true;
   2341 };
   2342 
   2343 var combinators = {
   2344 
   2345 	' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level
   2346 
   2347 		var i, item, children;
   2348 
   2349 		if (this.isHTMLDocument){
   2350 			getById: if (id){
   2351 				item = this.document.getElementById(id);
   2352 				if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
   2353 					// all[id] returns all the elements with that name or id inside node
   2354 					// if theres just one it will return the element, else it will be a collection
   2355 					children = node.all[id];
   2356 					if (!children) return;
   2357 					if (!children[0]) children = [children];
   2358 					for (i = 0; item = children[i++];){
   2359 						var idNode = item.getAttributeNode('id');
   2360 						if (idNode && idNode.nodeValue == id){
   2361 							this.push(item, tag, null, classes, attributes, pseudos);
   2362 							break;
   2363 						}
   2364 					}
   2365 					return;
   2366 				}
   2367 				if (!item){
   2368 					// if the context is in the dom we return, else we will try GEBTN, breaking the getById label
   2369 					if (this.contains(this.root, node)) return;
   2370 					else break getById;
   2371 				} else if (this.document !== node && !this.contains(node, item)) return;
   2372 				this.push(item, tag, null, classes, attributes, pseudos);
   2373 				return;
   2374 			}
   2375 			getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
   2376 				children = node.getElementsByClassName(classList.join(' '));
   2377 				if (!(children && children.length)) break getByClass;
   2378 				for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
   2379 				return;
   2380 			}
   2381 		}
   2382 		getByTag: {
   2383 			children = node.getElementsByTagName(tag);
   2384 			if (!(children && children.length)) break getByTag;
   2385 			if (!this.brokenStarGEBTN) tag = null;
   2386 			for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
   2387 		}
   2388 	},
   2389 
   2390 	'>': function(node, tag, id, classes, attributes, pseudos){ // direct children
   2391 		if ((node = node.firstChild)) do {
   2392 			if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
   2393 		} while ((node = node.nextSibling));
   2394 	},
   2395 
   2396 	'+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
   2397 		while ((node = node.nextSibling)) if (node.nodeType == 1){
   2398 			this.push(node, tag, id, classes, attributes, pseudos);
   2399 			break;
   2400 		}
   2401 	},
   2402 
   2403 	'^': function(node, tag, id, classes, attributes, pseudos){ // first child
   2404 		node = node.firstChild;
   2405 		if (node){
   2406 			if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
   2407 			else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
   2408 		}
   2409 	},
   2410 
   2411 	'~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
   2412 		while ((node = node.nextSibling)){
   2413 			if (node.nodeType != 1) continue;
   2414 			var uid = this.getUID(node);
   2415 			if (this.bitUniques[uid]) break;
   2416 			this.bitUniques[uid] = true;
   2417 			this.push(node, tag, id, classes, attributes, pseudos);
   2418 		}
   2419 	},
   2420 
   2421 	'++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
   2422 		this['combinator:+'](node, tag, id, classes, attributes, pseudos);
   2423 		this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
   2424 	},
   2425 
   2426 	'~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
   2427 		this['combinator:~'](node, tag, id, classes, attributes, pseudos);
   2428 		this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
   2429 	},
   2430 
   2431 	'!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
   2432 		while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
   2433 	},
   2434 
   2435 	'!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
   2436 		node = node.parentNode;
   2437 		if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
   2438 	},
   2439 
   2440 	'!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
   2441 		while ((node = node.previousSibling)) if (node.nodeType == 1){
   2442 			this.push(node, tag, id, classes, attributes, pseudos);
   2443 			break;
   2444 		}
   2445 	},
   2446 
   2447 	'!^': function(node, tag, id, classes, attributes, pseudos){ // last child
   2448 		node = node.lastChild;
   2449 		if (node){
   2450 			if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
   2451 			else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
   2452 		}
   2453 	},
   2454 
   2455 	'!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
   2456 		while ((node = node.previousSibling)){
   2457 			if (node.nodeType != 1) continue;
   2458 			var uid = this.getUID(node);
   2459 			if (this.bitUniques[uid]) break;
   2460 			this.bitUniques[uid] = true;
   2461 			this.push(node, tag, id, classes, attributes, pseudos);
   2462 		}
   2463 	}
   2464 
   2465 };
   2466 
   2467 for (var c in combinators) local['combinator:' + c] = combinators[c];
   2468 
   2469 var pseudos = {
   2470 
   2471 	/*<pseudo-selectors>*/
   2472 
   2473 	'empty': function(node){
   2474 		var child = node.firstChild;
   2475 		return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
   2476 	},
   2477 
   2478 	'not': function(node, expression){
   2479 		return !this.matchNode(node, expression);
   2480 	},
   2481 
   2482 	'contains': function(node, text){
   2483 		return (node.innerText || node.textContent || '').indexOf(text) > -1;
   2484 	},
   2485 
   2486 	'first-child': function(node){
   2487 		while ((node = node.previousSibling)) if (node.nodeType == 1) return false;
   2488 		return true;
   2489 	},
   2490 
   2491 	'last-child': function(node){
   2492 		while ((node = node.nextSibling)) if (node.nodeType == 1) return false;
   2493 		return true;
   2494 	},
   2495 
   2496 	'only-child': function(node){
   2497 		var prev = node;
   2498 		while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false;
   2499 		var next = node;
   2500 		while ((next = next.nextSibling)) if (next.nodeType == 1) return false;
   2501 		return true;
   2502 	},
   2503 
   2504 	/*<nth-pseudo-selectors>*/
   2505 
   2506 	'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),
   2507 
   2508 	'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),
   2509 
   2510 	'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),
   2511 
   2512 	'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),
   2513 
   2514 	'index': function(node, index){
   2515 		return this['pseudo:nth-child'](node, '' + (index + 1));
   2516 	},
   2517 
   2518 	'even': function(node){
   2519 		return this['pseudo:nth-child'](node, '2n');
   2520 	},
   2521 
   2522 	'odd': function(node){
   2523 		return this['pseudo:nth-child'](node, '2n+1');
   2524 	},
   2525 
   2526 	/*</nth-pseudo-selectors>*/
   2527 
   2528 	/*<of-type-pseudo-selectors>*/
   2529 
   2530 	'first-of-type': function(node){
   2531 		var nodeName = node.nodeName;
   2532 		while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false;
   2533 		return true;
   2534 	},
   2535 
   2536 	'last-of-type': function(node){
   2537 		var nodeName = node.nodeName;
   2538 		while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false;
   2539 		return true;
   2540 	},
   2541 
   2542 	'only-of-type': function(node){
   2543 		var prev = node, nodeName = node.nodeName;
   2544 		while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false;
   2545 		var next = node;
   2546 		while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false;
   2547 		return true;
   2548 	},
   2549 
   2550 	/*</of-type-pseudo-selectors>*/
   2551 
   2552 	// custom pseudos
   2553 
   2554 	'enabled': function(node){
   2555 		return !node.disabled;
   2556 	},
   2557 
   2558 	'disabled': function(node){
   2559 		return node.disabled;
   2560 	},
   2561 
   2562 	'checked': function(node){
   2563 		return node.checked || node.selected;
   2564 	},
   2565 
   2566 	'focus': function(node){
   2567 		return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
   2568 	},
   2569 
   2570 	'root': function(node){
   2571 		return (node === this.root);
   2572 	},
   2573 
   2574 	'selected': function(node){
   2575 		return node.selected;
   2576 	}
   2577 
   2578 	/*</pseudo-selectors>*/
   2579 };
   2580 
   2581 for (var p in pseudos) local['pseudo:' + p] = pseudos[p];
   2582 
   2583 // attributes methods
   2584 
   2585 var attributeGetters = local.attributeGetters = {
   2586 
   2587 	'for': function(){
   2588 		return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
   2589 	},
   2590 
   2591 	'href': function(){
   2592 		return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
   2593 	},
   2594 
   2595 	'style': function(){
   2596 		return (this.style) ? this.style.cssText : this.getAttribute('style');
   2597 	},
   2598 
   2599 	'tabindex': function(){
   2600 		var attributeNode = this.getAttributeNode('tabindex');
   2601 		return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
   2602 	},
   2603 
   2604 	'type': function(){
   2605 		return this.getAttribute('type');
   2606 	},
   2607 
   2608 	'maxlength': function(){
   2609 		var attributeNode = this.getAttributeNode('maxLength');
   2610 		return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
   2611 	}
   2612 
   2613 };
   2614 
   2615 attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength;
   2616 
   2617 // Slick
   2618 
   2619 var Slick = local.Slick = (this.Slick || {});
   2620 
   2621 Slick.version = '1.1.7';
   2622 
   2623 // Slick finder
   2624 
   2625 Slick.search = function(context, expression, append){
   2626 	return local.search(context, expression, append);
   2627 };
   2628 
   2629 Slick.find = function(context, expression){
   2630 	return local.search(context, expression, null, true);
   2631 };
   2632 
   2633 // Slick containment checker
   2634 
   2635 Slick.contains = function(container, node){
   2636 	local.setDocument(container);
   2637 	return local.contains(container, node);
   2638 };
   2639 
   2640 // Slick attribute getter
   2641 
   2642 Slick.getAttribute = function(node, name){
   2643 	local.setDocument(node);
   2644 	return local.getAttribute(node, name);
   2645 };
   2646 
   2647 Slick.hasAttribute = function(node, name){
   2648 	local.setDocument(node);
   2649 	return local.hasAttribute(node, name);
   2650 };
   2651 
   2652 // Slick matcher
   2653 
   2654 Slick.match = function(node, selector){
   2655 	if (!(node && selector)) return false;
   2656 	if (!selector || selector === node) return true;
   2657 	local.setDocument(node);
   2658 	return local.matchNode(node, selector);
   2659 };
   2660 
   2661 // Slick attribute accessor
   2662 
   2663 Slick.defineAttributeGetter = function(name, fn){
   2664 	local.attributeGetters[name] = fn;
   2665 	return this;
   2666 };
   2667 
   2668 Slick.lookupAttributeGetter = function(name){
   2669 	return local.attributeGetters[name];
   2670 };
   2671 
   2672 // Slick pseudo accessor
   2673 
   2674 Slick.definePseudo = function(name, fn){
   2675 	local['pseudo:' + name] = function(node, argument){
   2676 		return fn.call(node, argument);
   2677 	};
   2678 	return this;
   2679 };
   2680 
   2681 Slick.lookupPseudo = function(name){
   2682 	var pseudo = local['pseudo:' + name];
   2683 	if (pseudo) return function(argument){
   2684 		return pseudo.call(this, argument);
   2685 	};
   2686 	return null;
   2687 };
   2688 
   2689 // Slick overrides accessor
   2690 
   2691 Slick.override = function(regexp, fn){
   2692 	local.override(regexp, fn);
   2693 	return this;
   2694 };
   2695 
   2696 Slick.isXML = local.isXML;
   2697 
   2698 Slick.uidOf = function(node){
   2699 	return local.getUIDHTML(node);
   2700 };
   2701 
   2702 if (!this.Slick) this.Slick = Slick;
   2703 
   2704 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
   2705 
   2706 
   2707 /*
   2708 ---
   2709 
   2710 name: Element
   2711 
   2712 description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements.
   2713 
   2714 license: MIT-style license.
   2715 
   2716 requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder]
   2717 
   2718 provides: [Element, Elements, $, $$, IFrame, Selectors]
   2719 
   2720 ...
   2721 */
   2722 
   2723 var Element = this.Element = function(tag, props){
   2724 	var konstructor = Element.Constructors[tag];
   2725 	if (konstructor) return konstructor(props);
   2726 	if (typeof tag != 'string') return document.id(tag).set(props);
   2727 
   2728 	if (!props) props = {};
   2729 
   2730 	if (!(/^[\w-]+$/).test(tag)){
   2731 		var parsed = Slick.parse(tag).expressions[0][0];
   2732 		tag = (parsed.tag == '*') ? 'div' : parsed.tag;
   2733 		if (parsed.id && props.id == null) props.id = parsed.id;
   2734 
   2735 		var attributes = parsed.attributes;
   2736 		if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){
   2737 			attr = attributes[i];
   2738 			if (props[attr.key] != null) continue;
   2739 
   2740 			if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value;
   2741 			else if (!attr.value && !attr.operator) props[attr.key] = true;
   2742 		}
   2743 
   2744 		if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' ');
   2745 	}
   2746 
   2747 	return document.newElement(tag, props);
   2748 };
   2749 
   2750 
   2751 if (Browser.Element){
   2752 	Element.prototype = Browser.Element.prototype;
   2753 	// IE8 and IE9 require the wrapping.
   2754 	Element.prototype._fireEvent = (function(fireEvent){
   2755 		return function(type, event){
   2756 			return fireEvent.call(this, type, event);
   2757 		};
   2758 	})(Element.prototype.fireEvent);
   2759 }
   2760 
   2761 new Type('Element', Element).mirror(function(name){
   2762 	if (Array.prototype[name]) return;
   2763 
   2764 	var obj = {};
   2765 	obj[name] = function(){
   2766 		var results = [], args = arguments, elements = true;
   2767 		for (var i = 0, l = this.length; i < l; i++){
   2768 			var element = this[i], result = results[i] = element[name].apply(element, args);
   2769 			elements = (elements && typeOf(result) == 'element');
   2770 		}
   2771 		return (elements) ? new Elements(results) : results;
   2772 	};
   2773 
   2774 	Elements.implement(obj);
   2775 });
   2776 
   2777 if (!Browser.Element){
   2778 	Element.parent = Object;
   2779 
   2780 	Element.Prototype = {
   2781 		'$constructor': Element,
   2782 		'$family': Function.from('element').hide()
   2783 	};
   2784 
   2785 	Element.mirror(function(name, method){
   2786 		Element.Prototype[name] = method;
   2787 	});
   2788 }
   2789 
   2790 Element.Constructors = {};
   2791 
   2792 
   2793 
   2794 var IFrame = new Type('IFrame', function(){
   2795 	var params = Array.link(arguments, {
   2796 		properties: Type.isObject,
   2797 		iframe: function(obj){
   2798 			return (obj != null);
   2799 		}
   2800 	});
   2801 
   2802 	var props = params.properties || {}, iframe;
   2803 	if (params.iframe) iframe = document.id(params.iframe);
   2804 	var onload = props.onload || function(){};
   2805 	delete props.onload;
   2806 	props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick();
   2807 	iframe = new Element(iframe || 'iframe', props);
   2808 
   2809 	var onLoad = function(){
   2810 		onload.call(iframe.contentWindow);
   2811 	};
   2812 
   2813 	if (window.frames[props.id]) onLoad();
   2814 	else iframe.addListener('load', onLoad);
   2815 	return iframe;
   2816 });
   2817 
   2818 var Elements = this.Elements = function(nodes){
   2819 	if (nodes && nodes.length){
   2820 		var uniques = {}, node;
   2821 		for (var i = 0; node = nodes[i++];){
   2822 			var uid = Slick.uidOf(node);
   2823 			if (!uniques[uid]){
   2824 				uniques[uid] = true;
   2825 				this.push(node);
   2826 			}
   2827 		}
   2828 	}
   2829 };
   2830 
   2831 Elements.prototype = {length: 0};
   2832 Elements.parent = Array;
   2833 
   2834 new Type('Elements', Elements).implement({
   2835 
   2836 	filter: function(filter, bind){
   2837 		if (!filter) return this;
   2838 		return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){
   2839 			return item.match(filter);
   2840 		} : filter, bind));
   2841 	}.protect(),
   2842 
   2843 	push: function(){
   2844 		var length = this.length;
   2845 		for (var i = 0, l = arguments.length; i < l; i++){
   2846 			var item = document.id(arguments[i]);
   2847 			if (item) this[length++] = item;
   2848 		}
   2849 		return (this.length = length);
   2850 	}.protect(),
   2851 
   2852 	unshift: function(){
   2853 		var items = [];
   2854 		for (var i = 0, l = arguments.length; i < l; i++){
   2855 			var item = document.id(arguments[i]);
   2856 			if (item) items.push(item);
   2857 		}
   2858 		return Array.prototype.unshift.apply(this, items);
   2859 	}.protect(),
   2860 
   2861 	concat: function(){
   2862 		var newElements = new Elements(this);
   2863 		for (var i = 0, l = arguments.length; i < l; i++){
   2864 			var item = arguments[i];
   2865 			if (Type.isEnumerable(item)) newElements.append(item);
   2866 			else newElements.push(item);
   2867 		}
   2868 		return newElements;
   2869 	}.protect(),
   2870 
   2871 	append: function(collection){
   2872 		for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]);
   2873 		return this;
   2874 	}.protect(),
   2875 
   2876 	empty: function(){
   2877 		while (this.length) delete this[--this.length];
   2878 		return this;
   2879 	}.protect()
   2880 
   2881 });
   2882 
   2883 
   2884 
   2885 (function(){
   2886 
   2887 // FF, IE
   2888 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2};
   2889 
   2890 splice.call(object, 1, 1);
   2891 if (object[1] == 1) Elements.implement('splice', function(){
   2892 	var length = this.length;
   2893 	var result = splice.apply(this, arguments);
   2894 	while (length >= this.length) delete this[length--];
   2895 	return result;
   2896 }.protect());
   2897 
   2898 Array.forEachMethod(function(method, name){
   2899 	Elements.implement(name, method);
   2900 });
   2901 
   2902 Array.mirror(Elements);
   2903 
   2904 /*<ltIE8>*/
   2905 var createElementAcceptsHTML;
   2906 try {
   2907 	createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x');
   2908 } catch (e){}
   2909 
   2910 var escapeQuotes = function(html){
   2911 	return ('' + html).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
   2912 };
   2913 /*</ltIE8>*/
   2914 
   2915 Document.implement({
   2916 
   2917 	newElement: function(tag, props){
   2918 		if (props && props.checked != null) props.defaultChecked = props.checked;
   2919 		/*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
   2920 		if (createElementAcceptsHTML && props){
   2921 			tag = '<' + tag;
   2922 			if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
   2923 			if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
   2924 			tag += '>';
   2925 			delete props.name;
   2926 			delete props.type;
   2927 		}
   2928 		/*</ltIE8>*/
   2929 		return this.id(this.createElement(tag)).set(props);
   2930 	}
   2931 
   2932 });
   2933 
   2934 })();
   2935 
   2936 (function(){
   2937 
   2938 Slick.uidOf(window);
   2939 Slick.uidOf(document);
   2940 
   2941 Document.implement({
   2942 
   2943 	newTextNode: function(text){
   2944 		return this.createTextNode(text);
   2945 	},
   2946 
   2947 	getDocument: function(){
   2948 		return this;
   2949 	},
   2950 
   2951 	getWindow: function(){
   2952 		return this.window;
   2953 	},
   2954 
   2955 	id: (function(){
   2956 
   2957 		var types = {
   2958 
   2959 			string: function(id, nocash, doc){
   2960 				id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1'));
   2961 				return (id) ? types.element(id, nocash) : null;
   2962 			},
   2963 
   2964 			element: function(el, nocash){
   2965 				Slick.uidOf(el);
   2966 				if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){
   2967 					var fireEvent = el.fireEvent;
   2968 					// wrapping needed in IE7, or else crash
   2969 					el._fireEvent = function(type, event){
   2970 						return fireEvent(type, event);
   2971 					};
   2972 					Object.append(el, Element.Prototype);
   2973 				}
   2974 				return el;
   2975 			},
   2976 
   2977 			object: function(obj, nocash, doc){
   2978 				if (obj.toElement) return types.element(obj.toElement(doc), nocash);
   2979 				return null;
   2980 			}
   2981 
   2982 		};
   2983 
   2984 		types.textnode = types.whitespace = types.window = types.document = function(zero){
   2985 			return zero;
   2986 		};
   2987 
   2988 		return function(el, nocash, doc){
   2989 			if (el && el.$family && el.uniqueNumber) return el;
   2990 			var type = typeOf(el);
   2991 			return (types[type]) ? types[type](el, nocash, doc || document) : null;
   2992 		};
   2993 
   2994 	})()
   2995 
   2996 });
   2997 
   2998 if (window.$ == null) Window.implement('$', function(el, nc){
   2999 	return document.id(el, nc, this.document);
   3000 });
   3001 
   3002 Window.implement({
   3003 
   3004 	getDocument: function(){
   3005 		return this.document;
   3006 	},
   3007 
   3008 	getWindow: function(){
   3009 		return this;
   3010 	}
   3011 
   3012 });
   3013 
   3014 [Document, Element].invoke('implement', {
   3015 
   3016 	getElements: function(expression){
   3017 		return Slick.search(this, expression, new Elements);
   3018 	},
   3019 
   3020 	getElement: function(expression){
   3021 		return document.id(Slick.find(this, expression));
   3022 	}
   3023 
   3024 });
   3025 
   3026 var contains = {contains: function(element){
   3027 	return Slick.contains(this, element);
   3028 }};
   3029 
   3030 if (!document.contains) Document.implement(contains);
   3031 if (!document.createElement('div').contains) Element.implement(contains);
   3032 
   3033 
   3034 
   3035 // tree walking
   3036 
   3037 var injectCombinator = function(expression, combinator){
   3038 	if (!expression) return combinator;
   3039 
   3040 	expression = Object.clone(Slick.parse(expression));
   3041 
   3042 	var expressions = expression.expressions;
   3043 	for (var i = expressions.length; i--;)
   3044 		expressions[i][0].combinator = combinator;
   3045 
   3046 	return expression;
   3047 };
   3048 
   3049 Object.forEach({
   3050 	getNext: '~',
   3051 	getPrevious: '!~',
   3052 	getParent: '!'
   3053 }, function(combinator, method){
   3054 	Element.implement(method, function(expression){
   3055 		return this.getElement(injectCombinator(expression, combinator));
   3056 	});
   3057 });
   3058 
   3059 Object.forEach({
   3060 	getAllNext: '~',
   3061 	getAllPrevious: '!~',
   3062 	getSiblings: '~~',
   3063 	getChildren: '>',
   3064 	getParents: '!'
   3065 }, function(combinator, method){
   3066 	Element.implement(method, function(expression){
   3067 		return this.getElements(injectCombinator(expression, combinator));
   3068 	});
   3069 });
   3070 
   3071 Element.implement({
   3072 
   3073 	getFirst: function(expression){
   3074 		return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
   3075 	},
   3076 
   3077 	getLast: function(expression){
   3078 		return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
   3079 	},
   3080 
   3081 	getWindow: function(){
   3082 		return this.ownerDocument.window;
   3083 	},
   3084 
   3085 	getDocument: function(){
   3086 		return this.ownerDocument;
   3087 	},
   3088 
   3089 	getElementById: function(id){
   3090 		return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1')));
   3091 	},
   3092 
   3093 	match: function(expression){
   3094 		return !expression || Slick.match(this, expression);
   3095 	}
   3096 
   3097 });
   3098 
   3099 
   3100 
   3101 if (window.$$ == null) Window.implement('$$', function(selector){
   3102 	if (arguments.length == 1){
   3103 		if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements);
   3104 		else if (Type.isEnumerable(selector)) return new Elements(selector);
   3105 	}
   3106 	return new Elements(arguments);
   3107 });
   3108 
   3109 // Inserters
   3110 
   3111 var inserters = {
   3112 
   3113 	before: function(context, element){
   3114 		var parent = element.parentNode;
   3115 		if (parent) parent.insertBefore(context, element);
   3116 	},
   3117 
   3118 	after: function(context, element){
   3119 		var parent = element.parentNode;
   3120 		if (parent) parent.insertBefore(context, element.nextSibling);
   3121 	},
   3122 
   3123 	bottom: function(context, element){
   3124 		element.appendChild(context);
   3125 	},
   3126 
   3127 	top: function(context, element){
   3128 		element.insertBefore(context, element.firstChild);
   3129 	}
   3130 
   3131 };
   3132 
   3133 inserters.inside = inserters.bottom;
   3134 
   3135 
   3136 
   3137 // getProperty / setProperty
   3138 
   3139 var propertyGetters = {}, propertySetters = {};
   3140 
   3141 // properties
   3142 
   3143 var properties = {};
   3144 Array.forEach([
   3145 	'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan',
   3146 	'frameBorder', 'rowSpan', 'tabIndex', 'useMap'
   3147 ], function(property){
   3148 	properties[property.toLowerCase()] = property;
   3149 });
   3150 
   3151 properties.html = 'innerHTML';
   3152 properties.text = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
   3153 
   3154 Object.forEach(properties, function(real, key){
   3155 	propertySetters[key] = function(node, value){
   3156 		node[real] = value;
   3157 	};
   3158 	propertyGetters[key] = function(node){
   3159 		return node[real];
   3160 	};
   3161 });
   3162 
   3163 // Booleans
   3164 
   3165 var bools = [
   3166 	'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked',
   3167 	'disabled', 'readOnly', 'multiple', 'selected', 'noresize',
   3168 	'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay',
   3169 	'loop'
   3170 ];
   3171 
   3172 var booleans = {};
   3173 Array.forEach(bools, function(bool){
   3174 	var lower = bool.toLowerCase();
   3175 	booleans[lower] = bool;
   3176 	propertySetters[lower] = function(node, value){
   3177 		node[bool] = !!value;
   3178 	};
   3179 	propertyGetters[lower] = function(node){
   3180 		return !!node[bool];
   3181 	};
   3182 });
   3183 
   3184 // Special cases
   3185 
   3186 Object.append(propertySetters, {
   3187 
   3188 	'class': function(node, value){
   3189 		('className' in node) ? node.className = (value || '') : node.setAttribute('class', value);
   3190 	},
   3191 
   3192 	'for': function(node, value){
   3193 		('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value);
   3194 	},
   3195 
   3196 	'style': function(node, value){
   3197 		(node.style) ? node.style.cssText = value : node.setAttribute('style', value);
   3198 	},
   3199 
   3200 	'value': function(node, value){
   3201 		node.value = (value != null) ? value : '';
   3202 	}
   3203 
   3204 });
   3205 
   3206 propertyGetters['class'] = function(node){
   3207 	return ('className' in node) ? node.className || null : node.getAttribute('class');
   3208 };
   3209 
   3210 /* <webkit> */
   3211 var el = document.createElement('button');
   3212 // IE sets type as readonly and throws
   3213 try { el.type = 'button'; } catch(e){}
   3214 if (el.type != 'button') propertySetters.type = function(node, value){
   3215 	node.setAttribute('type', value);
   3216 };
   3217 el = null;
   3218 /* </webkit> */
   3219 
   3220 /*<IE>*/
   3221 var input = document.createElement('input');
   3222 input.value = 't';
   3223 input.type = 'submit';
   3224 if (input.value != 't') propertySetters.type = function(node, type){
   3225 	var value = node.value;
   3226 	node.type = type;
   3227 	node.value = value;
   3228 };
   3229 input = null;
   3230 /*</IE>*/
   3231 
   3232 /* getProperty, setProperty */
   3233 
   3234 /* <ltIE9> */
   3235 var pollutesGetAttribute = (function(div){
   3236 	div.random = 'attribute';
   3237 	return (div.getAttribute('random') == 'attribute');
   3238 })(document.createElement('div'));
   3239 
   3240 var hasCloneBug = (function(test){
   3241 	test.innerHTML = '<object><param name="should_fix" value="the unknown"></object>';
   3242 	return test.cloneNode(true).firstChild.childNodes.length != 1;
   3243 })(document.createElement('div'));
   3244 /* </ltIE9> */
   3245 
   3246 var hasClassList = !!document.createElement('div').classList;
   3247 
   3248 var classes = function(className){
   3249 	var classNames = (className || '').clean().split(" "), uniques = {};
   3250 	return classNames.filter(function(className){
   3251 		if (className !== "" && !uniques[className]) return uniques[className] = className;
   3252 	});
   3253 };
   3254 
   3255 var addToClassList = function(name){
   3256 	this.classList.add(name);
   3257 };
   3258 
   3259 var removeFromClassList = function(name){
   3260 	this.classList.remove(name);
   3261 };
   3262 
   3263 Element.implement({
   3264 
   3265 	setProperty: function(name, value){
   3266 		var setter = propertySetters[name.toLowerCase()];
   3267 		if (setter){
   3268 			setter(this, value);
   3269 		} else {
   3270 			/* <ltIE9> */
   3271 			var attributeWhiteList;
   3272 			if (pollutesGetAttribute) attributeWhiteList = this.retrieve('$attributeWhiteList', {});
   3273 			/* </ltIE9> */
   3274 
   3275 			if (value == null){
   3276 				this.removeAttribute(name);
   3277 				/* <ltIE9> */
   3278 				if (pollutesGetAttribute) delete attributeWhiteList[name];
   3279 				/* </ltIE9> */
   3280 			} else {
   3281 				this.setAttribute(name, '' + value);
   3282 				/* <ltIE9> */
   3283 				if (pollutesGetAttribute) attributeWhiteList[name] = true;
   3284 				/* </ltIE9> */
   3285 			}
   3286 		}
   3287 		return this;
   3288 	},
   3289 
   3290 	setProperties: function(attributes){
   3291 		for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
   3292 		return this;
   3293 	},
   3294 
   3295 	getProperty: function(name){
   3296 		var getter = propertyGetters[name.toLowerCase()];
   3297 		if (getter) return getter(this);
   3298 		/* <ltIE9> */
   3299 		if (pollutesGetAttribute){
   3300 			var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve('$attributeWhiteList', {});
   3301 			if (!attr) return null;
   3302 			if (attr.expando && !attributeWhiteList[name]){
   3303 				var outer = this.outerHTML;
   3304 				// segment by the opening tag and find mention of attribute name
   3305 				if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(name) < 0) return null;
   3306 				attributeWhiteList[name] = true;
   3307 			}
   3308 		}
   3309 		/* </ltIE9> */
   3310 		var result = Slick.getAttribute(this, name);
   3311 		return (!result && !Slick.hasAttribute(this, name)) ? null : result;
   3312 	},
   3313 
   3314 	getProperties: function(){
   3315 		var args = Array.from(arguments);
   3316 		return args.map(this.getProperty, this).associate(args);
   3317 	},
   3318 
   3319 	removeProperty: function(name){
   3320 		return this.setProperty(name, null);
   3321 	},
   3322 
   3323 	removeProperties: function(){
   3324 		Array.each(arguments, this.removeProperty, this);
   3325 		return this;
   3326 	},
   3327 
   3328 	set: function(prop, value){
   3329 		var property = Element.Properties[prop];
   3330 		(property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
   3331 	}.overloadSetter(),
   3332 
   3333 	get: function(prop){
   3334 		var property = Element.Properties[prop];
   3335 		return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
   3336 	}.overloadGetter(),
   3337 
   3338 	erase: function(prop){
   3339 		var property = Element.Properties[prop];
   3340 		(property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
   3341 		return this;
   3342 	},
   3343 
   3344 	hasClass: hasClassList ? function(className){
   3345 		return this.classList.contains(className);
   3346 	} : function(className){
   3347 		return this.className.clean().contains(className, ' ');
   3348 	},
   3349 
   3350 	addClass: hasClassList ? function(className){
   3351 		classes(className).forEach(addToClassList, this);
   3352 		return this;
   3353 	} : function(className){
   3354 		this.className = classes(className + ' ' + this.className).join(' ');
   3355 		return this;
   3356 	},
   3357 
   3358 	removeClass: hasClassList ? function(className){
   3359 		classes(className).forEach(removeFromClassList, this);
   3360 		return this;
   3361 	} : function(className){
   3362 		var classNames = classes(this.className);
   3363 		classes(className).forEach(classNames.erase, classNames);
   3364 		this.className = classNames.join(' ');
   3365 		return this;
   3366 	},
   3367 
   3368 	toggleClass: function(className, force){
   3369 		if (force == null) force = !this.hasClass(className);
   3370 		return (force) ? this.addClass(className) : this.removeClass(className);
   3371 	},
   3372 
   3373 	adopt: function(){
   3374 		var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length;
   3375 		if (length > 1) parent = fragment = document.createDocumentFragment();
   3376 
   3377 		for (var i = 0; i < length; i++){
   3378 			var element = document.id(elements[i], true);
   3379 			if (element) parent.appendChild(element);
   3380 		}
   3381 
   3382 		if (fragment) this.appendChild(fragment);
   3383 
   3384 		return this;
   3385 	},
   3386 
   3387 	appendText: function(text, where){
   3388 		return this.grab(this.getDocument().newTextNode(text), where);
   3389 	},
   3390 
   3391 	grab: function(el, where){
   3392 		inserters[where || 'bottom'](document.id(el, true), this);
   3393 		return this;
   3394 	},
   3395 
   3396 	inject: function(el, where){
   3397 		inserters[where || 'bottom'](this, document.id(el, true));
   3398 		return this;
   3399 	},
   3400 
   3401 	replaces: function(el){
   3402 		el = document.id(el, true);
   3403 		el.parentNode.replaceChild(this, el);
   3404 		return this;
   3405 	},
   3406 
   3407 	wraps: function(el, where){
   3408 		el = document.id(el, true);
   3409 		return this.replaces(el).grab(el, where);
   3410 	},
   3411 
   3412 	getSelected: function(){
   3413 		this.selectedIndex; // Safari 3.2.1
   3414 		return new Elements(Array.from(this.options).filter(function(option){
   3415 			return option.selected;
   3416 		}));
   3417 	},
   3418 
   3419 	toQueryString: function(){
   3420 		var queryString = [];
   3421 		this.getElements('input, select, textarea').each(function(el){
   3422 			var type = el.type;
   3423 			if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return;
   3424 
   3425 			var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){
   3426 				// IE
   3427 				return document.id(opt).get('value');
   3428 			}) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value');
   3429 
   3430 			Array.from(value).each(function(val){
   3431 				if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val));
   3432 			});
   3433 		});
   3434 		return queryString.join('&');
   3435 	}
   3436 
   3437 });
   3438 
   3439 
   3440 // appendHTML
   3441 
   3442 var appendInserters = {
   3443 	before: 'beforeBegin',
   3444 	after: 'afterEnd',
   3445 	bottom: 'beforeEnd',
   3446 	top: 'afterBegin',
   3447 	inside: 'beforeEnd'
   3448 };
   3449 
   3450 Element.implement('appendHTML', ('insertAdjacentHTML' in document.createElement('div')) ? function(html, where){
   3451 	this.insertAdjacentHTML(appendInserters[where || 'bottom'], html);
   3452 	return this;
   3453 } : function(html, where){
   3454 	var temp = new Element('div', {html: html}),
   3455 		children = temp.childNodes,
   3456 		fragment = temp.firstChild;
   3457 
   3458 	if (!fragment) return this;
   3459 	if (children.length > 1){
   3460 		fragment = document.createDocumentFragment();
   3461 		for (var i = 0, l = children.length; i < l; i++){
   3462 			fragment.appendChild(children[i]);
   3463 		}
   3464 	}
   3465 
   3466 	inserters[where || 'bottom'](fragment, this);
   3467 	return this;
   3468 });
   3469 
   3470 var collected = {}, storage = {};
   3471 
   3472 var get = function(uid){
   3473 	return (storage[uid] || (storage[uid] = {}));
   3474 };
   3475 
   3476 var clean = function(item){
   3477 	var uid = item.uniqueNumber;
   3478 	if (item.removeEvents) item.removeEvents();
   3479 	if (item.clearAttributes) item.clearAttributes();
   3480 	if (uid != null){
   3481 		delete collected[uid];
   3482 		delete storage[uid];
   3483 	}
   3484 	return item;
   3485 };
   3486 
   3487 var formProps = {input: 'checked', option: 'selected', textarea: 'value'};
   3488 
   3489 Element.implement({
   3490 
   3491 	destroy: function(){
   3492 		var children = clean(this).getElementsByTagName('*');
   3493 		Array.each(children, clean);
   3494 		Element.dispose(this);
   3495 		return null;
   3496 	},
   3497 
   3498 	empty: function(){
   3499 		Array.from(this.childNodes).each(Element.dispose);
   3500 		return this;
   3501 	},
   3502 
   3503 	dispose: function(){
   3504 		return (this.parentNode) ? this.parentNode.removeChild(this) : this;
   3505 	},
   3506 
   3507 	clone: function(contents, keepid){
   3508 		contents = contents !== false;
   3509 		var clone = this.cloneNode(contents), ce = [clone], te = [this], i;
   3510 
   3511 		if (contents){
   3512 			ce.append(Array.from(clone.getElementsByTagName('*')));
   3513 			te.append(Array.from(this.getElementsByTagName('*')));
   3514 		}
   3515 
   3516 		for (i = ce.length; i--;){
   3517 			var node = ce[i], element = te[i];
   3518 			if (!keepid) node.removeAttribute('id');
   3519 			/*<ltIE9>*/
   3520 			if (node.clearAttributes){
   3521 				node.clearAttributes();
   3522 				node.mergeAttributes(element);
   3523 				node.removeAttribute('uniqueNumber');
   3524 				if (node.options){
   3525 					var no = node.options, eo = element.options;
   3526 					for (var j = no.length; j--;) no[j].selected = eo[j].selected;
   3527 				}
   3528 			}
   3529 			/*</ltIE9>*/
   3530 			var prop = formProps[element.tagName.toLowerCase()];
   3531 			if (prop && element[prop]) node[prop] = element[prop];
   3532 		}
   3533 
   3534 		/*<ltIE9>*/
   3535 		if (hasCloneBug){
   3536 			var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object');
   3537 			for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML;
   3538 		}
   3539 		/*</ltIE9>*/
   3540 		return document.id(clone);
   3541 	}
   3542 
   3543 });
   3544 
   3545 [Element, Window, Document].invoke('implement', {
   3546 
   3547 	addListener: function(type, fn){
   3548 		if (window.attachEvent && !window.addEventListener){
   3549 			collected[Slick.uidOf(this)] = this;
   3550 		}
   3551 		if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]);
   3552 		else this.attachEvent('on' + type, fn);
   3553 		return this;
   3554 	},
   3555 
   3556 	removeListener: function(type, fn){
   3557 		if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]);
   3558 		else this.detachEvent('on' + type, fn);
   3559 		return this;
   3560 	},
   3561 
   3562 	retrieve: function(property, dflt){
   3563 		var storage = get(Slick.uidOf(this)), prop = storage[property];
   3564 		if (dflt != null && prop == null) prop = storage[property] = dflt;
   3565 		return prop != null ? prop : null;
   3566 	},
   3567 
   3568 	store: function(property, value){
   3569 		var storage = get(Slick.uidOf(this));
   3570 		storage[property] = value;
   3571 		return this;
   3572 	},
   3573 
   3574 	eliminate: function(property){
   3575 		var storage = get(Slick.uidOf(this));
   3576 		delete storage[property];
   3577 		return this;
   3578 	}
   3579 
   3580 });
   3581 
   3582 /*<ltIE9>*/
   3583 if (window.attachEvent && !window.addEventListener){
   3584 	var gc = function(){
   3585 		Object.each(collected, clean);
   3586 		if (window.CollectGarbage) CollectGarbage();
   3587 		window.removeListener('unload', gc);
   3588 	}
   3589 	window.addListener('unload', gc);
   3590 }
   3591 /*</ltIE9>*/
   3592 
   3593 Element.Properties = {};
   3594 
   3595 
   3596 
   3597 Element.Properties.style = {
   3598 
   3599 	set: function(style){
   3600 		this.style.cssText = style;
   3601 	},
   3602 
   3603 	get: function(){
   3604 		return this.style.cssText;
   3605 	},
   3606 
   3607 	erase: function(){
   3608 		this.style.cssText = '';
   3609 	}
   3610 
   3611 };
   3612 
   3613 Element.Properties.tag = {
   3614 
   3615 	get: function(){
   3616 		return this.tagName.toLowerCase();
   3617 	}
   3618 
   3619 };
   3620 
   3621 Element.Properties.html = {
   3622 
   3623 	set: function(html){
   3624 		if (html == null) html = '';
   3625 		else if (typeOf(html) == 'array') html = html.join('');
   3626 		this.innerHTML = html;
   3627 	},
   3628 
   3629 	erase: function(){
   3630 		this.innerHTML = '';
   3631 	}
   3632 
   3633 };
   3634 
   3635 var supportsHTML5Elements = true, supportsTableInnerHTML = true, supportsTRInnerHTML = true;
   3636 
   3637 /*<ltIE9>*/
   3638 // technique by jdbarlett - http://jdbartlett.com/innershiv/
   3639 var div = document.createElement('div');
   3640 div.innerHTML = '<nav></nav>';
   3641 supportsHTML5Elements = (div.childNodes.length == 1);
   3642 if (!supportsHTML5Elements){
   3643 	var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '),
   3644 		fragment = document.createDocumentFragment(), l = tags.length;
   3645 	while (l--) fragment.createElement(tags[l]);
   3646 }
   3647 div = null;
   3648 /*</ltIE9>*/
   3649 
   3650 /*<IE>*/
   3651 supportsTableInnerHTML = Function.attempt(function(){
   3652 	var table = document.createElement('table');
   3653 	table.innerHTML = '<tr><td></td></tr>';
   3654 	return true;
   3655 });
   3656 
   3657 /*<ltFF4>*/
   3658 var tr = document.createElement('tr'), html = '<td></td>';
   3659 tr.innerHTML = html;
   3660 supportsTRInnerHTML = (tr.innerHTML == html);
   3661 tr = null;
   3662 /*</ltFF4>*/
   3663 
   3664 if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){
   3665 
   3666 	Element.Properties.html.set = (function(set){
   3667 
   3668 		var translations = {
   3669 			table: [1, '<table>', '</table>'],
   3670 			select: [1, '<select>', '</select>'],
   3671 			tbody: [2, '<table><tbody>', '</tbody></table>'],
   3672 			tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
   3673 		};
   3674 
   3675 		translations.thead = translations.tfoot = translations.tbody;
   3676 
   3677 		return function(html){
   3678 			var wrap = translations[this.get('tag')];
   3679 			if (!wrap && !supportsHTML5Elements) wrap = [0, '', ''];
   3680 			if (!wrap) return set.call(this, html);
   3681 
   3682 			var level = wrap[0], wrapper = document.createElement('div'), target = wrapper;
   3683 			if (!supportsHTML5Elements) fragment.appendChild(wrapper);
   3684 			wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join('');
   3685 			while (level--) target = target.firstChild;
   3686 			this.empty().adopt(target.childNodes);
   3687 			if (!supportsHTML5Elements) fragment.removeChild(wrapper);
   3688 			wrapper = null;
   3689 		};
   3690 
   3691 	})(Element.Properties.html.set);
   3692 }
   3693 /*</IE>*/
   3694 
   3695 /*<ltIE9>*/
   3696 var testForm = document.createElement('form');
   3697 testForm.innerHTML = '<select><option>s</option></select>';
   3698 
   3699 if (testForm.firstChild.value != 's') Element.Properties.value = {
   3700 
   3701 	set: function(value){
   3702 		var tag = this.get('tag');
   3703 		if (tag != 'select') return this.setProperty('value', value);
   3704 		var options = this.getElements('option');
   3705 		value = String(value);
   3706 		for (var i = 0; i < options.length; i++){
   3707 			var option = options[i],
   3708 				attr = option.getAttributeNode('value'),
   3709 				optionValue = (attr && attr.specified) ? option.value : option.get('text');
   3710 			if (optionValue === value) return option.selected = true;
   3711 		}
   3712 	},
   3713 
   3714 	get: function(){
   3715 		var option = this, tag = option.get('tag');
   3716 
   3717 		if (tag != 'select' && tag != 'option') return this.getProperty('value');
   3718 
   3719 		if (tag == 'select' && !(option = option.getSelected()[0])) return '';
   3720 
   3721 		var attr = option.getAttributeNode('value');
   3722 		return (attr && attr.specified) ? option.value : option.get('text');
   3723 	}
   3724 
   3725 };
   3726 testForm = null;
   3727 /*</ltIE9>*/
   3728 
   3729 /*<IE>*/
   3730 if (document.createElement('div').getAttributeNode('id')) Element.Properties.id = {
   3731 	set: function(id){
   3732 		this.id = this.getAttributeNode('id').value = id;
   3733 	},
   3734 	get: function(){
   3735 		return this.id || null;
   3736 	},
   3737 	erase: function(){
   3738 		this.id = this.getAttributeNode('id').value = '';
   3739 	}
   3740 };
   3741 /*</IE>*/
   3742 
   3743 })();
   3744 
   3745 
   3746 /*
   3747 ---
   3748 
   3749 name: Element.Style
   3750 
   3751 description: Contains methods for interacting with the styles of Elements in a fashionable way.
   3752 
   3753 license: MIT-style license.
   3754 
   3755 requires: Element
   3756 
   3757 provides: Element.Style
   3758 
   3759 ...
   3760 */
   3761 
   3762 (function(){
   3763 
   3764 var html = document.html, el;
   3765 
   3766 //<ltIE9>
   3767 // Check for oldIE, which does not remove styles when they're set to null
   3768 el = document.createElement('div');
   3769 el.style.color = 'red';
   3770 el.style.color = null;
   3771 var doesNotRemoveStyles = el.style.color == 'red';
   3772 
   3773 // check for oldIE, which returns border* shorthand styles in the wrong order (color-width-style instead of width-style-color)
   3774 var border = '1px solid #123abc';
   3775 el.style.border = border;
   3776 var returnsBordersInWrongOrder = el.style.border != border;
   3777 el = null;
   3778 //</ltIE9>
   3779 
   3780 var hasGetComputedStyle = !!window.getComputedStyle;
   3781 
   3782 Element.Properties.styles = {set: function(styles){
   3783 	this.setStyles(styles);
   3784 }};
   3785 
   3786 var hasOpacity = (html.style.opacity != null),
   3787 	hasFilter = (html.style.filter != null),
   3788 	reAlpha = /alpha\(opacity=([\d.]+)\)/i;
   3789 
   3790 var setVisibility = function(element, opacity){
   3791 	element.store('$opacity', opacity);
   3792 	element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden';
   3793 };
   3794 
   3795 //<ltIE9>
   3796 var setFilter = function(element, regexp, value){
   3797 	var style = element.style,
   3798 		filter = style.filter || element.getComputedStyle('filter') || '';
   3799 	style.filter = (regexp.test(filter) ? filter.replace(regexp, value) : filter + ' ' + value).trim();
   3800 	if (!style.filter) style.removeAttribute('filter');
   3801 };
   3802 //</ltIE9>
   3803 
   3804 var setOpacity = (hasOpacity ? function(element, opacity){
   3805 	element.style.opacity = opacity;
   3806 } : (hasFilter ? function(element, opacity){
   3807 	if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1;
   3808 	if (opacity == null || opacity == 1){
   3809 		setFilter(element, reAlpha, '');
   3810 		if (opacity == 1 && getOpacity(element) != 1) setFilter(element, reAlpha, 'alpha(opacity=100)');
   3811 	} else {
   3812 		setFilter(element, reAlpha, 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')');
   3813 	}
   3814 } : setVisibility));
   3815 
   3816 var getOpacity = (hasOpacity ? function(element){
   3817 	var opacity = element.style.opacity || element.getComputedStyle('opacity');
   3818 	return (opacity == '') ? 1 : opacity.toFloat();
   3819 } : (hasFilter ? function(element){
   3820 	var filter = (element.style.filter || element.getComputedStyle('filter')),
   3821 		opacity;
   3822 	if (filter) opacity = filter.match(reAlpha);
   3823 	return (opacity == null || filter == null) ? 1 : (opacity[1] / 100);
   3824 } : function(element){
   3825 	var opacity = element.retrieve('$opacity');
   3826 	if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1);
   3827 	return opacity;
   3828 }));
   3829 
   3830 var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat',
   3831 	namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'},
   3832 	hasBackgroundPositionXY = (html.style.backgroundPositionX != null);
   3833 
   3834 //<ltIE9>
   3835 var removeStyle = function(style, property){
   3836 	if (property == 'backgroundPosition'){
   3837 		style.removeAttribute(property + 'X');
   3838 		property += 'Y';
   3839 	}
   3840 	style.removeAttribute(property);
   3841 };
   3842 //</ltIE9>
   3843 
   3844 Element.implement({
   3845 
   3846 	getComputedStyle: function(property){
   3847 		if (!hasGetComputedStyle && this.currentStyle) return this.currentStyle[property.camelCase()];
   3848 		var defaultView = Element.getDocument(this).defaultView,
   3849 			computed = defaultView ? defaultView.getComputedStyle(this, null) : null;
   3850 		return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : '';
   3851 	},
   3852 
   3853 	setStyle: function(property, value){
   3854 		if (property == 'opacity'){
   3855 			if (value != null) value = parseFloat(value);
   3856 			setOpacity(this, value);
   3857 			return this;
   3858 		}
   3859 		property = (property == 'float' ? floatName : property).camelCase();
   3860 		if (typeOf(value) != 'string'){
   3861 			var map = (Element.Styles[property] || '@').split(' ');
   3862 			value = Array.from(value).map(function(val, i){
   3863 				if (!map[i]) return '';
   3864 				return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
   3865 			}).join(' ');
   3866 		} else if (value == String(Number(value))){
   3867 			value = Math.round(value);
   3868 		}
   3869 		this.style[property] = value;
   3870 		//<ltIE9>
   3871 		if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){
   3872 			removeStyle(this.style, property);
   3873 		}
   3874 		//</ltIE9>
   3875 		return this;
   3876 	},
   3877 
   3878 	getStyle: function(property){
   3879 		if (property == 'opacity') return getOpacity(this);
   3880 		property = (property == 'float' ? floatName : property).camelCase();
   3881 		var result = this.style[property];
   3882 		if (!result || property == 'zIndex'){
   3883 			if (Element.ShortStyles.hasOwnProperty(property)){
   3884 				result = [];
   3885 				for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
   3886 				return result.join(' ');
   3887 			}
   3888 			result = this.getComputedStyle(property);
   3889 		}
   3890 		if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){
   3891 			return result.replace(/(top|right|bottom|left)/g, function(position){
   3892 				return namedPositions[position];
   3893 			}) || '0px';
   3894 		}
   3895 		if (!result && property == 'backgroundPosition') return '0px 0px';
   3896 		if (result){
   3897 			result = String(result);
   3898 			var color = result.match(/rgba?\([\d\s,]+\)/);
   3899 			if (color) result = result.replace(color[0], color[0].rgbToHex());
   3900 		}
   3901 		if (!hasGetComputedStyle && !this.style[property]){
   3902 			if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){
   3903 				var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
   3904 				values.each(function(value){
   3905 					size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
   3906 				}, this);
   3907 				return this['offset' + property.capitalize()] - size + 'px';
   3908 			}
   3909 			if ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
   3910 				return '0px';
   3911 			}
   3912 		}
   3913 		//<ltIE9>
   3914 		if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){
   3915 			return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1');
   3916 		}
   3917 		//</ltIE9>
   3918 		return result;
   3919 	},
   3920 
   3921 	setStyles: function(styles){
   3922 		for (var style in styles) this.setStyle(style, styles[style]);
   3923 		return this;
   3924 	},
   3925 
   3926 	getStyles: function(){
   3927 		var result = {};
   3928 		Array.flatten(arguments).each(function(key){
   3929 			result[key] = this.getStyle(key);
   3930 		}, this);
   3931 		return result;
   3932 	}
   3933 
   3934 });
   3935 
   3936 Element.Styles = {
   3937 	left: '@px', top: '@px', bottom: '@px', right: '@px',
   3938 	width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
   3939 	backgroundColor: 'rgb(@, @, @)', backgroundSize: '@px', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
   3940 	fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
   3941 	margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
   3942 	borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
   3943 	zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
   3944 };
   3945 
   3946 
   3947 
   3948 
   3949 
   3950 Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
   3951 
   3952 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
   3953 	var Short = Element.ShortStyles;
   3954 	var All = Element.Styles;
   3955 	['margin', 'padding'].each(function(style){
   3956 		var sd = style + direction;
   3957 		Short[style][sd] = All[sd] = '@px';
   3958 	});
   3959 	var bd = 'border' + direction;
   3960 	Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
   3961 	var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
   3962 	Short[bd] = {};
   3963 	Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
   3964 	Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
   3965 	Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
   3966 });
   3967 
   3968 if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'};
   3969 })();
   3970 
   3971 
   3972 /*
   3973 ---
   3974 
   3975 name: Element.Event
   3976 
   3977 description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary.
   3978 
   3979 license: MIT-style license.
   3980 
   3981 requires: [Element, Event]
   3982 
   3983 provides: Element.Event
   3984 
   3985 ...
   3986 */
   3987 
   3988 (function(){
   3989 
   3990 Element.Properties.events = {set: function(events){
   3991 	this.addEvents(events);
   3992 }};
   3993 
   3994 [Element, Window, Document].invoke('implement', {
   3995 
   3996 	addEvent: function(type, fn){
   3997 		var events = this.retrieve('events', {});
   3998 		if (!events[type]) events[type] = {keys: [], values: []};
   3999 		if (events[type].keys.contains(fn)) return this;
   4000 		events[type].keys.push(fn);
   4001 		var realType = type,
   4002 			custom = Element.Events[type],
   4003 			condition = fn,
   4004 			self = this;
   4005 		if (custom){
   4006 			if (custom.onAdd) custom.onAdd.call(this, fn, type);
   4007 			if (custom.condition){
   4008 				condition = function(event){
   4009 					if (custom.condition.call(this, event, type)) return fn.call(this, event);
   4010 					return true;
   4011 				};
   4012 			}
   4013 			if (custom.base) realType = Function.from(custom.base).call(this, type);
   4014 		}
   4015 		var defn = function(){
   4016 			return fn.call(self);
   4017 		};
   4018 		var nativeEvent = Element.NativeEvents[realType];
   4019 		if (nativeEvent){
   4020 			if (nativeEvent == 2){
   4021 				defn = function(event){
   4022 					event = new DOMEvent(event, self.getWindow());
   4023 					if (condition.call(self, event) === false) event.stop();
   4024 				};
   4025 			}
   4026 			this.addListener(realType, defn, arguments[2]);
   4027 		}
   4028 		events[type].values.push(defn);
   4029 		return this;
   4030 	},
   4031 
   4032 	removeEvent: function(type, fn){
   4033 		var events = this.retrieve('events');
   4034 		if (!events || !events[type]) return this;
   4035 		var list = events[type];
   4036 		var index = list.keys.indexOf(fn);
   4037 		if (index == -1) return this;
   4038 		var value = list.values[index];
   4039 		delete list.keys[index];
   4040 		delete list.values[index];
   4041 		var custom = Element.Events[type];
   4042 		if (custom){
   4043 			if (custom.onRemove) custom.onRemove.call(this, fn, type);
   4044 			if (custom.base) type = Function.from(custom.base).call(this, type);
   4045 		}
   4046 		return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this;
   4047 	},
   4048 
   4049 	addEvents: function(events){
   4050 		for (var event in events) this.addEvent(event, events[event]);
   4051 		return this;
   4052 	},
   4053 
   4054 	removeEvents: function(events){
   4055 		var type;
   4056 		if (typeOf(events) == 'object'){
   4057 			for (type in events) this.removeEvent(type, events[type]);
   4058 			return this;
   4059 		}
   4060 		var attached = this.retrieve('events');
   4061 		if (!attached) return this;
   4062 		if (!events){
   4063 			for (type in attached) this.removeEvents(type);
   4064 			this.eliminate('events');
   4065 		} else if (attached[events]){
   4066 			attached[events].keys.each(function(fn){
   4067 				this.removeEvent(events, fn);
   4068 			}, this);
   4069 			delete attached[events];
   4070 		}
   4071 		return this;
   4072 	},
   4073 
   4074 	fireEvent: function(type, args, delay){
   4075 		var events = this.retrieve('events');
   4076 		if (!events || !events[type]) return this;
   4077 		args = Array.from(args);
   4078 
   4079 		events[type].keys.each(function(fn){
   4080 			if (delay) fn.delay(delay, this, args);
   4081 			else fn.apply(this, args);
   4082 		}, this);
   4083 		return this;
   4084 	},
   4085 
   4086 	cloneEvents: function(from, type){
   4087 		from = document.id(from);
   4088 		var events = from.retrieve('events');
   4089 		if (!events) return this;
   4090 		if (!type){
   4091 			for (var eventType in events) this.cloneEvents(from, eventType);
   4092 		} else if (events[type]){
   4093 			events[type].keys.each(function(fn){
   4094 				this.addEvent(type, fn);
   4095 			}, this);
   4096 		}
   4097 		return this;
   4098 	}
   4099 
   4100 });
   4101 
   4102 Element.NativeEvents = {
   4103 	click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
   4104 	mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
   4105 	mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
   4106 	keydown: 2, keypress: 2, keyup: 2, //keyboard
   4107 	orientationchange: 2, // mobile
   4108 	touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch
   4109 	gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture
   4110 	focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements
   4111 	load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
   4112 	hashchange: 1, popstate: 2, // history
   4113 	error: 1, abort: 1, scroll: 1 //misc
   4114 };
   4115 
   4116 Element.Events = {
   4117 	mousewheel: {
   4118 		base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll'
   4119 	}
   4120 };
   4121 
   4122 var check = function(event){
   4123 	var related = event.relatedTarget;
   4124 	if (related == null) return true;
   4125 	if (!related) return false;
   4126 	return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
   4127 };
   4128 
   4129 if ('onmouseenter' in document.documentElement){
   4130 	Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2;
   4131 	Element.MouseenterCheck = check;
   4132 } else {
   4133 	Element.Events.mouseenter = {
   4134 		base: 'mouseover',
   4135 		condition: check
   4136 	};
   4137 
   4138 	Element.Events.mouseleave = {
   4139 		base: 'mouseout',
   4140 		condition: check
   4141 	};
   4142 }
   4143 
   4144 /*<ltIE9>*/
   4145 if (!window.addEventListener){
   4146 	Element.NativeEvents.propertychange = 2;
   4147 	Element.Events.change = {
   4148 		base: function(){
   4149 			var type = this.type;
   4150 			return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change';
   4151 		},
   4152 		condition: function(event){
   4153 			return event.type != 'propertychange' || event.event.propertyName == 'checked';
   4154 		}
   4155 	};
   4156 }
   4157 /*</ltIE9>*/
   4158 
   4159 
   4160 
   4161 })();
   4162 
   4163 
   4164 /*
   4165 ---
   4166 
   4167 name: Element.Delegation
   4168 
   4169 description: Extends the Element native object to include the delegate method for more efficient event management.
   4170 
   4171 license: MIT-style license.
   4172 
   4173 requires: [Element.Event]
   4174 
   4175 provides: [Element.Delegation]
   4176 
   4177 ...
   4178 */
   4179 
   4180 (function(){
   4181 
   4182 var eventListenerSupport = !!window.addEventListener;
   4183 
   4184 Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2;
   4185 
   4186 var bubbleUp = function(self, match, fn, event, target){
   4187 	while (target && target != self){
   4188 		if (match(target, event)) return fn.call(target, event, target);
   4189 		target = document.id(target.parentNode);
   4190 	}
   4191 };
   4192 
   4193 var map = {
   4194 	mouseenter: {
   4195 		base: 'mouseover',
   4196 		condition: Element.MouseenterCheck
   4197 	},
   4198 	mouseleave: {
   4199 		base: 'mouseout',
   4200 		condition: Element.MouseenterCheck
   4201 	},
   4202 	focus: {
   4203 		base: 'focus' + (eventListenerSupport ? '' : 'in'),
   4204 		capture: true
   4205 	},
   4206 	blur: {
   4207 		base: eventListenerSupport ? 'blur' : 'focusout',
   4208 		capture: true
   4209 	}
   4210 };
   4211 
   4212 /*<ltIE9>*/
   4213 var _key = '$delegation:';
   4214 var formObserver = function(type){
   4215 
   4216 	return {
   4217 
   4218 		base: 'focusin',
   4219 
   4220 		remove: function(self, uid){
   4221 			var list = self.retrieve(_key + type + 'listeners', {})[uid];
   4222 			if (list && list.forms) for (var i = list.forms.length; i--;){
   4223 				list.forms[i].removeEvent(type, list.fns[i]);
   4224 			}
   4225 		},
   4226 
   4227 		listen: function(self, match, fn, event, target, uid){
   4228 			var form = (target.get('tag') == 'form') ? target : event.target.getParent('form');
   4229 			if (!form) return;
   4230 
   4231 			var listeners = self.retrieve(_key + type + 'listeners', {}),
   4232 				listener = listeners[uid] || {forms: [], fns: []},
   4233 				forms = listener.forms, fns = listener.fns;
   4234 
   4235 			if (forms.indexOf(form) != -1) return;
   4236 			forms.push(form);
   4237 
   4238 			var _fn = function(event){
   4239 				bubbleUp(self, match, fn, event, target);
   4240 			};
   4241 			form.addEvent(type, _fn);
   4242 			fns.push(_fn);
   4243 
   4244 			listeners[uid] = listener;
   4245 			self.store(_key + type + 'listeners', listeners);
   4246 		}
   4247 	};
   4248 };
   4249 
   4250 var inputObserver = function(type){
   4251 	return {
   4252 		base: 'focusin',
   4253 		listen: function(self, match, fn, event, target){
   4254 			var events = {blur: function(){
   4255 				this.removeEvents(events);
   4256 			}};
   4257 			events[type] = function(event){
   4258 				bubbleUp(self, match, fn, event, target);
   4259 			};
   4260 			event.target.addEvents(events);
   4261 		}
   4262 	};
   4263 };
   4264 
   4265 if (!eventListenerSupport) Object.append(map, {
   4266 	submit: formObserver('submit'),
   4267 	reset: formObserver('reset'),
   4268 	change: inputObserver('change'),
   4269 	select: inputObserver('select')
   4270 });
   4271 /*</ltIE9>*/
   4272 
   4273 var proto = Element.prototype,
   4274 	addEvent = proto.addEvent,
   4275 	removeEvent = proto.removeEvent;
   4276 
   4277 var relay = function(old, method){
   4278 	return function(type, fn, useCapture){
   4279 		if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture);
   4280 		var parsed = Slick.parse(type).expressions[0][0];
   4281 		if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture);
   4282 		var newType = parsed.tag;
   4283 		parsed.pseudos.slice(1).each(function(pseudo){
   4284 			newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : '');
   4285 		});
   4286 		old.call(this, type, fn);
   4287 		return method.call(this, newType, parsed.pseudos[0].value, fn);
   4288 	};
   4289 };
   4290 
   4291 var delegation = {
   4292 
   4293 	addEvent: function(type, match, fn){
   4294 		var storage = this.retrieve('$delegates', {}), stored = storage[type];
   4295 		if (stored) for (var _uid in stored){
   4296 			if (stored[_uid].fn == fn && stored[_uid].match == match) return this;
   4297 		}
   4298 
   4299 		var _type = type, _match = match, _fn = fn, _map = map[type] || {};
   4300 		type = _map.base || _type;
   4301 
   4302 		match = function(target){
   4303 			return Slick.match(target, _match);
   4304 		};
   4305 
   4306 		var elementEvent = Element.Events[_type];
   4307 		if (_map.condition || elementEvent && elementEvent.condition){
   4308 			var __match = match, condition = _map.condition || elementEvent.condition;
   4309 			match = function(target, event){
   4310 				return __match(target, event) && condition.call(target, event, type);
   4311 			};
   4312 		}
   4313 
   4314 		var self = this, uid = String.uniqueID();
   4315 		var delegator = _map.listen ? function(event, target){
   4316 			if (!target && event && event.target) target = event.target;
   4317 			if (target) _map.listen(self, match, fn, event, target, uid);
   4318 		} : function(event, target){
   4319 			if (!target && event && event.target) target = event.target;
   4320 			if (target) bubbleUp(self, match, fn, event, target);
   4321 		};
   4322 
   4323 		if (!stored) stored = {};
   4324 		stored[uid] = {
   4325 			match: _match,
   4326 			fn: _fn,
   4327 			delegator: delegator
   4328 		};
   4329 		storage[_type] = stored;
   4330 		return addEvent.call(this, type, delegator, _map.capture);
   4331 	},
   4332 
   4333 	removeEvent: function(type, match, fn, _uid){
   4334 		var storage = this.retrieve('$delegates', {}), stored = storage[type];
   4335 		if (!stored) return this;
   4336 
   4337 		if (_uid){
   4338 			var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {};
   4339 			type = _map.base || _type;
   4340 			if (_map.remove) _map.remove(this, _uid);
   4341 			delete stored[_uid];
   4342 			storage[_type] = stored;
   4343 			return removeEvent.call(this, type, delegator, _map.capture);
   4344 		}
   4345 
   4346 		var __uid, s;
   4347 		if (fn) for (__uid in stored){
   4348 			s = stored[__uid];
   4349 			if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid);
   4350 		} else for (__uid in stored){
   4351 			s = stored[__uid];
   4352 			if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid);
   4353 		}
   4354 		return this;
   4355 	}
   4356 
   4357 };
   4358 
   4359 [Element, Window, Document].invoke('implement', {
   4360 	addEvent: relay(addEvent, delegation.addEvent),
   4361 	removeEvent: relay(removeEvent, delegation.removeEvent)
   4362 });
   4363 
   4364 })();
   4365 
   4366 
   4367 /*
   4368 ---
   4369 
   4370 name: Element.Dimensions
   4371 
   4372 description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
   4373 
   4374 license: MIT-style license.
   4375 
   4376 credits:
   4377   - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
   4378   - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
   4379 
   4380 requires: [Element, Element.Style]
   4381 
   4382 provides: [Element.Dimensions]
   4383 
   4384 ...
   4385 */
   4386 
   4387 (function(){
   4388 
   4389 var element = document.createElement('div'),
   4390 	child = document.createElement('div');
   4391 element.style.height = '0';
   4392 element.appendChild(child);
   4393 var brokenOffsetParent = (child.offsetParent === element);
   4394 element = child = null;
   4395 
   4396 var isOffset = function(el){
   4397 	return styleString(el, 'position') != 'static' || isBody(el);
   4398 };
   4399 
   4400 var isOffsetStatic = function(el){
   4401 	return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName);
   4402 };
   4403 
   4404 Element.implement({
   4405 
   4406 	scrollTo: function(x, y){
   4407 		if (isBody(this)){
   4408 			this.getWindow().scrollTo(x, y);
   4409 		} else {
   4410 			this.scrollLeft = x;
   4411 			this.scrollTop = y;
   4412 		}
   4413 		return this;
   4414 	},
   4415 
   4416 	getSize: function(){
   4417 		if (isBody(this)) return this.getWindow().getSize();
   4418 		return {x: this.offsetWidth, y: this.offsetHeight};
   4419 	},
   4420 
   4421 	getScrollSize: function(){
   4422 		if (isBody(this)) return this.getWindow().getScrollSize();
   4423 		return {x: this.scrollWidth, y: this.scrollHeight};
   4424 	},
   4425 
   4426 	getScroll: function(){
   4427 		if (isBody(this)) return this.getWindow().getScroll();
   4428 		return {x: this.scrollLeft, y: this.scrollTop};
   4429 	},
   4430 
   4431 	getScrolls: function(){
   4432 		var element = this.parentNode, position = {x: 0, y: 0};
   4433 		while (element && !isBody(element)){
   4434 			position.x += element.scrollLeft;
   4435 			position.y += element.scrollTop;
   4436 			element = element.parentNode;
   4437 		}
   4438 		return position;
   4439 	},
   4440 
   4441 	getOffsetParent: brokenOffsetParent ? function(){
   4442 		var element = this;
   4443 		if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
   4444 
   4445 		var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset;
   4446 		while ((element = element.parentNode)){
   4447 			if (isOffsetCheck(element)) return element;
   4448 		}
   4449 		return null;
   4450 	} : function(){
   4451 		var element = this;
   4452 		if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
   4453 
   4454 		try {
   4455 			return element.offsetParent;
   4456 		} catch(e) {}
   4457 		return null;
   4458 	},
   4459 
   4460 	getOffsets: function(){
   4461 		var hasGetBoundingClientRect = this.getBoundingClientRect;
   4462 
   4463 		if (hasGetBoundingClientRect){
   4464 			var bound = this.getBoundingClientRect(),
   4465 				html = document.id(this.getDocument().documentElement),
   4466 				htmlScroll = html.getScroll(),
   4467 				elemScrolls = this.getScrolls(),
   4468 				isFixed = (styleString(this, 'position') == 'fixed');
   4469 
   4470 			return {
   4471 				x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
   4472 				y: bound.top.toInt()  + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
   4473 			};
   4474 		}
   4475 
   4476 		var element = this, position = {x: 0, y: 0};
   4477 		if (isBody(this)) return position;
   4478 
   4479 		while (element && !isBody(element)){
   4480 			position.x += element.offsetLeft;
   4481 			position.y += element.offsetTop;
   4482 
   4483 			element = element.offsetParent;
   4484 		}
   4485 
   4486 		return position;
   4487 	},
   4488 
   4489 	getPosition: function(relative){
   4490 		var offset = this.getOffsets(),
   4491 			scroll = this.getScrolls();
   4492 		var position = {
   4493 			x: offset.x - scroll.x,
   4494 			y: offset.y - scroll.y
   4495 		};
   4496 
   4497 		if (relative && (relative = document.id(relative))){
   4498 			var relativePosition = relative.getPosition();
   4499 			return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)};
   4500 		}
   4501 		return position;
   4502 	},
   4503 
   4504 	getCoordinates: function(element){
   4505 		if (isBody(this)) return this.getWindow().getCoordinates();
   4506 		var position = this.getPosition(element),
   4507 			size = this.getSize();
   4508 		var obj = {
   4509 			left: position.x,
   4510 			top: position.y,
   4511 			width: size.x,
   4512 			height: size.y
   4513 		};
   4514 		obj.right = obj.left + obj.width;
   4515 		obj.bottom = obj.top + obj.height;
   4516 		return obj;
   4517 	},
   4518 
   4519 	computePosition: function(obj){
   4520 		return {
   4521 			left: obj.x - styleNumber(this, 'margin-left'),
   4522 			top: obj.y - styleNumber(this, 'margin-top')
   4523 		};
   4524 	},
   4525 
   4526 	setPosition: function(obj){
   4527 		return this.setStyles(this.computePosition(obj));
   4528 	}
   4529 
   4530 });
   4531 
   4532 
   4533 [Document, Window].invoke('implement', {
   4534 
   4535 	getSize: function(){
   4536 		var doc = getCompatElement(this);
   4537 		return {x: doc.clientWidth, y: doc.clientHeight};
   4538 	},
   4539 
   4540 	getScroll: function(){
   4541 		var win = this.getWindow(), doc = getCompatElement(this);
   4542 		return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
   4543 	},
   4544 
   4545 	getScrollSize: function(){
   4546 		var doc = getCompatElement(this),
   4547 			min = this.getSize(),
   4548 			body = this.getDocument().body;
   4549 
   4550 		return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)};
   4551 	},
   4552 
   4553 	getPosition: function(){
   4554 		return {x: 0, y: 0};
   4555 	},
   4556 
   4557 	getCoordinates: function(){
   4558 		var size = this.getSize();
   4559 		return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
   4560 	}
   4561 
   4562 });
   4563 
   4564 // private methods
   4565 
   4566 var styleString = Element.getComputedStyle;
   4567 
   4568 function styleNumber(element, style){
   4569 	return styleString(element, style).toInt() || 0;
   4570 }
   4571 
   4572 function borderBox(element){
   4573 	return styleString(element, '-moz-box-sizing') == 'border-box';
   4574 }
   4575 
   4576 function topBorder(element){
   4577 	return styleNumber(element, 'border-top-width');
   4578 }
   4579 
   4580 function leftBorder(element){
   4581 	return styleNumber(element, 'border-left-width');
   4582 }
   4583 
   4584 function isBody(element){
   4585 	return (/^(?:body|html)$/i).test(element.tagName);
   4586 }
   4587 
   4588 function getCompatElement(element){
   4589 	var doc = element.getDocument();
   4590 	return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
   4591 }
   4592 
   4593 })();
   4594 
   4595 //aliases
   4596 Element.alias({position: 'setPosition'}); //compatability
   4597 
   4598 [Window, Document, Element].invoke('implement', {
   4599 
   4600 	getHeight: function(){
   4601 		return this.getSize().y;
   4602 	},
   4603 
   4604 	getWidth: function(){
   4605 		return this.getSize().x;
   4606 	},
   4607 
   4608 	getScrollTop: function(){
   4609 		return this.getScroll().y;
   4610 	},
   4611 
   4612 	getScrollLeft: function(){
   4613 		return this.getScroll().x;
   4614 	},
   4615 
   4616 	getScrollHeight: function(){
   4617 		return this.getScrollSize().y;
   4618 	},
   4619 
   4620 	getScrollWidth: function(){
   4621 		return this.getScrollSize().x;
   4622 	},
   4623 
   4624 	getTop: function(){
   4625 		return this.getPosition().y;
   4626 	},
   4627 
   4628 	getLeft: function(){
   4629 		return this.getPosition().x;
   4630 	}
   4631 
   4632 });
   4633 
   4634 
   4635 /*
   4636 ---
   4637 
   4638 name: Fx
   4639 
   4640 description: Contains the basic animation logic to be extended by all other Fx Classes.
   4641 
   4642 license: MIT-style license.
   4643 
   4644 requires: [Chain, Events, Options]
   4645 
   4646 provides: Fx
   4647 
   4648 ...
   4649 */
   4650 
   4651 (function(){
   4652 
   4653 var Fx = this.Fx = new Class({
   4654 
   4655 	Implements: [Chain, Events, Options],
   4656 
   4657 	options: {
   4658 		/*
   4659 		onStart: nil,
   4660 		onCancel: nil,
   4661 		onComplete: nil,
   4662 		*/
   4663 		fps: 60,
   4664 		unit: false,
   4665 		duration: 500,
   4666 		frames: null,
   4667 		frameSkip: true,
   4668 		link: 'ignore'
   4669 	},
   4670 
   4671 	initialize: function(options){
   4672 		this.subject = this.subject || this;
   4673 		this.setOptions(options);
   4674 	},
   4675 
   4676 	getTransition: function(){
   4677 		return function(p){
   4678 			return -(Math.cos(Math.PI * p) - 1) / 2;
   4679 		};
   4680 	},
   4681 
   4682 	step: function(now){
   4683 		if (this.options.frameSkip){
   4684 			var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval;
   4685 			this.time = now;
   4686 			this.frame += frames;
   4687 		} else {
   4688 			this.frame++;
   4689 		}
   4690 
   4691 		if (this.frame < this.frames){
   4692 			var delta = this.transition(this.frame / this.frames);
   4693 			this.set(this.compute(this.from, this.to, delta));
   4694 		} else {
   4695 			this.frame = this.frames;
   4696 			this.set(this.compute(this.from, this.to, 1));
   4697 			this.stop();
   4698 		}
   4699 	},
   4700 
   4701 	set: function(now){
   4702 		return now;
   4703 	},
   4704 
   4705 	compute: function(from, to, delta){
   4706 		return Fx.compute(from, to, delta);
   4707 	},
   4708 
   4709 	check: function(){
   4710 		if (!this.isRunning()) return true;
   4711 		switch (this.options.link){
   4712 			case 'cancel': this.cancel(); return true;
   4713 			case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
   4714 		}
   4715 		return false;
   4716 	},
   4717 
   4718 	start: function(from, to){
   4719 		if (!this.check(from, to)) return this;
   4720 		this.from = from;
   4721 		this.to = to;
   4722 		this.frame = (this.options.frameSkip) ? 0 : -1;
   4723 		this.time = null;
   4724 		this.transition = this.getTransition();
   4725 		var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration;
   4726 		this.duration = Fx.Durations[duration] || duration.toInt();
   4727 		this.frameInterval = 1000 / fps;
   4728 		this.frames = frames || Math.round(this.duration / this.frameInterval);
   4729 		this.fireEvent('start', this.subject);
   4730 		pushInstance.call(this, fps);
   4731 		return this;
   4732 	},
   4733 
   4734 	stop: function(){
   4735 		if (this.isRunning()){
   4736 			this.time = null;
   4737 			pullInstance.call(this, this.options.fps);
   4738 			if (this.frames == this.frame){
   4739 				this.fireEvent('complete', this.subject);
   4740 				if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
   4741 			} else {
   4742 				this.fireEvent('stop', this.subject);
   4743 			}
   4744 		}
   4745 		return this;
   4746 	},
   4747 
   4748 	cancel: function(){
   4749 		if (this.isRunning()){
   4750 			this.time = null;
   4751 			pullInstance.call(this, this.options.fps);
   4752 			this.frame = this.frames;
   4753 			this.fireEvent('cancel', this.subject).clearChain();
   4754 		}
   4755 		return this;
   4756 	},
   4757 
   4758 	pause: function(){
   4759 		if (this.isRunning()){
   4760 			this.time = null;
   4761 			pullInstance.call(this, this.options.fps);
   4762 		}
   4763 		return this;
   4764 	},
   4765 
   4766 	resume: function(){
   4767 		if (this.isPaused()) pushInstance.call(this, this.options.fps);
   4768 		return this;
   4769 	},
   4770 
   4771 	isRunning: function(){
   4772 		var list = instances[this.options.fps];
   4773 		return list && list.contains(this);
   4774 	},
   4775 
   4776 	isPaused: function(){
   4777 		return (this.frame < this.frames) && !this.isRunning();
   4778 	}
   4779 
   4780 });
   4781 
   4782 Fx.compute = function(from, to, delta){
   4783 	return (to - from) * delta + from;
   4784 };
   4785 
   4786 Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
   4787 
   4788 // global timers
   4789 
   4790 var instances = {}, timers = {};
   4791 
   4792 var loop = function(){
   4793 	var now = Date.now();
   4794 	for (var i = this.length; i--;){
   4795 		var instance = this[i];
   4796 		if (instance) instance.step(now);
   4797 	}
   4798 };
   4799 
   4800 var pushInstance = function(fps){
   4801 	var list = instances[fps] || (instances[fps] = []);
   4802 	list.push(this);
   4803 	if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list);
   4804 };
   4805 
   4806 var pullInstance = function(fps){
   4807 	var list = instances[fps];
   4808 	if (list){
   4809 		list.erase(this);
   4810 		if (!list.length && timers[fps]){
   4811 			delete instances[fps];
   4812 			timers[fps] = clearInterval(timers[fps]);
   4813 		}
   4814 	}
   4815 };
   4816 
   4817 })();
   4818 
   4819 
   4820 /*
   4821 ---
   4822 
   4823 name: Fx.CSS
   4824 
   4825 description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
   4826 
   4827 license: MIT-style license.
   4828 
   4829 requires: [Fx, Element.Style]
   4830 
   4831 provides: Fx.CSS
   4832 
   4833 ...
   4834 */
   4835 
   4836 Fx.CSS = new Class({
   4837 
   4838 	Extends: Fx,
   4839 
   4840 	//prepares the base from/to object
   4841 
   4842 	prepare: function(element, property, values){
   4843 		values = Array.from(values);
   4844 		var from = values[0], to = values[1];
   4845 		if (to == null){
   4846 			to = from;
   4847 			from = element.getStyle(property);
   4848 			var unit = this.options.unit;
   4849 			// adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299
   4850 			if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){
   4851 				element.setStyle(property, to + unit);
   4852 				var value = element.getComputedStyle(property);
   4853 				// IE and Opera support pixelLeft or pixelWidth
   4854 				if (!(/px$/.test(value))){
   4855 					value = element.style[('pixel-' + property).camelCase()];
   4856 					if (value == null){
   4857 						// adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
   4858 						var left = element.style.left;
   4859 						element.style.left = to + unit;
   4860 						value = element.style.pixelLeft;
   4861 						element.style.left = left;
   4862 					}
   4863 				}
   4864 				from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0);
   4865 				element.setStyle(property, from + unit);
   4866 			}
   4867 		}
   4868 		return {from: this.parse(from), to: this.parse(to)};
   4869 	},
   4870 
   4871 	//parses a value into an array
   4872 
   4873 	parse: function(value){
   4874 		value = Function.from(value)();
   4875 		value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
   4876 		return value.map(function(val){
   4877 			val = String(val);
   4878 			var found = false;
   4879 			Object.each(Fx.CSS.Parsers, function(parser, key){
   4880 				if (found) return;
   4881 				var parsed = parser.parse(val);
   4882 				if (parsed || parsed === 0) found = {value: parsed, parser: parser};
   4883 			});
   4884 			found = found || {value: val, parser: Fx.CSS.Parsers.String};
   4885 			return found;
   4886 		});
   4887 	},
   4888 
   4889 	//computes by a from and to prepared objects, using their parsers.
   4890 
   4891 	compute: function(from, to, delta){
   4892 		var computed = [];
   4893 		(Math.min(from.length, to.length)).times(function(i){
   4894 			computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
   4895 		});
   4896 		computed.$family = Function.from('fx:css:value');
   4897 		return computed;
   4898 	},
   4899 
   4900 	//serves the value as settable
   4901 
   4902 	serve: function(value, unit){
   4903 		if (typeOf(value) != 'fx:css:value') value = this.parse(value);
   4904 		var returned = [];
   4905 		value.each(function(bit){
   4906 			returned = returned.concat(bit.parser.serve(bit.value, unit));
   4907 		});
   4908 		return returned;
   4909 	},
   4910 
   4911 	//renders the change to an element
   4912 
   4913 	render: function(element, property, value, unit){
   4914 		element.setStyle(property, this.serve(value, unit));
   4915 	},
   4916 
   4917 	//searches inside the page css to find the values for a selector
   4918 
   4919 	search: function(selector){
   4920 		if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
   4921 		var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
   4922 
   4923 		var searchStyles = function(rules){
   4924 			Array.each(rules, function(rule, i){
   4925 				if (rule.media){
   4926 					searchStyles(rule.rules || rule.cssRules);
   4927 					return;
   4928 				}
   4929 				if (!rule.style) return;
   4930 				var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
   4931 					return m.toLowerCase();
   4932 				}) : null;
   4933 				if (!selectorText || !selectorTest.test(selectorText)) return;
   4934 				Object.each(Element.Styles, function(value, style){
   4935 					if (!rule.style[style] || Element.ShortStyles[style]) return;
   4936 					value = String(rule.style[style]);
   4937 					to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
   4938 				});
   4939 			});
   4940 		};
   4941 
   4942 		Array.each(document.styleSheets, function(sheet, j){
   4943 			var href = sheet.href;
   4944 			if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return;
   4945 			var rules = sheet.rules || sheet.cssRules;
   4946 			searchStyles(rules);
   4947 		});
   4948 		return Fx.CSS.Cache[selector] = to;
   4949 	}
   4950 
   4951 });
   4952 
   4953 Fx.CSS.Cache = {};
   4954 
   4955 Fx.CSS.Parsers = {
   4956 
   4957 	Color: {
   4958 		parse: function(value){
   4959 			if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
   4960 			return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
   4961 		},
   4962 		compute: function(from, to, delta){
   4963 			return from.map(function(value, i){
   4964 				return Math.round(Fx.compute(from[i], to[i], delta));
   4965 			});
   4966 		},
   4967 		serve: function(value){
   4968 			return value.map(Number);
   4969 		}
   4970 	},
   4971 
   4972 	Number: {
   4973 		parse: parseFloat,
   4974 		compute: Fx.compute,
   4975 		serve: function(value, unit){
   4976 			return (unit) ? value + unit : value;
   4977 		}
   4978 	},
   4979 
   4980 	String: {
   4981 		parse: Function.from(false),
   4982 		compute: function(zero, one){
   4983 			return one;
   4984 		},
   4985 		serve: function(zero){
   4986 			return zero;
   4987 		}
   4988 	}
   4989 
   4990 };
   4991 
   4992 
   4993 
   4994 
   4995 /*
   4996 ---
   4997 
   4998 name: Fx.Tween
   4999 
   5000 description: Formerly Fx.Style, effect to transition any CSS property for an element.
   5001 
   5002 license: MIT-style license.
   5003 
   5004 requires: Fx.CSS
   5005 
   5006 provides: [Fx.Tween, Element.fade, Element.highlight]
   5007 
   5008 ...
   5009 */
   5010 
   5011 Fx.Tween = new Class({
   5012 
   5013 	Extends: Fx.CSS,
   5014 
   5015 	initialize: function(element, options){
   5016 		this.element = this.subject = document.id(element);
   5017 		this.parent(options);
   5018 	},
   5019 
   5020 	set: function(property, now){
   5021 		if (arguments.length == 1){
   5022 			now = property;
   5023 			property = this.property || this.options.property;
   5024 		}
   5025 		this.render(this.element, property, now, this.options.unit);
   5026 		return this;
   5027 	},
   5028 
   5029 	start: function(property, from, to){
   5030 		if (!this.check(property, from, to)) return this;
   5031 		var args = Array.flatten(arguments);
   5032 		this.property = this.options.property || args.shift();
   5033 		var parsed = this.prepare(this.element, this.property, args);
   5034 		return this.parent(parsed.from, parsed.to);
   5035 	}
   5036 
   5037 });
   5038 
   5039 Element.Properties.tween = {
   5040 
   5041 	set: function(options){
   5042 		this.get('tween').cancel().setOptions(options);
   5043 		return this;
   5044 	},
   5045 
   5046 	get: function(){
   5047 		var tween = this.retrieve('tween');
   5048 		if (!tween){
   5049 			tween = new Fx.Tween(this, {link: 'cancel'});
   5050 			this.store('tween', tween);
   5051 		}
   5052 		return tween;
   5053 	}
   5054 
   5055 };
   5056 
   5057 Element.implement({
   5058 
   5059 	tween: function(property, from, to){
   5060 		this.get('tween').start(property, from, to);
   5061 		return this;
   5062 	},
   5063 
   5064 	fade: function(how){
   5065 		var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle;
   5066 		if (args[1] == null) args[1] = 'toggle';
   5067 		switch (args[1]){
   5068 			case 'in': method = 'start'; args[1] = 1; break;
   5069 			case 'out': method = 'start'; args[1] = 0; break;
   5070 			case 'show': method = 'set'; args[1] = 1; break;
   5071 			case 'hide': method = 'set'; args[1] = 0; break;
   5072 			case 'toggle':
   5073 				var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1);
   5074 				method = 'start';
   5075 				args[1] = flag ? 0 : 1;
   5076 				this.store('fade:flag', !flag);
   5077 				toggle = true;
   5078 			break;
   5079 			default: method = 'start';
   5080 		}
   5081 		if (!toggle) this.eliminate('fade:flag');
   5082 		fade[method].apply(fade, args);
   5083 		var to = args[args.length - 1];
   5084 		if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible');
   5085 		else fade.chain(function(){
   5086 			this.element.setStyle('visibility', 'hidden');
   5087 			this.callChain();
   5088 		});
   5089 		return this;
   5090 	},
   5091 
   5092 	highlight: function(start, end){
   5093 		if (!end){
   5094 			end = this.retrieve('highlight:original', this.getStyle('background-color'));
   5095 			end = (end == 'transparent') ? '#fff' : end;
   5096 		}
   5097 		var tween = this.get('tween');
   5098 		tween.start('background-color', start || '#ffff88', end).chain(function(){
   5099 			this.setStyle('background-color', this.retrieve('highlight:original'));
   5100 			tween.callChain();
   5101 		}.bind(this));
   5102 		return this;
   5103 	}
   5104 
   5105 });
   5106 
   5107 
   5108 /*
   5109 ---
   5110 
   5111 name: Fx.Morph
   5112 
   5113 description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
   5114 
   5115 license: MIT-style license.
   5116 
   5117 requires: Fx.CSS
   5118 
   5119 provides: Fx.Morph
   5120 
   5121 ...
   5122 */
   5123 
   5124 Fx.Morph = new Class({
   5125 
   5126 	Extends: Fx.CSS,
   5127 
   5128 	initialize: function(element, options){
   5129 		this.element = this.subject = document.id(element);
   5130 		this.parent(options);
   5131 	},
   5132 
   5133 	set: function(now){
   5134 		if (typeof now == 'string') now = this.search(now);
   5135 		for (var p in now) this.render(this.element, p, now[p], this.options.unit);
   5136 		return this;
   5137 	},
   5138 
   5139 	compute: function(from, to, delta){
   5140 		var now = {};
   5141 		for (var p in from) now[p] = this.parent(from[p], to[p], delta);
   5142 		return now;
   5143 	},
   5144 
   5145 	start: function(properties){
   5146 		if (!this.check(properties)) return this;
   5147 		if (typeof properties == 'string') properties = this.search(properties);
   5148 		var from = {}, to = {};
   5149 		for (var p in properties){
   5150 			var parsed = this.prepare(this.element, p, properties[p]);
   5151 			from[p] = parsed.from;
   5152 			to[p] = parsed.to;
   5153 		}
   5154 		return this.parent(from, to);
   5155 	}
   5156 
   5157 });
   5158 
   5159 Element.Properties.morph = {
   5160 
   5161 	set: function(options){
   5162 		this.get('morph').cancel().setOptions(options);
   5163 		return this;
   5164 	},
   5165 
   5166 	get: function(){
   5167 		var morph = this.retrieve('morph');
   5168 		if (!morph){
   5169 			morph = new Fx.Morph(this, {link: 'cancel'});
   5170 			this.store('morph', morph);
   5171 		}
   5172 		return morph;
   5173 	}
   5174 
   5175 };
   5176 
   5177 Element.implement({
   5178 
   5179 	morph: function(props){
   5180 		this.get('morph').start(props);
   5181 		return this;
   5182 	}
   5183 
   5184 });
   5185 
   5186 
   5187 /*
   5188 ---
   5189 
   5190 name: Fx.Transitions
   5191 
   5192 description: Contains a set of advanced transitions to be used with any of the Fx Classes.
   5193 
   5194 license: MIT-style license.
   5195 
   5196 credits:
   5197   - Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
   5198 
   5199 requires: Fx
   5200 
   5201 provides: Fx.Transitions
   5202 
   5203 ...
   5204 */
   5205 
   5206 Fx.implement({
   5207 
   5208 	getTransition: function(){
   5209 		var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
   5210 		if (typeof trans == 'string'){
   5211 			var data = trans.split(':');
   5212 			trans = Fx.Transitions;
   5213 			trans = trans[data[0]] || trans[data[0].capitalize()];
   5214 			if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
   5215 		}
   5216 		return trans;
   5217 	}
   5218 
   5219 });
   5220 
   5221 Fx.Transition = function(transition, params){
   5222 	params = Array.from(params);
   5223 	var easeIn = function(pos){
   5224 		return transition(pos, params);
   5225 	};
   5226 	return Object.append(easeIn, {
   5227 		easeIn: easeIn,
   5228 		easeOut: function(pos){
   5229 			return 1 - transition(1 - pos, params);
   5230 		},
   5231 		easeInOut: function(pos){
   5232 			return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2;
   5233 		}
   5234 	});
   5235 };
   5236 
   5237 Fx.Transitions = {
   5238 
   5239 	linear: function(zero){
   5240 		return zero;
   5241 	}
   5242 
   5243 };
   5244 
   5245 
   5246 
   5247 Fx.Transitions.extend = function(transitions){
   5248 	for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
   5249 };
   5250 
   5251 Fx.Transitions.extend({
   5252 
   5253 	Pow: function(p, x){
   5254 		return Math.pow(p, x && x[0] || 6);
   5255 	},
   5256 
   5257 	Expo: function(p){
   5258 		return Math.pow(2, 8 * (p - 1));
   5259 	},
   5260 
   5261 	Circ: function(p){
   5262 		return 1 - Math.sin(Math.acos(p));
   5263 	},
   5264 
   5265 	Sine: function(p){
   5266 		return 1 - Math.cos(p * Math.PI / 2);
   5267 	},
   5268 
   5269 	Back: function(p, x){
   5270 		x = x && x[0] || 1.618;
   5271 		return Math.pow(p, 2) * ((x + 1) * p - x);
   5272 	},
   5273 
   5274 	Bounce: function(p){
   5275 		var value;
   5276 		for (var a = 0, b = 1; 1; a += b, b /= 2){
   5277 			if (p >= (7 - 4 * a) / 11){
   5278 				value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
   5279 				break;
   5280 			}
   5281 		}
   5282 		return value;
   5283 	},
   5284 
   5285 	Elastic: function(p, x){
   5286 		return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3);
   5287 	}
   5288 
   5289 });
   5290 
   5291 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
   5292 	Fx.Transitions[transition] = new Fx.Transition(function(p){
   5293 		return Math.pow(p, i + 2);
   5294 	});
   5295 });
   5296 
   5297 
   5298 /*
   5299 ---
   5300 
   5301 name: Request
   5302 
   5303 description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
   5304 
   5305 license: MIT-style license.
   5306 
   5307 requires: [Object, Element, Chain, Events, Options, Browser]
   5308 
   5309 provides: Request
   5310 
   5311 ...
   5312 */
   5313 
   5314 (function(){
   5315 
   5316 var empty = function(){},
   5317 	progressSupport = ('onprogress' in new Browser.Request);
   5318 
   5319 var Request = this.Request = new Class({
   5320 
   5321 	Implements: [Chain, Events, Options],
   5322 
   5323 	options: {/*
   5324 		onRequest: function(){},
   5325 		onLoadstart: function(event, xhr){},
   5326 		onProgress: function(event, xhr){},
   5327 		onComplete: function(){},
   5328 		onCancel: function(){},
   5329 		onSuccess: function(responseText, responseXML){},
   5330 		onFailure: function(xhr){},
   5331 		onException: function(headerName, value){},
   5332 		onTimeout: function(){},
   5333 		user: '',
   5334 		password: '',*/
   5335 		url: '',
   5336 		data: '',
   5337 		headers: {
   5338 			'X-Requested-With': 'XMLHttpRequest',
   5339 			'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
   5340 		},
   5341 		async: true,
   5342 		format: false,
   5343 		method: 'post',
   5344 		link: 'ignore',
   5345 		isSuccess: null,
   5346 		emulation: true,
   5347 		urlEncoded: true,
   5348 		encoding: 'utf-8',
   5349 		evalScripts: false,
   5350 		evalResponse: false,
   5351 		timeout: 0,
   5352 		noCache: false
   5353 	},
   5354 
   5355 	initialize: function(options){
   5356 		this.xhr = new Browser.Request();
   5357 		this.setOptions(options);
   5358 		this.headers = this.options.headers;
   5359 	},
   5360 
   5361 	onStateChange: function(){
   5362 		var xhr = this.xhr;
   5363 		if (xhr.readyState != 4 || !this.running) return;
   5364 		this.running = false;
   5365 		this.status = 0;
   5366 		Function.attempt(function(){
   5367 			var status = xhr.status;
   5368 			this.status = (status == 1223) ? 204 : status;
   5369 		}.bind(this));
   5370 		xhr.onreadystatechange = empty;
   5371 		if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
   5372 		clearTimeout(this.timer);
   5373 
   5374 		this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
   5375 		if (this.options.isSuccess.call(this, this.status))
   5376 			this.success(this.response.text, this.response.xml);
   5377 		else
   5378 			this.failure();
   5379 	},
   5380 
   5381 	isSuccess: function(){
   5382 		var status = this.status;
   5383 		return (status >= 200 && status < 300);
   5384 	},
   5385 
   5386 	isRunning: function(){
   5387 		return !!this.running;
   5388 	},
   5389 
   5390 	processScripts: function(text){
   5391 		if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text);
   5392 		return text.stripScripts(this.options.evalScripts);
   5393 	},
   5394 
   5395 	success: function(text, xml){
   5396 		this.onSuccess(this.processScripts(text), xml);
   5397 	},
   5398 
   5399 	onSuccess: function(){
   5400 		this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
   5401 	},
   5402 
   5403 	failure: function(){
   5404 		this.onFailure();
   5405 	},
   5406 
   5407 	onFailure: function(){
   5408 		this.fireEvent('complete').fireEvent('failure', this.xhr);
   5409 	},
   5410 
   5411 	loadstart: function(event){
   5412 		this.fireEvent('loadstart', [event, this.xhr]);
   5413 	},
   5414 
   5415 	progress: function(event){
   5416 		this.fireEvent('progress', [event, this.xhr]);
   5417 	},
   5418 
   5419 	timeout: function(){
   5420 		this.fireEvent('timeout', this.xhr);
   5421 	},
   5422 
   5423 	setHeader: function(name, value){
   5424 		this.headers[name] = value;
   5425 		return this;
   5426 	},
   5427 
   5428 	getHeader: function(name){
   5429 		return Function.attempt(function(){
   5430 			return this.xhr.getResponseHeader(name);
   5431 		}.bind(this));
   5432 	},
   5433 
   5434 	check: function(){
   5435 		if (!this.running) return true;
   5436 		switch (this.options.link){
   5437 			case 'cancel': this.cancel(); return true;
   5438 			case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
   5439 		}
   5440 		return false;
   5441 	},
   5442 
   5443 	send: function(options){
   5444 		if (!this.check(options)) return this;
   5445 
   5446 		this.options.isSuccess = this.options.isSuccess || this.isSuccess;
   5447 		this.running = true;
   5448 
   5449 		var type = typeOf(options);
   5450 		if (type == 'string' || type == 'element') options = {data: options};
   5451 
   5452 		var old = this.options;
   5453 		options = Object.append({data: old.data, url: old.url, method: old.method}, options);
   5454 		var data = options.data, url = String(options.url), method = options.method.toLowerCase();
   5455 
   5456 		switch (typeOf(data)){
   5457 			case 'element': data = document.id(data).toQueryString(); break;
   5458 			case 'object': case 'hash': data = Object.toQueryString(data);
   5459 		}
   5460 
   5461 		if (this.options.format){
   5462 			var format = 'format=' + this.options.format;
   5463 			data = (data) ? format + '&' + data : format;
   5464 		}
   5465 
   5466 		if (this.options.emulation && !['get', 'post'].contains(method)){
   5467 			var _method = '_method=' + method;
   5468 			data = (data) ? _method + '&' + data : _method;
   5469 			method = 'post';
   5470 		}
   5471 
   5472 		if (this.options.urlEncoded && ['post', 'put'].contains(method)){
   5473 			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
   5474 			this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding;
   5475 		}
   5476 
   5477 		if (!url) url = document.location.pathname;
   5478 
   5479 		var trimPosition = url.lastIndexOf('/');
   5480 		if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
   5481 
   5482 		if (this.options.noCache)
   5483 			url += (url.indexOf('?') > -1 ? '&' : '?') + String.uniqueID();
   5484 
   5485 		if (data && (method == 'get' || method == 'delete')){
   5486 			url += (url.indexOf('?') > -1 ? '&' : '?') + data;
   5487 			data = null;
   5488 		}
   5489 
   5490 		var xhr = this.xhr;
   5491 		if (progressSupport){
   5492 			xhr.onloadstart = this.loadstart.bind(this);
   5493 			xhr.onprogress = this.progress.bind(this);
   5494 		}
   5495 
   5496 		xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
   5497 		if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;
   5498 
   5499 		xhr.onreadystatechange = this.onStateChange.bind(this);
   5500 
   5501 		Object.each(this.headers, function(value, key){
   5502 			try {
   5503 				xhr.setRequestHeader(key, value);
   5504 			} catch (e){
   5505 				this.fireEvent('exception', [key, value]);
   5506 			}
   5507 		}, this);
   5508 
   5509 		this.fireEvent('request');
   5510 		xhr.send(data);
   5511 		if (!this.options.async) this.onStateChange();
   5512 		else if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this);
   5513 		return this;
   5514 	},
   5515 
   5516 	cancel: function(){
   5517 		if (!this.running) return this;
   5518 		this.running = false;
   5519 		var xhr = this.xhr;
   5520 		xhr.abort();
   5521 		clearTimeout(this.timer);
   5522 		xhr.onreadystatechange = empty;
   5523 		if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
   5524 		this.xhr = new Browser.Request();
   5525 		this.fireEvent('cancel');
   5526 		return this;
   5527 	}
   5528 
   5529 });
   5530 
   5531 var methods = {};
   5532 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
   5533 	methods[method] = function(data){
   5534 		var object = {
   5535 			method: method
   5536 		};
   5537 		if (data != null) object.data = data;
   5538 		return this.send(object);
   5539 	};
   5540 });
   5541 
   5542 Request.implement(methods);
   5543 
   5544 Element.Properties.send = {
   5545 
   5546 	set: function(options){
   5547 		var send = this.get('send').cancel();
   5548 		send.setOptions(options);
   5549 		return this;
   5550 	},
   5551 
   5552 	get: function(){
   5553 		var send = this.retrieve('send');
   5554 		if (!send){
   5555 			send = new Request({
   5556 				data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
   5557 			});
   5558 			this.store('send', send);
   5559 		}
   5560 		return send;
   5561 	}
   5562 
   5563 };
   5564 
   5565 Element.implement({
   5566 
   5567 	send: function(url){
   5568 		var sender = this.get('send');
   5569 		sender.send({data: this, url: url || sender.options.url});
   5570 		return this;
   5571 	}
   5572 
   5573 });
   5574 
   5575 })();
   5576 
   5577 
   5578 /*
   5579 ---
   5580 
   5581 name: Request.HTML
   5582 
   5583 description: Extends the basic Request Class with additional methods for interacting with HTML responses.
   5584 
   5585 license: MIT-style license.
   5586 
   5587 requires: [Element, Request]
   5588 
   5589 provides: Request.HTML
   5590 
   5591 ...
   5592 */
   5593 
   5594 Request.HTML = new Class({
   5595 
   5596 	Extends: Request,
   5597 
   5598 	options: {
   5599 		update: false,
   5600 		append: false,
   5601 		evalScripts: true,
   5602 		filter: false,
   5603 		headers: {
   5604 			Accept: 'text/html, application/xml, text/xml, */*'
   5605 		}
   5606 	},
   5607 
   5608 	success: function(text){
   5609 		var options = this.options, response = this.response;
   5610 
   5611 		response.html = text.stripScripts(function(script){
   5612 			response.javascript = script;
   5613 		});
   5614 
   5615 		var match = response.html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
   5616 		if (match) response.html = match[1];
   5617 		var temp = new Element('div').set('html', response.html);
   5618 
   5619 		response.tree = temp.childNodes;
   5620 		response.elements = temp.getElements(options.filter || '*');
   5621 
   5622 		if (options.filter) response.tree = response.elements;
   5623 		if (options.update){
   5624 			var update = document.id(options.update).empty();
   5625 			if (options.filter) update.adopt(response.elements);
   5626 			else update.set('html', response.html);
   5627 		} else if (options.append){
   5628 			var append = document.id(options.append);
   5629 			if (options.filter) response.elements.reverse().inject(append);
   5630 			else append.adopt(temp.getChildren());
   5631 		}
   5632 		if (options.evalScripts) Browser.exec(response.javascript);
   5633 
   5634 		this.onSuccess(response.tree, response.elements, response.html, response.javascript);
   5635 	}
   5636 
   5637 });
   5638 
   5639 Element.Properties.load = {
   5640 
   5641 	set: function(options){
   5642 		var load = this.get('load').cancel();
   5643 		load.setOptions(options);
   5644 		return this;
   5645 	},
   5646 
   5647 	get: function(){
   5648 		var load = this.retrieve('load');
   5649 		if (!load){
   5650 			load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'});
   5651 			this.store('load', load);
   5652 		}
   5653 		return load;
   5654 	}
   5655 
   5656 };
   5657 
   5658 Element.implement({
   5659 
   5660 	load: function(){
   5661 		this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString}));
   5662 		return this;
   5663 	}
   5664 
   5665 });
   5666 
   5667 
   5668 /*
   5669 ---
   5670 
   5671 name: JSON
   5672 
   5673 description: JSON encoder and decoder.
   5674 
   5675 license: MIT-style license.
   5676 
   5677 SeeAlso: <http://www.json.org/>
   5678 
   5679 requires: [Array, String, Number, Function]
   5680 
   5681 provides: JSON
   5682 
   5683 ...
   5684 */
   5685 
   5686 if (typeof JSON == 'undefined') this.JSON = {};
   5687 
   5688 
   5689 
   5690 (function(){
   5691 
   5692 var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
   5693 
   5694 var escape = function(chr){
   5695 	return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
   5696 };
   5697 
   5698 JSON.validate = function(string){
   5699 	string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
   5700 					replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
   5701 					replace(/(?:^|:|,)(?:\s*\[)+/g, '');
   5702 
   5703 	return (/^[\],:{}\s]*$/).test(string);
   5704 };
   5705 
   5706 JSON.encode = JSON.stringify ? function(obj){
   5707 	return JSON.stringify(obj);
   5708 } : function(obj){
   5709 	if (obj && obj.toJSON) obj = obj.toJSON();
   5710 
   5711 	switch (typeOf(obj)){
   5712 		case 'string':
   5713 			return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
   5714 		case 'array':
   5715 			return '[' + obj.map(JSON.encode).clean() + ']';
   5716 		case 'object': case 'hash':
   5717 			var string = [];
   5718 			Object.each(obj, function(value, key){
   5719 				var json = JSON.encode(value);
   5720 				if (json) string.push(JSON.encode(key) + ':' + json);
   5721 			});
   5722 			return '{' + string + '}';
   5723 		case 'number': case 'boolean': return '' + obj;
   5724 		case 'null': return 'null';
   5725 	}
   5726 
   5727 	return null;
   5728 };
   5729 
   5730 JSON.secure = true;
   5731 
   5732 
   5733 JSON.decode = function(string, secure){
   5734 	if (!string || typeOf(string) != 'string') return null;
   5735 
   5736 	if (secure == null) secure = JSON.secure;
   5737 	if (secure){
   5738 		if (JSON.parse) return JSON.parse(string);
   5739 		if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
   5740 	}
   5741 
   5742 	return eval('(' + string + ')');
   5743 };
   5744 
   5745 })();
   5746 
   5747 
   5748 /*
   5749 ---
   5750 
   5751 name: Request.JSON
   5752 
   5753 description: Extends the basic Request Class with additional methods for sending and receiving JSON data.
   5754 
   5755 license: MIT-style license.
   5756 
   5757 requires: [Request, JSON]
   5758 
   5759 provides: Request.JSON
   5760 
   5761 ...
   5762 */
   5763 
   5764 Request.JSON = new Class({
   5765 
   5766 	Extends: Request,
   5767 
   5768 	options: {
   5769 		/*onError: function(text, error){},*/
   5770 		secure: true
   5771 	},
   5772 
   5773 	initialize: function(options){
   5774 		this.parent(options);
   5775 		Object.append(this.headers, {
   5776 			'Accept': 'application/json',
   5777 			'X-Request': 'JSON'
   5778 		});
   5779 	},
   5780 
   5781 	success: function(text){
   5782 		var json;
   5783 		try {
   5784 			json = this.response.json = JSON.decode(text, this.options.secure);
   5785 		} catch (error){
   5786 			this.fireEvent('error', [text, error]);
   5787 			return;
   5788 		}
   5789 		if (json == null) this.onFailure();
   5790 		else this.onSuccess(json, text);
   5791 	}
   5792 
   5793 });
   5794 
   5795 
   5796 /*
   5797 ---
   5798 
   5799 name: Cookie
   5800 
   5801 description: Class for creating, reading, and deleting browser Cookies.
   5802 
   5803 license: MIT-style license.
   5804 
   5805 credits:
   5806   - Based on the functions by Peter-Paul Koch (http://quirksmode.org).
   5807 
   5808 requires: [Options, Browser]
   5809 
   5810 provides: Cookie
   5811 
   5812 ...
   5813 */
   5814 
   5815 var Cookie = new Class({
   5816 
   5817 	Implements: Options,
   5818 
   5819 	options: {
   5820 		path: '/',
   5821 		domain: false,
   5822 		duration: false,
   5823 		secure: false,
   5824 		document: document,
   5825 		encode: true
   5826 	},
   5827 
   5828 	initialize: function(key, options){
   5829 		this.key = key;
   5830 		this.setOptions(options);
   5831 	},
   5832 
   5833 	write: function(value){
   5834 		if (this.options.encode) value = encodeURIComponent(value);
   5835 		if (this.options.domain) value += '; domain=' + this.options.domain;
   5836 		if (this.options.path) value += '; path=' + this.options.path;
   5837 		if (this.options.duration){
   5838 			var date = new Date();
   5839 			date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
   5840 			value += '; expires=' + date.toGMTString();
   5841 		}
   5842 		if (this.options.secure) value += '; secure';
   5843 		this.options.document.cookie = this.key + '=' + value;
   5844 		return this;
   5845 	},
   5846 
   5847 	read: function(){
   5848 		var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
   5849 		return (value) ? decodeURIComponent(value[1]) : null;
   5850 	},
   5851 
   5852 	dispose: function(){
   5853 		new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write('');
   5854 		return this;
   5855 	}
   5856 
   5857 });
   5858 
   5859 Cookie.write = function(key, value, options){
   5860 	return new Cookie(key, options).write(value);
   5861 };
   5862 
   5863 Cookie.read = function(key){
   5864 	return new Cookie(key).read();
   5865 };
   5866 
   5867 Cookie.dispose = function(key, options){
   5868 	return new Cookie(key, options).dispose();
   5869 };
   5870 
   5871 
   5872 /*
   5873 ---
   5874 
   5875 name: DOMReady
   5876 
   5877 description: Contains the custom event domready.
   5878 
   5879 license: MIT-style license.
   5880 
   5881 requires: [Browser, Element, Element.Event]
   5882 
   5883 provides: [DOMReady, DomReady]
   5884 
   5885 ...
   5886 */
   5887 
   5888 (function(window, document){
   5889 
   5890 var ready,
   5891 	loaded,
   5892 	checks = [],
   5893 	shouldPoll,
   5894 	timer,
   5895 	testElement = document.createElement('div');
   5896 
   5897 var domready = function(){
   5898 	clearTimeout(timer);
   5899 	if (ready) return;
   5900 	Browser.loaded = ready = true;
   5901 	document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check);
   5902 
   5903 	document.fireEvent('domready');
   5904 	window.fireEvent('domready');
   5905 };
   5906 
   5907 var check = function(){
   5908 	for (var i = checks.length; i--;) if (checks[i]()){
   5909 		domready();
   5910 		return true;
   5911 	}
   5912 	return false;
   5913 };
   5914 
   5915 var poll = function(){
   5916 	clearTimeout(timer);
   5917 	if (!check()) timer = setTimeout(poll, 10);
   5918 };
   5919 
   5920 document.addListener('DOMContentLoaded', domready);
   5921 
   5922 /*<ltIE8>*/
   5923 // doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/
   5924 // testElement.doScroll() throws when the DOM is not ready, only in the top window
   5925 var doScrollWorks = function(){
   5926 	try {
   5927 		testElement.doScroll();
   5928 		return true;
   5929 	} catch (e){}
   5930 	return false;
   5931 };
   5932 // If doScroll works already, it can't be used to determine domready
   5933 //   e.g. in an iframe
   5934 if (testElement.doScroll && !doScrollWorks()){
   5935 	checks.push(doScrollWorks);
   5936 	shouldPoll = true;
   5937 }
   5938 /*</ltIE8>*/
   5939 
   5940 if (document.readyState) checks.push(function(){
   5941 	var state = document.readyState;
   5942 	return (state == 'loaded' || state == 'complete');
   5943 });
   5944 
   5945 if ('onreadystatechange' in document) document.addListener('readystatechange', check);
   5946 else shouldPoll = true;
   5947 
   5948 if (shouldPoll) poll();
   5949 
   5950 Element.Events.domready = {
   5951 	onAdd: function(fn){
   5952 		if (ready) fn.call(this);
   5953 	}
   5954 };
   5955 
   5956 // Make sure that domready fires before load
   5957 Element.Events.load = {
   5958 	base: 'load',
   5959 	onAdd: function(fn){
   5960 		if (loaded && this == window) fn.call(this);
   5961 	},
   5962 	condition: function(){
   5963 		if (this == window){
   5964 			domready();
   5965 			delete Element.Events.load;
   5966 		}
   5967 		return true;
   5968 	}
   5969 };
   5970 
   5971 // This is based on the custom load event
   5972 window.addEvent('load', function(){
   5973 	loaded = true;
   5974 });
   5975 
   5976 })(window, document);
   5977 
   5978