PageSourceSearch

https://www.buseno.ch/media/system/js/mootools-core.js?00361600ac22ca2851f263fdb277ba5c

js buseno.ch collected 2026-10-02 22:01:55 UTC 162,032 bytes, 6,382 lines download raw bytes

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

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