PageSourceSearch

https://crna.si/media/system/js/mootools-core-uncompressed.js?b25edf4512d2d559bc587819abbf74ef

js crna.si collected 2026-10-02 20:27:53 UTC 150,812 bytes, 5,976 lines download raw bytes

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

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.