PageSourceSearch

https://www.nik.gov.pl/p/mootools-core-1.4.5-full-compat.js

js nik.gov.pl collected 2026-10-02 03:09:06 UTC 160,519 bytes, 6,447 lines download raw bytes

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

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.