PageSourceSearch

https://www.guitar-school.ru/media/system/js/mootools-core.js

js guitar-school.ru collected 2026-10-03 23:44:32 UTC 180,691 bytes, 6,915 lines download raw bytes

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

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