remove rss reference, update todo
[mkgallery.git] / include / mootools.js
1 /*
2 ---
3 MooTools: the javascript framework
4
5 web build:
6  - http://mootools.net/core/f62dd4514b59c41f42c7579664bca750
7
8 packager build:
9  - packager build Core/Core Core/Array Core/Event Core/Browser Core/Class.Extras Core/Element.Event Core/Element.Dimensions Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/DOMReady
10
11 /*
12 ---
13
14 name: Core
15
16 description: The heart of MooTools.
17
18 license: MIT-style license.
19
20 copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/).
21
22 authors: The MooTools production team (http://mootools.net/developers/)
23
24 inspiration:
25   - 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)
26   - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
27
28 provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
29
30 ...
31 */
32
33 (function(){
34
35 this.MooTools = {
36         version: '1.3',
37         build: 'a3eed692dd85050d80168ec2c708efe901bb7db3'
38 };
39
40 // typeOf, instanceOf
41
42 var typeOf = this.typeOf = function(item){
43         if (item == null) return 'null';
44         if (item.$family) return item.$family();
45
46         if (item.nodeName){
47                 if (item.nodeType == 1) return 'element';
48                 if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
49         } else if (typeof item.length == 'number'){
50                 if (item.callee) return 'arguments';
51                 if ('item' in item) return 'collection';
52         }
53
54         return typeof item;
55 };
56
57 var instanceOf = this.instanceOf = function(item, object){
58         if (item == null) return false;
59         var constructor = item.$constructor || item.constructor;
60         while (constructor){
61                 if (constructor === object) return true;
62                 constructor = constructor.parent;
63         }
64         return item instanceof object;
65 };
66
67 // Function overloading
68
69 var Function = this.Function;
70
71 var enumerables = true;
72 for (var i in {toString: 1}) enumerables = null;
73 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
74
75 Function.prototype.overloadSetter = function(usePlural){
76         var self = this;
77         return function(a, b){
78                 if (a == null) return this;
79                 if (usePlural || typeof a != 'string'){
80                         for (var k in a) self.call(this, k, a[k]);
81                         if (enumerables) for (var i = enumerables.length; i--;){
82                                 k = enumerables[i];
83                                 if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
84                         }
85                 } else {
86                         self.call(this, a, b);
87                 }
88                 return this;
89         };
90 };
91
92 Function.prototype.overloadGetter = function(usePlural){
93         var self = this;
94         return function(a){
95                 var args, result;
96                 if (usePlural || typeof a != 'string') args = a;
97                 else if (arguments.length > 1) args = arguments;
98                 if (args){
99                         result = {};
100                         for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
101                 } else {
102                         result = self.call(this, a);
103                 }
104                 return result;
105         };
106 };
107
108 Function.prototype.extend = function(key, value){
109         this[key] = value;
110 }.overloadSetter();
111
112 Function.prototype.implement = function(key, value){
113         this.prototype[key] = value;
114 }.overloadSetter();
115
116 // From
117
118 var slice = Array.prototype.slice;
119
120 Function.from = function(item){
121         return (typeOf(item) == 'function') ? item : function(){
122                 return item;
123         };
124 };
125
126 Array.from = function(item){
127         if (item == null) return [];
128         return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
129 };
130
131 Number.from = function(item){
132         var number = parseFloat(item);
133         return isFinite(number) ? number : null;
134 };
135
136 String.from = function(item){
137         return item + '';
138 };
139
140 // hide, protect
141
142 Function.implement({
143
144         hide: function(){
145                 this.$hidden = true;
146                 return this;
147         },
148
149         protect: function(){
150                 this.$protected = true;
151                 return this;
152         }
153
154 });
155
156 // Type
157
158 var Type = this.Type = function(name, object){
159         if (name){
160                 var lower = name.toLowerCase();
161                 var typeCheck = function(item){
162                         return (typeOf(item) == lower);
163                 };
164
165                 Type['is' + name] = typeCheck;
166                 if (object != null){
167                         object.prototype.$family = (function(){
168                                 return lower;
169                         }).hide();
170                         //<1.2compat>
171                         object.type = typeCheck;
172                         //</1.2compat>
173                 }
174         }
175
176         if (object == null) return null;
177
178         object.extend(this);
179         object.$constructor = Type;
180         object.prototype.$constructor = object;
181
182         return object;
183 };
184
185 var toString = Object.prototype.toString;
186
187 Type.isEnumerable = function(item){
188         return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
189 };
190
191 var hooks = {};
192
193 var hooksOf = function(object){
194         var type = typeOf(object.prototype);
195         return hooks[type] || (hooks[type] = []);
196 };
197
198 var implement = function(name, method){
199         if (method && method.$hidden) return this;
200
201         var hooks = hooksOf(this);
202
203         for (var i = 0; i < hooks.length; i++){
204                 var hook = hooks[i];
205                 if (typeOf(hook) == 'type') implement.call(hook, name, method);
206                 else hook.call(this, name, method);
207         }
208         
209         var previous = this.prototype[name];
210         if (previous == null || !previous.$protected) this.prototype[name] = method;
211
212         if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
213                 return method.apply(item, slice.call(arguments, 1));
214         });
215
216         return this;
217 };
218
219 var extend = function(name, method){
220         if (method && method.$hidden) return this;
221         var previous = this[name];
222         if (previous == null || !previous.$protected) this[name] = method;
223         return this;
224 };
225
226 Type.implement({
227
228         implement: implement.overloadSetter(),
229
230         extend: extend.overloadSetter(),
231
232         alias: function(name, existing){
233                 implement.call(this, name, this.prototype[existing]);
234         }.overloadSetter(),
235
236         mirror: function(hook){
237                 hooksOf(this).push(hook);
238                 return this;
239         }
240
241 });
242
243 new Type('Type', Type);
244
245 // Default Types
246
247 var force = function(name, object, methods){
248         var isType = (object != Object),
249                 prototype = object.prototype;
250
251         if (isType) object = new Type(name, object);
252
253         for (var i = 0, l = methods.length; i < l; i++){
254                 var key = methods[i],
255                         generic = object[key],
256                         proto = prototype[key];
257
258                 if (generic) generic.protect();
259
260                 if (isType && proto){
261                         delete prototype[key];
262                         prototype[key] = proto.protect();
263                 }
264         }
265
266         if (isType) object.implement(prototype);
267
268         return force;
269 };
270
271 force('String', String, [
272         'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
273         'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase'
274 ])('Array', Array, [
275         'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
276         'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
277 ])('Number', Number, [
278         'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
279 ])('Function', Function, [
280         'apply', 'call', 'bind'
281 ])('RegExp', RegExp, [
282         'exec', 'test'
283 ])('Object', Object, [
284         'create', 'defineProperty', 'defineProperties', 'keys',
285         'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
286         'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
287 ])('Date', Date, ['now']);
288
289 Object.extend = extend.overloadSetter();
290
291 Date.extend('now', function(){
292         return +(new Date);
293 });
294
295 new Type('Boolean', Boolean);
296
297 // fixes NaN returning as Number
298
299 Number.prototype.$family = function(){
300         return isFinite(this) ? 'number' : 'null';
301 }.hide();
302
303 // Number.random
304
305 Number.extend('random', function(min, max){
306         return Math.floor(Math.random() * (max - min + 1) + min);
307 });
308
309 // forEach, each
310
311 Object.extend('forEach', function(object, fn, bind){
312         for (var key in object){
313                 if (object.hasOwnProperty(key)) fn.call(bind, object[key], key, object);
314         }
315 });
316
317 Object.each = Object.forEach;
318
319 Array.implement({
320
321         forEach: function(fn, bind){
322                 for (var i = 0, l = this.length; i < l; i++){
323                         if (i in this) fn.call(bind, this[i], i, this);
324                 }
325         },
326
327         each: function(fn, bind){
328                 Array.forEach(this, fn, bind);
329                 return this;
330         }
331
332 });
333
334 // Array & Object cloning, Object merging and appending
335
336 var cloneOf = function(item){
337         switch (typeOf(item)){
338                 case 'array': return item.clone();
339                 case 'object': return Object.clone(item);
340                 default: return item;
341         }
342 };
343
344 Array.implement('clone', function(){
345         var i = this.length, clone = new Array(i);
346         while (i--) clone[i] = cloneOf(this[i]);
347         return clone;
348 });
349
350 var mergeOne = function(source, key, current){
351         switch (typeOf(current)){
352                 case 'object':
353                         if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
354                         else source[key] = Object.clone(current);
355                 break;
356                 case 'array': source[key] = current.clone(); break;
357                 default: source[key] = current;
358         }
359         return source;
360 };
361
362 Object.extend({
363
364         merge: function(source, k, v){
365                 if (typeOf(k) == 'string') return mergeOne(source, k, v);
366                 for (var i = 1, l = arguments.length; i < l; i++){
367                         var object = arguments[i];
368                         for (var key in object) mergeOne(source, key, object[key]);
369                 }
370                 return source;
371         },
372
373         clone: function(object){
374                 var clone = {};
375                 for (var key in object) clone[key] = cloneOf(object[key]);
376                 return clone;
377         },
378
379         append: function(original){
380                 for (var i = 1, l = arguments.length; i < l; i++){
381                         var extended = arguments[i] || {};
382                         for (var key in extended) original[key] = extended[key];
383                 }
384                 return original;
385         }
386
387 });
388
389 // Object-less types
390
391 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
392         new Type(name);
393 });
394
395 // Unique ID
396
397 var UID = Date.now();
398
399 String.extend('uniqueID', function(){
400         return (UID++).toString(36);
401 });
402
403 //<1.2compat>
404
405 var Hash = this.Hash = new Type('Hash', function(object){
406         if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
407         for (var key in object) this[key] = object[key];
408         return this;
409 });
410
411 Hash.implement({
412
413         forEach: function(fn, bind){
414                 Object.forEach(this, fn, bind);
415         },
416
417         getClean: function(){
418                 var clean = {};
419                 for (var key in this){
420                         if (this.hasOwnProperty(key)) clean[key] = this[key];
421                 }
422                 return clean;
423         },
424
425         getLength: function(){
426                 var length = 0;
427                 for (var key in this){
428                         if (this.hasOwnProperty(key)) length++;
429                 }
430                 return length;
431         }
432
433 });
434
435 Hash.alias('each', 'forEach');
436
437 Object.type = Type.isObject;
438
439 var Native = this.Native = function(properties){
440         return new Type(properties.name, properties.initialize);
441 };
442
443 Native.type = Type.type;
444
445 Native.implement = function(objects, methods){
446         for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
447         return Native;
448 };
449
450 var arrayType = Array.type;
451 Array.type = function(item){
452         return instanceOf(item, Array) || arrayType(item);
453 };
454
455 this.$A = function(item){
456         return Array.from(item).slice();
457 };
458
459 this.$arguments = function(i){
460         return function(){
461                 return arguments[i];
462         };
463 };
464
465 this.$chk = function(obj){
466         return !!(obj || obj === 0);
467 };
468
469 this.$clear = function(timer){
470         clearTimeout(timer);
471         clearInterval(timer);
472         return null;
473 };
474
475 this.$defined = function(obj){
476         return (obj != null);
477 };
478
479 this.$each = function(iterable, fn, bind){
480         var type = typeOf(iterable);
481         ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind);
482 };
483
484 this.$empty = function(){};
485
486 this.$extend = function(original, extended){
487         return Object.append(original, extended);
488 };
489
490 this.$H = function(object){
491         return new Hash(object);
492 };
493
494 this.$merge = function(){
495         var args = Array.slice(arguments);
496         args.unshift({});
497         return Object.merge.apply(null, args);
498 };
499
500 this.$lambda = Function.from;
501 this.$mixin = Object.merge;
502 this.$random = Number.random;
503 this.$splat = Array.from;
504 this.$time = Date.now;
505
506 this.$type = function(object){
507         var type = typeOf(object);
508         if (type == 'elements') return 'array';
509         return (type == 'null') ? false : type;
510 };
511
512 this.$unlink = function(object){
513         switch (typeOf(object)){
514                 case 'object': return Object.clone(object);
515                 case 'array': return Array.clone(object);
516                 case 'hash': return new Hash(object);
517                 default: return object;
518         }
519 };
520
521 //</1.2compat>
522
523 })();
524
525
526 /*
527 ---
528
529 name: Array
530
531 description: Contains Array Prototypes like each, contains, and erase.
532
533 license: MIT-style license.
534
535 requires: Type
536
537 provides: Array
538
539 ...
540 */
541
542 Array.implement({
543
544         invoke: function(methodName){
545                 var args = Array.slice(arguments, 1);
546                 return this.map(function(item){
547                         return item[methodName].apply(item, args);
548                 });
549         },
550
551         every: function(fn, bind){
552                 for (var i = 0, l = this.length; i < l; i++){
553                         if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
554                 }
555                 return true;
556         },
557
558         filter: function(fn, bind){
559                 var results = [];
560                 for (var i = 0, l = this.length; i < l; i++){
561                         if ((i in this) && fn.call(bind, this[i], i, this)) results.push(this[i]);
562                 }
563                 return results;
564         },
565
566         clean: function(){
567                 return this.filter(function(item){
568                         return item != null;
569                 });
570         },
571
572         indexOf: function(item, from){
573                 var len = this.length;
574                 for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
575                         if (this[i] === item) return i;
576                 }
577                 return -1;
578         },
579
580         map: function(fn, bind){
581                 var results = [];
582                 for (var i = 0, l = this.length; i < l; i++){
583                         if (i in this) results[i] = fn.call(bind, this[i], i, this);
584                 }
585                 return results;
586         },
587
588         some: function(fn, bind){
589                 for (var i = 0, l = this.length; i < l; i++){
590                         if ((i in this) && fn.call(bind, this[i], i, this)) return true;
591                 }
592                 return false;
593         },
594
595         associate: function(keys){
596                 var obj = {}, length = Math.min(this.length, keys.length);
597                 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
598                 return obj;
599         },
600
601         link: function(object){
602                 var result = {};
603                 for (var i = 0, l = this.length; i < l; i++){
604                         for (var key in object){
605                                 if (object[key](this[i])){
606                                         result[key] = this[i];
607                                         delete object[key];
608                                         break;
609                                 }
610                         }
611                 }
612                 return result;
613         },
614
615         contains: function(item, from){
616                 return this.indexOf(item, from) != -1;
617         },
618
619         append: function(array){
620                 this.push.apply(this, array);
621                 return this;
622         },
623
624         getLast: function(){
625                 return (this.length) ? this[this.length - 1] : null;
626         },
627
628         getRandom: function(){
629                 return (this.length) ? this[Number.random(0, this.length - 1)] : null;
630         },
631
632         include: function(item){
633                 if (!this.contains(item)) this.push(item);
634                 return this;
635         },
636
637         combine: function(array){
638                 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
639                 return this;
640         },
641
642         erase: function(item){
643                 for (var i = this.length; i--;){
644                         if (this[i] === item) this.splice(i, 1);
645                 }
646                 return this;
647         },
648
649         empty: function(){
650                 this.length = 0;
651                 return this;
652         },
653
654         flatten: function(){
655                 var array = [];
656                 for (var i = 0, l = this.length; i < l; i++){
657                         var type = typeOf(this[i]);
658                         if (type == 'null') continue;
659                         array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
660                 }
661                 return array;
662         },
663
664         pick: function(){
665                 for (var i = 0, l = this.length; i < l; i++){
666                         if (this[i] != null) return this[i];
667                 }
668                 return null;
669         },
670
671         hexToRgb: function(array){
672                 if (this.length != 3) return null;
673                 var rgb = this.map(function(value){
674                         if (value.length == 1) value += value;
675                         return value.toInt(16);
676                 });
677                 return (array) ? rgb : 'rgb(' + rgb + ')';
678         },
679
680         rgbToHex: function(array){
681                 if (this.length < 3) return null;
682                 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
683                 var hex = [];
684                 for (var i = 0; i < 3; i++){
685                         var bit = (this[i] - 0).toString(16);
686                         hex.push((bit.length == 1) ? '0' + bit : bit);
687                 }
688                 return (array) ? hex : '#' + hex.join('');
689         }
690
691 });
692
693 //<1.2compat>
694
695 Array.alias('extend', 'append');
696
697 var $pick = function(){
698         return Array.from(arguments).pick();
699 };
700
701 //</1.2compat>
702
703
704 /*
705 ---
706
707 name: Function
708
709 description: Contains Function Prototypes like create, bind, pass, and delay.
710
711 license: MIT-style license.
712
713 requires: Type
714
715 provides: Function
716
717 ...
718 */
719
720 Function.extend({
721
722         attempt: function(){
723                 for (var i = 0, l = arguments.length; i < l; i++){
724                         try {
725                                 return arguments[i]();
726                         } catch (e){}
727                 }
728                 return null;
729         }
730
731 });
732
733 Function.implement({
734
735         attempt: function(args, bind){
736                 try {
737                         return this.apply(bind, Array.from(args));
738                 } catch (e){}
739                 
740                 return null;
741         },
742
743         bind: function(bind){
744                 var self = this,
745                         args = (arguments.length > 1) ? Array.slice(arguments, 1) : null;
746                 
747                 return function(){
748                         if (!args && !arguments.length) return self.call(bind);
749                         if (args && arguments.length) return self.apply(bind, args.concat(Array.from(arguments)));
750                         return self.apply(bind, args || arguments);
751                 };
752         },
753
754         pass: function(args, bind){
755                 var self = this;
756                 if (args != null) args = Array.from(args);
757                 return function(){
758                         return self.apply(bind, args || arguments);
759                 };
760         },
761
762         delay: function(delay, bind, args){
763                 return setTimeout(this.pass(args, bind), delay);
764         },
765
766         periodical: function(periodical, bind, args){
767                 return setInterval(this.pass(args, bind), periodical);
768         }
769
770 });
771
772 //<1.2compat>
773
774 delete Function.prototype.bind;
775
776 Function.implement({
777
778         create: function(options){
779                 var self = this;
780                 options = options || {};
781                 return function(event){
782                         var args = options.arguments;
783                         args = (args != null) ? Array.from(args) : Array.slice(arguments, (options.event) ? 1 : 0);
784                         if (options.event) args = [event || window.event].extend(args);
785                         var returns = function(){
786                                 return self.apply(options.bind || null, args);
787                         };
788                         if (options.delay) return setTimeout(returns, options.delay);
789                         if (options.periodical) return setInterval(returns, options.periodical);
790                         if (options.attempt) return Function.attempt(returns);
791                         return returns();
792                 };
793         },
794
795         bind: function(bind, args){
796                 var self = this;
797                 if (args != null) args = Array.from(args);
798                 return function(){
799                         return self.apply(bind, args || arguments);
800                 };
801         },
802
803         bindWithEvent: function(bind, args){
804                 var self = this;
805                 if (args != null) args = Array.from(args);
806                 return function(event){
807                         return self.apply(bind, (args == null) ? arguments : [event].concat(args));
808                 };
809         },
810
811         run: function(args, bind){
812                 return this.apply(bind, Array.from(args));
813         }
814
815 });
816
817 var $try = Function.attempt;
818
819 //</1.2compat>
820
821
822 /*
823 ---
824
825 name: Number
826
827 description: Contains Number Prototypes like limit, round, times, and ceil.
828
829 license: MIT-style license.
830
831 requires: Type
832
833 provides: Number
834
835 ...
836 */
837
838 Number.implement({
839
840         limit: function(min, max){
841                 return Math.min(max, Math.max(min, this));
842         },
843
844         round: function(precision){
845                 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
846                 return Math.round(this * precision) / precision;
847         },
848
849         times: function(fn, bind){
850                 for (var i = 0; i < this; i++) fn.call(bind, i, this);
851         },
852
853         toFloat: function(){
854                 return parseFloat(this);
855         },
856
857         toInt: function(base){
858                 return parseInt(this, base || 10);
859         }
860
861 });
862
863 Number.alias('each', 'times');
864
865 (function(math){
866         var methods = {};
867         math.each(function(name){
868                 if (!Number[name]) methods[name] = function(){
869                         return Math[name].apply(null, [this].concat(Array.from(arguments)));
870                 };
871         });
872         Number.implement(methods);
873 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
874
875
876 /*
877 ---
878
879 name: String
880
881 description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
882
883 license: MIT-style license.
884
885 requires: Type
886
887 provides: String
888
889 ...
890 */
891
892 String.implement({
893
894         test: function(regex, params){
895                 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
896         },
897
898         contains: function(string, separator){
899                 return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
900         },
901
902         trim: function(){
903                 return this.replace(/^\s+|\s+$/g, '');
904         },
905
906         clean: function(){
907                 return this.replace(/\s+/g, ' ').trim();
908         },
909
910         camelCase: function(){
911                 return this.replace(/-\D/g, function(match){
912                         return match.charAt(1).toUpperCase();
913                 });
914         },
915
916         hyphenate: function(){
917                 return this.replace(/[A-Z]/g, function(match){
918                         return ('-' + match.charAt(0).toLowerCase());
919                 });
920         },
921
922         capitalize: function(){
923                 return this.replace(/\b[a-z]/g, function(match){
924                         return match.toUpperCase();
925                 });
926         },
927
928         escapeRegExp: function(){
929                 return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
930         },
931
932         toInt: function(base){
933                 return parseInt(this, base || 10);
934         },
935
936         toFloat: function(){
937                 return parseFloat(this);
938         },
939
940         hexToRgb: function(array){
941                 var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
942                 return (hex) ? hex.slice(1).hexToRgb(array) : null;
943         },
944
945         rgbToHex: function(array){
946                 var rgb = this.match(/\d{1,3}/g);
947                 return (rgb) ? rgb.rgbToHex(array) : null;
948         },
949
950         substitute: function(object, regexp){
951                 return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
952                         if (match.charAt(0) == '\\') return match.slice(1);
953                         return (object[name] != null) ? object[name] : '';
954                 });
955         }
956
957 });
958
959
960 /*
961 ---
962
963 name: Browser
964
965 description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
966
967 license: MIT-style license.
968
969 requires: [Array, Function, Number, String]
970
971 provides: [Browser, Window, Document]
972
973 ...
974 */
975
976 (function(){
977
978 var document = this.document;
979 var window = document.window = this;
980
981 var UID = 1;
982
983 this.$uid = (window.ActiveXObject) ? function(item){
984         return (item.uid || (item.uid = [UID++]))[0];
985 } : function(item){
986         return item.uid || (item.uid = UID++);
987 };
988
989 $uid(window);
990 $uid(document);
991
992 var ua = navigator.userAgent.toLowerCase(),
993         platform = navigator.platform.toLowerCase(),
994         UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0],
995         mode = UA[1] == 'ie' && document.documentMode;
996
997 var Browser = this.Browser = {
998
999         extend: Function.prototype.extend,
1000
1001         name: (UA[1] == 'version') ? UA[3] : UA[1],
1002
1003         version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
1004
1005         Platform: {
1006                 name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]
1007         },
1008
1009         Features: {
1010                 xpath: !!(document.evaluate),
1011                 air: !!(window.runtime),
1012                 query: !!(document.querySelector),
1013                 json: !!(window.JSON)
1014         },
1015
1016         Plugins: {}
1017
1018 };
1019
1020 Browser[Browser.name] = true;
1021 Browser[Browser.name + parseInt(Browser.version, 10)] = true;
1022 Browser.Platform[Browser.Platform.name] = true;
1023
1024 // Request
1025
1026 Browser.Request = (function(){
1027
1028         var XMLHTTP = function(){
1029                 return new XMLHttpRequest();
1030         };
1031
1032         var MSXML2 = function(){
1033                 return new ActiveXObject('MSXML2.XMLHTTP');
1034         };
1035
1036         var MSXML = function(){
1037                 return new ActiveXObject('Microsoft.XMLHTTP');
1038         };
1039
1040         return Function.attempt(function(){
1041                 XMLHTTP();
1042                 return XMLHTTP;
1043         }, function(){
1044                 MSXML2();
1045                 return MSXML2;
1046         }, function(){
1047                 MSXML();
1048                 return MSXML;
1049         });
1050
1051 })();
1052
1053 Browser.Features.xhr = !!(Browser.Request);
1054
1055 // Flash detection
1056
1057 var version = (Function.attempt(function(){
1058         return navigator.plugins['Shockwave Flash'].description;
1059 }, function(){
1060         return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
1061 }) || '0 r0').match(/\d+/g);
1062
1063 Browser.Plugins.Flash = {
1064         version: Number(version[0] || '0.' + version[1]) || 0,
1065         build: Number(version[2]) || 0
1066 };
1067
1068 // String scripts
1069
1070 Browser.exec = function(text){
1071         if (!text) return text;
1072         if (window.execScript){
1073                 window.execScript(text);
1074         } else {
1075                 var script = document.createElement('script');
1076                 script.setAttribute('type', 'text/javascript');
1077                 script.text = text;
1078                 document.head.appendChild(script);
1079                 document.head.removeChild(script);
1080         }
1081         return text;
1082 };
1083
1084 String.implement('stripScripts', function(exec){
1085         var scripts = '';
1086         var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
1087                 scripts += code + '\n';
1088                 return '';
1089         });
1090         if (exec === true) Browser.exec(scripts);
1091         else if (typeOf(exec) == 'function') exec(scripts, text);
1092         return text;
1093 });
1094
1095 // Window, Document
1096
1097 Browser.extend({
1098         Document: this.Document,
1099         Window: this.Window,
1100         Element: this.Element,
1101         Event: this.Event
1102 });
1103
1104 this.Window = this.$constructor = new Type('Window', function(){});
1105
1106 this.$family = Function.from('window').hide();
1107
1108 Window.mirror(function(name, method){
1109         window[name] = method;
1110 });
1111
1112 this.Document = document.$constructor = new Type('Document', function(){});
1113
1114 document.$family = Function.from('document').hide();
1115
1116 Document.mirror(function(name, method){
1117         document[name] = method;
1118 });
1119
1120 document.html = document.documentElement;
1121 document.head = document.getElementsByTagName('head')[0];
1122
1123 if (document.execCommand) try {
1124         document.execCommand("BackgroundImageCache", false, true);
1125 } catch (e){}
1126
1127 if (this.attachEvent && !this.addEventListener){
1128         var unloadEvent = function(){
1129                 this.detachEvent('onunload', unloadEvent);
1130                 document.head = document.html = document.window = null;
1131         };
1132         this.attachEvent('onunload', unloadEvent);
1133 }
1134
1135 // IE fails on collections and <select>.options (refers to <select>)
1136 var arrayFrom = Array.from;
1137 try {
1138         arrayFrom(document.html.childNodes);
1139 } catch(e){
1140         Array.from = function(item){
1141                 if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
1142                         var i = item.length, array = new Array(i);
1143                         while (i--) array[i] = item[i];
1144                         return array;
1145                 }
1146                 return arrayFrom(item);
1147         };
1148
1149         var prototype = Array.prototype,
1150                 slice = prototype.slice;
1151         ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
1152                 var method = prototype[name];
1153                 Array[name] = function(item){
1154                         return method.apply(Array.from(item), slice.call(arguments, 1));
1155                 };
1156         });
1157 }
1158
1159 //<1.2compat>
1160
1161 if (Browser.Platform.ios) Browser.Platform.ipod = true;
1162
1163 Browser.Engine = {};
1164
1165 var setEngine = function(name, version){
1166         Browser.Engine.name = name;
1167         Browser.Engine[name + version] = true;
1168         Browser.Engine.version = version;
1169 };
1170
1171 if (Browser.ie){
1172         Browser.Engine.trident = true;
1173
1174         switch (Browser.version){
1175                 case 6: setEngine('trident', 4); break;
1176                 case 7: setEngine('trident', 5); break;
1177                 case 8: setEngine('trident', 6);
1178         }
1179 }
1180
1181 if (Browser.firefox){
1182         Browser.Engine.gecko = true;
1183
1184         if (Browser.version >= 3) setEngine('gecko', 19);
1185         else setEngine('gecko', 18);
1186 }
1187
1188 if (Browser.safari || Browser.chrome){
1189         Browser.Engine.webkit = true;
1190
1191         switch (Browser.version){
1192                 case 2: setEngine('webkit', 419); break;
1193                 case 3: setEngine('webkit', 420); break;
1194                 case 4: setEngine('webkit', 525);
1195         }
1196 }
1197
1198 if (Browser.opera){
1199         Browser.Engine.presto = true;
1200
1201         if (Browser.version >= 9.6) setEngine('presto', 960);
1202         else if (Browser.version >= 9.5) setEngine('presto', 950);
1203         else setEngine('presto', 925);
1204 }
1205
1206 if (Browser.name == 'unknown'){
1207         switch ((ua.match(/(?:webkit|khtml|gecko)/) || [])[0]){
1208                 case 'webkit':
1209                 case 'khtml':
1210                         Browser.Engine.webkit = true;
1211                 break;
1212                 case 'gecko':
1213                         Browser.Engine.gecko = true;
1214         }
1215 }
1216
1217 this.$exec = Browser.exec;
1218
1219 //</1.2compat>
1220
1221 })();
1222
1223
1224 /*
1225 ---
1226
1227 name: Object
1228
1229 description: Object generic methods
1230
1231 license: MIT-style license.
1232
1233 requires: Type
1234
1235 provides: [Object, Hash]
1236
1237 ...
1238 */
1239
1240
1241 Object.extend({
1242
1243         subset: function(object, keys){
1244                 var results = {};
1245                 for (var i = 0, l = keys.length; i < l; i++){
1246                         var k = keys[i];
1247                         results[k] = object[k];
1248                 }
1249                 return results;
1250         },
1251
1252         map: function(object, fn, bind){
1253                 var results = {};
1254                 for (var key in object){
1255                         if (object.hasOwnProperty(key)) results[key] = fn.call(bind, object[key], key, object);
1256                 }
1257                 return results;
1258         },
1259
1260         filter: function(object, fn, bind){
1261                 var results = {};
1262                 Object.each(object, function(value, key){
1263                         if (fn.call(bind, value, key, object)) results[key] = value;
1264                 });
1265                 return results;
1266         },
1267
1268         every: function(object, fn, bind){
1269                 for (var key in object){
1270                         if (object.hasOwnProperty(key) && !fn.call(bind, object[key], key)) return false;
1271                 }
1272                 return true;
1273         },
1274
1275         some: function(object, fn, bind){
1276                 for (var key in object){
1277                         if (object.hasOwnProperty(key) && fn.call(bind, object[key], key)) return true;
1278                 }
1279                 return false;
1280         },
1281
1282         keys: function(object){
1283                 var keys = [];
1284                 for (var key in object){
1285                         if (object.hasOwnProperty(key)) keys.push(key);
1286                 }
1287                 return keys;
1288         },
1289
1290         values: function(object){
1291                 var values = [];
1292                 for (var key in object){
1293                         if (object.hasOwnProperty(key)) values.push(object[key]);
1294                 }
1295                 return values;
1296         },
1297
1298         getLength: function(object){
1299                 return Object.keys(object).length;
1300         },
1301
1302         keyOf: function(object, value){
1303                 for (var key in object){
1304                         if (object.hasOwnProperty(key) && object[key] === value) return key;
1305                 }
1306                 return null;
1307         },
1308
1309         contains: function(object, value){
1310                 return Object.keyOf(object, value) != null;
1311         },
1312
1313         toQueryString: function(object, base){
1314                 var queryString = [];
1315
1316                 Object.each(object, function(value, key){
1317                         if (base) key = base + '[' + key + ']';
1318                         var result;
1319                         switch (typeOf(value)){
1320                                 case 'object': result = Object.toQueryString(value, key); break;
1321                                 case 'array':
1322                                         var qs = {};
1323                                         value.each(function(val, i){
1324                                                 qs[i] = val;
1325                                         });
1326                                         result = Object.toQueryString(qs, key);
1327                                 break;
1328                                 default: result = key + '=' + encodeURIComponent(value);
1329                         }
1330                         if (value != null) queryString.push(result);
1331                 });
1332
1333                 return queryString.join('&');
1334         }
1335
1336 });
1337
1338
1339 //<1.2compat>
1340
1341 Hash.implement({
1342
1343         has: Object.prototype.hasOwnProperty,
1344
1345         keyOf: function(value){
1346                 return Object.keyOf(this, value);
1347         },
1348
1349         hasValue: function(value){
1350                 return Object.contains(this, value);
1351         },
1352
1353         extend: function(properties){
1354                 Hash.each(properties || {}, function(value, key){
1355                         Hash.set(this, key, value);
1356                 }, this);
1357                 return this;
1358         },
1359
1360         combine: function(properties){
1361                 Hash.each(properties || {}, function(value, key){
1362                         Hash.include(this, key, value);
1363                 }, this);
1364                 return this;
1365         },
1366
1367         erase: function(key){
1368                 if (this.hasOwnProperty(key)) delete this[key];
1369                 return this;
1370         },
1371
1372         get: function(key){
1373                 return (this.hasOwnProperty(key)) ? this[key] : null;
1374         },
1375
1376         set: function(key, value){
1377                 if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
1378                 return this;
1379         },
1380
1381         empty: function(){
1382                 Hash.each(this, function(value, key){
1383                         delete this[key];
1384                 }, this);
1385                 return this;
1386         },
1387
1388         include: function(key, value){
1389                 if (this[key] == null) this[key] = value;
1390                 return this;
1391         },
1392
1393         map: function(fn, bind){
1394                 return new Hash(Object.map(this, fn, bind));
1395         },
1396
1397         filter: function(fn, bind){
1398                 return new Hash(Object.filter(this, fn, bind));
1399         },
1400
1401         every: function(fn, bind){
1402                 return Object.every(this, fn, bind);
1403         },
1404
1405         some: function(fn, bind){
1406                 return Object.some(this, fn, bind);
1407         },
1408
1409         getKeys: function(){
1410                 return Object.keys(this);
1411         },
1412
1413         getValues: function(){
1414                 return Object.values(this);
1415         },
1416
1417         toQueryString: function(base){
1418                 return Object.toQueryString(this, base);
1419         }
1420
1421 });
1422
1423 Hash.extend = Object.append;
1424
1425 Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
1426
1427 //</1.2compat>
1428
1429
1430 /*
1431 ---
1432
1433 name: Event
1434
1435 description: Contains the Event Class, to make the event object cross-browser.
1436
1437 license: MIT-style license.
1438
1439 requires: [Window, Document, Array, Function, String, Object]
1440
1441 provides: Event
1442
1443 ...
1444 */
1445
1446 var Event = new Type('Event', function(event, win){
1447         if (!win) win = window;
1448         var doc = win.document;
1449         event = event || win.event;
1450         if (event.$extended) return event;
1451         this.$extended = true;
1452         var type = event.type,
1453                 target = event.target || event.srcElement,
1454                 page = {},
1455                 client = {};
1456         while (target && target.nodeType == 3) target = target.parentNode;
1457
1458         if (type.indexOf('key') != -1){
1459                 var code = event.which || event.keyCode;
1460                 var key = Object.keyOf(Event.Keys, code);
1461                 if (type == 'keydown'){
1462                         var fKey = code - 111;
1463                         if (fKey > 0 && fKey < 13) key = 'f' + fKey;
1464                 }
1465                 if (!key) key = String.fromCharCode(code).toLowerCase();
1466         } else if (type.test(/click|mouse|menu/i)){
1467                 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
1468                 page = {
1469                         x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
1470                         y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop
1471                 };
1472                 client = {
1473                         x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
1474                         y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
1475                 };
1476                 if (type.test(/DOMMouseScroll|mousewheel/)){
1477                         var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
1478                 }
1479                 var rightClick = (event.which == 3) || (event.button == 2),
1480                         related = null;
1481                 if (type.test(/over|out/)){
1482                         related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
1483                         var testRelated = function(){
1484                                 while (related && related.nodeType == 3) related = related.parentNode;
1485                                 return true;
1486                         };
1487                         var hasRelated = (Browser.firefox2) ? testRelated.attempt() : testRelated();
1488                         related = (hasRelated) ? related : null;
1489                 }
1490         } else if (type.test(/gesture|touch/i)){
1491                 this.rotation = event.rotation;
1492                 this.scale = event.scale;
1493                 this.targetTouches = event.targetTouches;
1494                 this.changedTouches = event.changedTouches;
1495                 var touches = this.touches = event.touches;
1496                 if (touches && touches[0]){
1497                         var touch = touches[0];
1498                         page = {x: touch.pageX, y: touch.pageY};
1499                         client = {x: touch.clientX, y: touch.clientY};
1500                 }
1501         }
1502
1503         return Object.append(this, {
1504                 event: event,
1505                 type: type,
1506
1507                 page: page,
1508                 client: client,
1509                 rightClick: rightClick,
1510
1511                 wheel: wheel,
1512
1513                 relatedTarget: document.id(related),
1514                 target: document.id(target),
1515
1516                 code: code,
1517                 key: key,
1518
1519                 shift: event.shiftKey,
1520                 control: event.ctrlKey,
1521                 alt: event.altKey,
1522                 meta: event.metaKey
1523         });
1524 });
1525
1526 Event.Keys = {
1527         'enter': 13,
1528         'up': 38,
1529         'down': 40,
1530         'left': 37,
1531         'right': 39,
1532         'esc': 27,
1533         'space': 32,
1534         'backspace': 8,
1535         'tab': 9,
1536         'delete': 46
1537 };
1538
1539 //<1.2compat>
1540
1541 Event.Keys = new Hash(Event.Keys);
1542
1543 //</1.2compat>
1544
1545 Event.implement({
1546
1547         stop: function(){
1548                 return this.stopPropagation().preventDefault();
1549         },
1550
1551         stopPropagation: function(){
1552                 if (this.event.stopPropagation) this.event.stopPropagation();
1553                 else this.event.cancelBubble = true;
1554                 return this;
1555         },
1556
1557         preventDefault: function(){
1558                 if (this.event.preventDefault) this.event.preventDefault();
1559                 else this.event.returnValue = false;
1560                 return this;
1561         }
1562
1563 });
1564
1565
1566 /*
1567 ---
1568
1569 name: Class
1570
1571 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
1572
1573 license: MIT-style license.
1574
1575 requires: [Array, String, Function, Number]
1576
1577 provides: Class
1578
1579 ...
1580 */
1581
1582 (function(){
1583
1584 var Class = this.Class = new Type('Class', function(params){
1585         if (instanceOf(params, Function)) params = {initialize: params};
1586
1587         var newClass = function(){
1588                 reset(this);
1589                 if (newClass.$prototyping) return this;
1590                 this.$caller = null;
1591                 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
1592                 this.$caller = this.caller = null;
1593                 return value;
1594         }.extend(this).implement(params);
1595
1596         newClass.$constructor = Class;
1597         newClass.prototype.$constructor = newClass;
1598         newClass.prototype.parent = parent;
1599
1600         return newClass;
1601 });
1602
1603 var parent = function(){
1604         if (!this.$caller) throw new Error('The method "parent" cannot be called.');
1605         var name = this.$caller.$name,
1606                 parent = this.$caller.$owner.parent,
1607                 previous = (parent) ? parent.prototype[name] : null;
1608         if (!previous) throw new Error('The method "' + name + '" has no parent.');
1609         return previous.apply(this, arguments);
1610 };
1611
1612 var reset = function(object){
1613         for (var key in object){
1614                 var value = object[key];
1615                 switch (typeOf(value)){
1616                         case 'object':
1617                                 var F = function(){};
1618                                 F.prototype = value;
1619                                 object[key] = reset(new F);
1620                         break;
1621                         case 'array': object[key] = value.clone(); break;
1622                 }
1623         }
1624         return object;
1625 };
1626
1627 var wrap = function(self, key, method){
1628         if (method.$origin) method = method.$origin;
1629         var wrapper = function(){
1630                 if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
1631                 var caller = this.caller, current = this.$caller;
1632                 this.caller = current; this.$caller = wrapper;
1633                 var result = method.apply(this, arguments);
1634                 this.$caller = current; this.caller = caller;
1635                 return result;
1636         }.extend({$owner: self, $origin: method, $name: key});
1637         return wrapper;
1638 };
1639
1640 var implement = function(key, value, retain){
1641         if (Class.Mutators.hasOwnProperty(key)){
1642                 value = Class.Mutators[key].call(this, value);
1643                 if (value == null) return this;
1644         }
1645
1646         if (typeOf(value) == 'function'){
1647                 if (value.$hidden) return this;
1648                 this.prototype[key] = (retain) ? value : wrap(this, key, value);
1649         } else {
1650                 Object.merge(this.prototype, key, value);
1651         }
1652
1653         return this;
1654 };
1655
1656 var getInstance = function(klass){
1657         klass.$prototyping = true;
1658         var proto = new klass;
1659         delete klass.$prototyping;
1660         return proto;
1661 };
1662
1663 Class.implement('implement', implement.overloadSetter());
1664
1665 Class.Mutators = {
1666
1667         Extends: function(parent){
1668                 this.parent = parent;
1669                 this.prototype = getInstance(parent);
1670         },
1671
1672         Implements: function(items){
1673                 Array.from(items).each(function(item){
1674                         var instance = new item;
1675                         for (var key in instance) implement.call(this, key, instance[key], true);
1676                 }, this);
1677         }
1678 };
1679
1680 })();
1681
1682
1683 /*
1684 ---
1685
1686 name: Class.Extras
1687
1688 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1689
1690 license: MIT-style license.
1691
1692 requires: Class
1693
1694 provides: [Class.Extras, Chain, Events, Options]
1695
1696 ...
1697 */
1698
1699 (function(){
1700
1701 this.Chain = new Class({
1702
1703         $chain: [],
1704
1705         chain: function(){
1706                 this.$chain.append(Array.flatten(arguments));
1707                 return this;
1708         },
1709
1710         callChain: function(){
1711                 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1712         },
1713
1714         clearChain: function(){
1715                 this.$chain.empty();
1716                 return this;
1717         }
1718
1719 });
1720
1721 var removeOn = function(string){
1722         return string.replace(/^on([A-Z])/, function(full, first){
1723                 return first.toLowerCase();
1724         });
1725 };
1726
1727 this.Events = new Class({
1728
1729         $events: {},
1730
1731         addEvent: function(type, fn, internal){
1732                 type = removeOn(type);
1733
1734                 /*<1.2compat>*/
1735                 if (fn == $empty) return this;
1736                 /*</1.2compat>*/
1737
1738                 this.$events[type] = (this.$events[type] || []).include(fn);
1739                 if (internal) fn.internal = true;
1740                 return this;
1741         },
1742
1743         addEvents: function(events){
1744                 for (var type in events) this.addEvent(type, events[type]);
1745                 return this;
1746         },
1747
1748         fireEvent: function(type, args, delay){
1749                 type = removeOn(type);
1750                 var events = this.$events[type];
1751                 if (!events) return this;
1752                 args = Array.from(args);
1753                 events.each(function(fn){
1754                         if (delay) fn.delay(delay, this, args);
1755                         else fn.apply(this, args);
1756                 }, this);
1757                 return this;
1758         },
1759         
1760         removeEvent: function(type, fn){
1761                 type = removeOn(type);
1762                 var events = this.$events[type];
1763                 if (events && !fn.internal){
1764                         var index =  events.indexOf(fn);
1765                         if (index != -1) delete events[index];
1766                 }
1767                 return this;
1768         },
1769
1770         removeEvents: function(events){
1771                 var type;
1772                 if (typeOf(events) == 'object'){
1773                         for (type in events) this.removeEvent(type, events[type]);
1774                         return this;
1775                 }
1776                 if (events) events = removeOn(events);
1777                 for (type in this.$events){
1778                         if (events && events != type) continue;
1779                         var fns = this.$events[type];
1780                         for (var i = fns.length; i--;) this.removeEvent(type, fns[i]);
1781                 }
1782                 return this;
1783         }
1784
1785 });
1786
1787 this.Options = new Class({
1788
1789         setOptions: function(){
1790                 var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
1791                 if (!this.addEvent) return this;
1792                 for (var option in options){
1793                         if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1794                         this.addEvent(option, options[option]);
1795                         delete options[option];
1796                 }
1797                 return this;
1798         }
1799
1800 });
1801
1802 })();
1803
1804
1805 /*
1806 ---
1807 name: Slick.Parser
1808 description: Standalone CSS3 Selector parser
1809 provides: Slick.Parser
1810 ...
1811 */
1812
1813 (function(){
1814
1815 var parsed,
1816         separatorIndex,
1817         combinatorIndex,
1818         reversed,
1819         cache = {},
1820         reverseCache = {},
1821         reUnescape = /\\/g;
1822
1823 var parse = function(expression, isReversed){
1824         if (expression == null) return null;
1825         if (expression.Slick === true) return expression;
1826         expression = ('' + expression).replace(/^\s+|\s+$/g, '');
1827         reversed = !!isReversed;
1828         var currentCache = (reversed) ? reverseCache : cache;
1829         if (currentCache[expression]) return currentCache[expression];
1830         parsed = {Slick: true, expressions: [], raw: expression, reverse: function(){
1831                 return parse(this.raw, true);
1832         }};
1833         separatorIndex = -1;
1834         while (expression != (expression = expression.replace(regexp, parser)));
1835         parsed.length = parsed.expressions.length;
1836         return currentCache[expression] = (reversed) ? reverse(parsed) : parsed;
1837 };
1838
1839 var reverseCombinator = function(combinator){
1840         if (combinator === '!') return ' ';
1841         else if (combinator === ' ') return '!';
1842         else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
1843         else return '!' + combinator;
1844 };
1845
1846 var reverse = function(expression){
1847         var expressions = expression.expressions;
1848         for (var i = 0; i < expressions.length; i++){
1849                 var exp = expressions[i];
1850                 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
1851
1852                 for (var j = 0; j < exp.length; j++){
1853                         var cexp = exp[j];
1854                         if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
1855                         cexp.combinator = cexp.reverseCombinator;
1856                         delete cexp.reverseCombinator;
1857                 }
1858
1859                 exp.reverse().push(last);
1860         }
1861         return expression;
1862 };
1863
1864 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
1865         return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
1866 };
1867
1868 var regexp = new RegExp(
1869 /*
1870 #!/usr/bin/env ruby
1871 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
1872 __END__
1873         "(?x)^(?:\
1874           \\s* ( , ) \\s*               # Separator          \n\
1875         | \\s* ( <combinator>+ ) \\s*   # Combinator         \n\
1876         |      ( \\s+ )                 # CombinatorChildren \n\
1877         |      ( <unicode>+ | \\* )     # Tag                \n\
1878         | \\#  ( <unicode>+       )     # ID                 \n\
1879         | \\.  ( <unicode>+       )     # ClassName          \n\
1880         |                               # Attribute          \n\
1881         \\[  \
1882                 \\s* (<unicode1>+)  (?:  \
1883                         \\s* ([*^$!~|]?=)  (?:  \
1884                                 \\s* (?:\
1885                                         ([\"']?)(.*?)\\9 \
1886                                 )\
1887                         )  \
1888                 )?  \\s*  \
1889         \\](?!\\]) \n\
1890         |   :+ ( <unicode>+ )(?:\
1891         \\( (?:\
1892                 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
1893         ) \\)\
1894         )?\
1895         )"
1896 */
1897         "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|:+(<unicode>+)(?:\\((?:(?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
1898         .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
1899         .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1900         .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1901 );
1902
1903 function parser(
1904         rawMatch,
1905
1906         separator,
1907         combinator,
1908         combinatorChildren,
1909
1910         tagName,
1911         id,
1912         className,
1913
1914         attributeKey,
1915         attributeOperator,
1916         attributeQuote,
1917         attributeValue,
1918
1919         pseudoClass,
1920         pseudoQuote,
1921         pseudoClassQuotedValue,
1922         pseudoClassValue
1923 ){
1924         if (separator || separatorIndex === -1){
1925                 parsed.expressions[++separatorIndex] = [];
1926                 combinatorIndex = -1;
1927                 if (separator) return '';
1928         }
1929
1930         if (combinator || combinatorChildren || combinatorIndex === -1){
1931                 combinator = combinator || ' ';
1932                 var currentSeparator = parsed.expressions[separatorIndex];
1933                 if (reversed && currentSeparator[combinatorIndex])
1934                         currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
1935                 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
1936         }
1937
1938         var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
1939
1940         if (tagName){
1941                 currentParsed.tag = tagName.replace(reUnescape, '');
1942
1943         } else if (id){
1944                 currentParsed.id = id.replace(reUnescape, '');
1945
1946         } else if (className){
1947                 className = className.replace(reUnescape, '');
1948
1949                 if (!currentParsed.classList) currentParsed.classList = [];
1950                 if (!currentParsed.classes) currentParsed.classes = [];
1951                 currentParsed.classList.push(className);
1952                 currentParsed.classes.push({
1953                         value: className,
1954                         regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
1955                 });
1956
1957         } else if (pseudoClass){
1958                 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
1959                 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
1960
1961                 if (!currentParsed.pseudos) currentParsed.pseudos = [];
1962                 currentParsed.pseudos.push({
1963                         key: pseudoClass.replace(reUnescape, ''),
1964                         value: pseudoClassValue
1965                 });
1966
1967         } else if (attributeKey){
1968                 attributeKey = attributeKey.replace(reUnescape, '');
1969                 attributeValue = (attributeValue || '').replace(reUnescape, '');
1970
1971                 var test, regexp;
1972
1973                 switch (attributeOperator){
1974                         case '^=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue)            ); break;
1975                         case '$=' : regexp = new RegExp(            escapeRegExp(attributeValue) +'$'       ); break;
1976                         case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
1977                         case '|=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue) +'(-|$)'   ); break;
1978                         case  '=' : test = function(value){
1979                                 return attributeValue == value;
1980                         }; break;
1981                         case '*=' : test = function(value){
1982                                 return value && value.indexOf(attributeValue) > -1;
1983                         }; break;
1984                         case '!=' : test = function(value){
1985                                 return attributeValue != value;
1986                         }; break;
1987                         default   : test = function(value){
1988                                 return !!value;
1989                         };
1990                 }
1991
1992                 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
1993                         return false;
1994                 };
1995
1996                 if (!test) test = function(value){
1997                         return value && regexp.test(value);
1998                 };
1999
2000                 if (!currentParsed.attributes) currentParsed.attributes = [];
2001                 currentParsed.attributes.push({
2002                         key: attributeKey,
2003                         operator: attributeOperator,
2004                         value: attributeValue,
2005                         test: test
2006                 });
2007
2008         }
2009
2010         return '';
2011 };
2012
2013 // Slick NS
2014
2015 var Slick = (this.Slick || {});
2016
2017 Slick.parse = function(expression){
2018         return parse(expression);
2019 };
2020
2021 Slick.escapeRegExp = escapeRegExp;
2022
2023 if (!this.Slick) this.Slick = Slick;
2024
2025 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
2026
2027
2028 /*
2029 ---
2030 name: Slick.Finder
2031 description: The new, superfast css selector engine.
2032 provides: Slick.Finder
2033 requires: Slick.Parser
2034 ...
2035 */
2036
2037 (function(){
2038
2039 var local = {};
2040
2041 // Feature / Bug detection
2042
2043 local.isNativeCode = function(fn){
2044         return (/\{\s*\[native code\]\s*\}/).test('' + fn);
2045 };
2046
2047 local.isXML = function(document){
2048         return (!!document.xmlVersion) || (!!document.xml) || (Object.prototype.toString.call(document) === '[object XMLDocument]') ||
2049         (document.nodeType === 9 && document.documentElement.nodeName !== 'HTML');
2050 };
2051
2052 local.setDocument = function(document){
2053
2054         // convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
2055
2056         if (document.nodeType === 9); // document
2057         else if (document.ownerDocument) document = document.ownerDocument; // node
2058         else if (document.navigator) document = document.document; // window
2059         else return;
2060
2061         // check if it's the old document
2062
2063         if (this.document === document) return;
2064         this.document = document;
2065         var root = this.root = document.documentElement;
2066
2067         this.isXMLDocument = this.isXML(document);
2068
2069         this.brokenStarGEBTN
2070         = this.starSelectsClosedQSA
2071         = this.idGetsName
2072         = this.brokenMixedCaseQSA
2073         = this.brokenGEBCN
2074         = this.brokenCheckedQSA
2075         = this.brokenEmptyAttributeQSA
2076         = this.isHTMLDocument
2077         = false;
2078
2079         var starSelectsClosed, starSelectsComments,
2080                 brokenSecondClassNameGEBCN, cachedGetElementsByClassName;
2081
2082         var selected, id;
2083         var testNode = document.createElement('div');
2084         root.appendChild(testNode);
2085
2086         // on non-HTML documents innerHTML and getElementsById doesnt work properly
2087         try {
2088                 id = 'slick_getbyid_test';
2089                 testNode.innerHTML = '<a id="'+id+'"></a>';
2090                 this.isHTMLDocument = !!document.getElementById(id);
2091         } catch(e){};
2092
2093         if (this.isHTMLDocument){
2094                 
2095                 testNode.style.display = 'none';
2096                 
2097                 // IE returns comment nodes for getElementsByTagName('*') for some documents
2098                 testNode.appendChild(document.createComment(''));
2099                 starSelectsComments = (testNode.getElementsByTagName('*').length > 0);
2100
2101                 // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
2102                 try {
2103                         testNode.innerHTML = 'foo</foo>';
2104                         selected = testNode.getElementsByTagName('*');
2105                         starSelectsClosed = (selected && selected.length && selected[0].nodeName.charAt(0) == '/');
2106                 } catch(e){};
2107
2108                 this.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
2109
2110                 // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
2111                 if (testNode.querySelectorAll) try {
2112                         testNode.innerHTML = 'foo</foo>';
2113                         selected = testNode.querySelectorAll('*');
2114                         this.starSelectsClosedQSA = (selected && selected.length && selected[0].nodeName.charAt(0) == '/');
2115                 } catch(e){};
2116
2117                 // IE returns elements with the name instead of just id for getElementsById for some documents
2118                 try {
2119                         id = 'slick_id_gets_name';
2120                         testNode.innerHTML = '<a name="'+id+'"></a><b id="'+id+'"></b>';
2121                         this.idGetsName = document.getElementById(id) === testNode.firstChild;
2122                 } catch(e){};
2123
2124                 // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
2125                 try {
2126                         testNode.innerHTML = '<a class="MiXedCaSe"></a>';
2127                         this.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiXedCaSe').length;
2128                 } catch(e){};
2129
2130                 try {
2131                         testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
2132                         testNode.getElementsByClassName('b').length;
2133                         testNode.firstChild.className = 'b';
2134                         cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
2135                 } catch(e){};
2136
2137                 // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
2138                 try {
2139                         testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
2140                         brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
2141                 } catch(e){};
2142
2143                 this.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
2144                 
2145                 // Webkit dont return selected options on querySelectorAll
2146                 try {
2147                         testNode.innerHTML = '<select><option selected="selected">a</option></select>';
2148                         this.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
2149                 } catch(e){};
2150                 
2151                 // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
2152                 try {
2153                         testNode.innerHTML = '<a class=""></a>';
2154                         this.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
2155                 } catch(e){};
2156                 
2157         }
2158
2159         root.removeChild(testNode);
2160         testNode = null;
2161
2162         // hasAttribute
2163
2164         this.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
2165                 return node.hasAttribute(attribute);
2166         } : function(node, attribute) {
2167                 node = node.getAttributeNode(attribute);
2168                 return !!(node && (node.specified || node.nodeValue));
2169         };
2170
2171         // contains
2172         // FIXME: Add specs: local.contains should be different for xml and html documents?
2173         this.contains = (root && this.isNativeCode(root.contains)) ? function(context, node){
2174                 return context.contains(node);
2175         } : (root && root.compareDocumentPosition) ? function(context, node){
2176                 return context === node || !!(context.compareDocumentPosition(node) & 16);
2177         } : function(context, node){
2178                 if (node) do {
2179                         if (node === context) return true;
2180                 } while ((node = node.parentNode));
2181                 return false;
2182         };
2183
2184         // document order sorting
2185         // credits to Sizzle (http://sizzlejs.com/)
2186
2187         this.documentSorter = (root.compareDocumentPosition) ? function(a, b){
2188                 if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
2189                 return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
2190         } : ('sourceIndex' in root) ? function(a, b){
2191                 if (!a.sourceIndex || !b.sourceIndex) return 0;
2192                 return a.sourceIndex - b.sourceIndex;
2193         } : (document.createRange) ? function(a, b){
2194                 if (!a.ownerDocument || !b.ownerDocument) return 0;
2195                 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
2196                 aRange.setStart(a, 0);
2197                 aRange.setEnd(a, 0);
2198                 bRange.setStart(b, 0);
2199                 bRange.setEnd(b, 0);
2200                 return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
2201         } : null ;
2202
2203         this.getUID = (this.isHTMLDocument) ? this.getUIDHTML : this.getUIDXML;
2204
2205 };
2206
2207 // Main Method
2208
2209 local.search = function(context, expression, append, first){
2210
2211         var found = this.found = (first) ? null : (append || []);
2212
2213         // context checks
2214
2215         if (!context) return found; // No context
2216         if (context.navigator) context = context.document; // Convert the node from a window to a document
2217         else if (!context.nodeType) return found; // Reject misc junk input
2218
2219         // setup
2220
2221         var parsed, i;
2222
2223         var uniques = this.uniques = {};
2224
2225         if (this.document !== (context.ownerDocument || context)) this.setDocument(context);
2226
2227         // should sort if there are nodes in append and if you pass multiple expressions.
2228         // should remove duplicates if append already has items
2229         var shouldUniques = !!(append && append.length);
2230
2231         // avoid duplicating items already in the append array
2232         if (shouldUniques) for (i = found.length; i--;) this.uniques[this.getUID(found[i])] = true;
2233
2234         // expression checks
2235
2236         if (typeof expression == 'string'){ // expression is a string
2237
2238                 // Overrides
2239
2240                 for (i = this.overrides.length; i--;){
2241                         var override = this.overrides[i];
2242                         if (override.regexp.test(expression)){
2243                                 var result = override.method.call(context, expression, found, first);
2244                                 if (result === false) continue;
2245                                 if (result === true) return found;
2246                                 return result;
2247                         }
2248                 }
2249
2250                 parsed = this.Slick.parse(expression);
2251                 if (!parsed.length) return found;
2252         } else if (expression == null){ // there is no expression
2253                 return found;
2254         } else if (expression.Slick){ // expression is a parsed Slick object
2255                 parsed = expression;
2256         } else if (this.contains(context.documentElement || context, expression)){ // expression is a node
2257                 (found) ? found.push(expression) : found = expression;
2258                 return found;
2259         } else { // other junk
2260                 return found;
2261         }
2262
2263         // cache elements for the nth selectors
2264
2265         /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2266
2267         this.posNTH = {};
2268         this.posNTHLast = {};
2269         this.posNTHType = {};
2270         this.posNTHTypeLast = {};
2271
2272         /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2273
2274         // if append is null and there is only a single selector with one expression use pushArray, else use pushUID
2275         this.push = (!shouldUniques && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
2276
2277         if (found == null) found = [];
2278
2279         // default engine
2280
2281         var j, m, n;
2282         var combinator, tag, id, classList, classes, attributes, pseudos;
2283         var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;
2284
2285         search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){
2286
2287                 combinator = 'combinator:' + currentBit.combinator;
2288                 if (!this[combinator]) continue search;
2289
2290                 tag        = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
2291                 id         = currentBit.id;
2292                 classList  = currentBit.classList;
2293                 classes    = currentBit.classes;
2294                 attributes = currentBit.attributes;
2295                 pseudos    = currentBit.pseudos;
2296                 lastBit    = (j === (currentExpression.length - 1));
2297
2298                 this.bitUniques = {};
2299
2300                 if (lastBit){
2301                         this.uniques = uniques;
2302                         this.found = found;
2303                 } else {
2304                         this.uniques = {};
2305                         this.found = [];
2306                 }
2307
2308                 if (j === 0){
2309                         this[combinator](context, tag, id, classes, attributes, pseudos, classList);
2310                         if (first && lastBit && found.length) break search;
2311                 } else {
2312                         if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
2313                                 this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2314                                 if (found.length) break search;
2315                         } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2316                 }
2317
2318                 currentItems = this.found;
2319         }
2320
2321         if (shouldUniques || (parsed.expressions.length > 1)) this.sort(found);
2322
2323         return (first) ? (found[0] || null) : found;
2324 };
2325
2326 // Utils
2327
2328 local.uidx = 1;
2329 local.uidk = 'slick:uniqueid';
2330
2331 local.getUIDXML = function(node){
2332         var uid = node.getAttribute(this.uidk);
2333         if (!uid){
2334                 uid = this.uidx++;
2335                 node.setAttribute(this.uidk, uid);
2336         }
2337         return uid;
2338 };
2339
2340 local.getUIDHTML = function(node){
2341         return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
2342 };
2343
2344 // sort based on the setDocument documentSorter method.
2345
2346 local.sort = function(results){
2347         if (!this.documentSorter) return results;
2348         results.sort(this.documentSorter);
2349         return results;
2350 };
2351
2352 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2353
2354 local.cacheNTH = {};
2355
2356 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;
2357
2358 local.parseNTHArgument = function(argument){
2359         var parsed = argument.match(this.matchNTH);
2360         if (!parsed) return false;
2361         var special = parsed[2] || false;
2362         var a = parsed[1] || 1;
2363         if (a == '-') a = -1;
2364         var b = +parsed[3] || 0;
2365         parsed =
2366                 (special == 'n')        ? {a: a, b: b} :
2367                 (special == 'odd')      ? {a: 2, b: 1} :
2368                 (special == 'even')     ? {a: 2, b: 0} : {a: 0, b: a};
2369
2370         return (this.cacheNTH[argument] = parsed);
2371 };
2372
2373 local.createNTHPseudo = function(child, sibling, positions, ofType){
2374         return function(node, argument){
2375                 var uid = this.getUID(node);
2376                 if (!this[positions][uid]){
2377                         var parent = node.parentNode;
2378                         if (!parent) return false;
2379                         var el = parent[child], count = 1;
2380                         if (ofType){
2381                                 var nodeName = node.nodeName;
2382                                 do {
2383                                         if (el.nodeName !== nodeName) continue;
2384                                         this[positions][this.getUID(el)] = count++;
2385                                 } while ((el = el[sibling]));
2386                         } else {
2387                                 do {
2388                                         if (el.nodeType !== 1) continue;
2389                                         this[positions][this.getUID(el)] = count++;
2390                                 } while ((el = el[sibling]));
2391                         }
2392                 }
2393                 argument = argument || 'n';
2394                 var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
2395                 if (!parsed) return false;
2396                 var a = parsed.a, b = parsed.b, pos = this[positions][uid];
2397                 if (a == 0) return b == pos;
2398                 if (a > 0){
2399                         if (pos < b) return false;
2400                 } else {
2401                         if (b < pos) return false;
2402                 }
2403                 return ((pos - b) % a) == 0;
2404         };
2405 };
2406
2407 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2408
2409 local.pushArray = function(node, tag, id, classes, attributes, pseudos){
2410         if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
2411 };
2412
2413 local.pushUID = function(node, tag, id, classes, attributes, pseudos){
2414         var uid = this.getUID(node);
2415         if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
2416                 this.uniques[uid] = true;
2417                 this.found.push(node);
2418         }
2419 };
2420
2421 local.matchNode = function(node, selector){
2422         var parsed = this.Slick.parse(selector);
2423         if (!parsed) return true;
2424
2425         // simple (single) selectors
2426         if(parsed.length == 1 && parsed.expressions[0].length == 1){
2427                 var exp = parsed.expressions[0][0];
2428                 return this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos);
2429         }
2430
2431         var nodes = this.search(this.document, parsed);
2432         for (var i = 0, item; item = nodes[i++];){
2433                 if (item === node) return true;
2434         }
2435         return false;
2436 };
2437
2438 local.matchPseudo = function(node, name, argument){
2439         var pseudoName = 'pseudo:' + name;
2440         if (this[pseudoName]) return this[pseudoName](node, argument);
2441         var attribute = this.getAttribute(node, name);
2442         return (argument) ? argument == attribute : !!attribute;
2443 };
2444
2445 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
2446         if (tag){
2447                 if (tag == '*'){
2448                         if (node.nodeName < '@') return false; // Fix for comment nodes and closed nodes
2449                 } else {
2450                         if (node.nodeName != tag) return false;
2451                 }
2452         }
2453
2454         if (id && node.getAttribute('id') != id) return false;
2455
2456         var i, part, cls;
2457         if (classes) for (i = classes.length; i--;){
2458                 cls = ('className' in node) ? node.className : node.getAttribute('class');
2459                 if (!(cls && classes[i].regexp.test(cls))) return false;
2460         }
2461         if (attributes) for (i = attributes.length; i--;){
2462                 part = attributes[i];
2463                 if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
2464         }
2465         if (pseudos) for (i = pseudos.length; i--;){
2466                 part = pseudos[i];
2467                 if (!this.matchPseudo(node, part.key, part.value)) return false;
2468         }
2469         return true;
2470 };
2471
2472 var combinators = {
2473
2474         ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level
2475
2476                 var i, item, children;
2477
2478                 if (this.isHTMLDocument){
2479                         getById: if (id){
2480                                 item = this.document.getElementById(id);
2481                                 if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
2482                                         // all[id] returns all the elements with that name or id inside node
2483                                         // if theres just one it will return the element, else it will be a collection
2484                                         children = node.all[id];
2485                                         if (!children) return;
2486                                         if (!children[0]) children = [children];
2487                                         for (i = 0; item = children[i++];) if (item.getAttributeNode('id').nodeValue == id){
2488                                                 this.push(item, tag, null, classes, attributes, pseudos);
2489                                                 break;
2490                                         } 
2491                                         return;
2492                                 }
2493                                 if (!item){
2494                                         // if the context is in the dom we return, else we will try GEBTN, breaking the getById label
2495                                         if (this.contains(this.document.documentElement, node)) return;
2496                                         else break getById;
2497                                 } else if (this.document !== node && !this.contains(node, item)) return;
2498                                 this.push(item, tag, null, classes, attributes, pseudos);
2499                                 return;
2500                         }
2501                         getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
2502                                 children = node.getElementsByClassName(classList.join(' '));
2503                                 if (!(children && children.length)) break getByClass;
2504                                 for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
2505                                 return;
2506                         }
2507                 }
2508                 getByTag: {
2509                         children = node.getElementsByTagName(tag);
2510                         if (!(children && children.length)) break getByTag;
2511                         if (!this.brokenStarGEBTN) tag = null;
2512                         for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
2513                 }
2514         },
2515
2516         '>': function(node, tag, id, classes, attributes, pseudos){ // direct children
2517                 if ((node = node.firstChild)) do {
2518                         if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
2519                 } while ((node = node.nextSibling));
2520         },
2521
2522         '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
2523                 while ((node = node.nextSibling)) if (node.nodeType === 1){
2524                         this.push(node, tag, id, classes, attributes, pseudos);
2525                         break;
2526                 }
2527         },
2528
2529         '^': function(node, tag, id, classes, attributes, pseudos){ // first child
2530                 node = node.firstChild;
2531                 if (node){
2532                         if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
2533                         else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2534                 }
2535         },
2536
2537         '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
2538                 while ((node = node.nextSibling)){
2539                         if (node.nodeType !== 1) continue;
2540                         var uid = this.getUID(node);
2541                         if (this.bitUniques[uid]) break;
2542                         this.bitUniques[uid] = true;
2543                         this.push(node, tag, id, classes, attributes, pseudos);
2544                 }
2545         },
2546
2547         '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
2548                 this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2549                 this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2550         },
2551
2552         '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
2553                 this['combinator:~'](node, tag, id, classes, attributes, pseudos);
2554                 this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
2555         },
2556
2557         '!': function(node, tag, id, classes, attributes, pseudos){  // all parent nodes up to document
2558                 while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2559         },
2560
2561         '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
2562                 node = node.parentNode;
2563                 if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2564         },
2565
2566         '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
2567                 while ((node = node.previousSibling)) if (node.nodeType === 1){
2568                         this.push(node, tag, id, classes, attributes, pseudos);
2569                         break;
2570                 }
2571         },
2572
2573         '!^': function(node, tag, id, classes, attributes, pseudos){ // last child
2574                 node = node.lastChild;
2575                 if (node){
2576                         if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
2577                         else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2578                 }
2579         },
2580
2581         '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
2582                 while ((node = node.previousSibling)){
2583                         if (node.nodeType !== 1) continue;
2584                         var uid = this.getUID(node);
2585                         if (this.bitUniques[uid]) break;
2586                         this.bitUniques[uid] = true;
2587                         this.push(node, tag, id, classes, attributes, pseudos);
2588                 }
2589         }
2590
2591 };
2592
2593 for (var c in combinators) local['combinator:' + c] = combinators[c];
2594
2595 var pseudos = {
2596
2597         /*<pseudo-selectors>*/
2598
2599         'empty': function(node){
2600                 var child = node.firstChild;
2601                 return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
2602         },
2603
2604         'not': function(node, expression){
2605                 return !this.matchNode(node, expression);
2606         },
2607
2608         'contains': function(node, text){
2609                 return (node.innerText || node.textContent || '').indexOf(text) > -1;
2610         },
2611
2612         'first-child': function(node){
2613                 while ((node = node.previousSibling)) if (node.nodeType === 1) return false;
2614                 return true;
2615         },
2616
2617         'last-child': function(node){
2618                 while ((node = node.nextSibling)) if (node.nodeType === 1) return false;
2619                 return true;
2620         },
2621
2622         'only-child': function(node){
2623                 var prev = node;
2624                 while ((prev = prev.previousSibling)) if (prev.nodeType === 1) return false;
2625                 var next = node;
2626                 while ((next = next.nextSibling)) if (next.nodeType === 1) return false;
2627                 return true;
2628         },
2629
2630         /*<nth-pseudo-selectors>*/
2631
2632         'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),
2633
2634         'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),
2635
2636         'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),
2637
2638         'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),
2639
2640         'index': function(node, index){
2641                 return this['pseudo:nth-child'](node, '' + index + 1);
2642         },
2643
2644         'even': function(node, argument){
2645                 return this['pseudo:nth-child'](node, '2n');
2646         },
2647
2648         'odd': function(node, argument){
2649                 return this['pseudo:nth-child'](node, '2n+1');
2650         },
2651
2652         /*</nth-pseudo-selectors>*/
2653
2654         /*<of-type-pseudo-selectors>*/
2655
2656         'first-of-type': function(node){
2657                 var nodeName = node.nodeName;
2658                 while ((node = node.previousSibling)) if (node.nodeName === nodeName) return false;
2659                 return true;
2660         },
2661
2662         'last-of-type': function(node){
2663                 var nodeName = node.nodeName;
2664                 while ((node = node.nextSibling)) if (node.nodeName === nodeName) return false;
2665                 return true;
2666         },
2667
2668         'only-of-type': function(node){
2669                 var prev = node, nodeName = node.nodeName;
2670                 while ((prev = prev.previousSibling)) if (prev.nodeName === nodeName) return false;
2671                 var next = node;
2672                 while ((next = next.nextSibling)) if (next.nodeName === nodeName) return false;
2673                 return true;
2674         },
2675
2676         /*</of-type-pseudo-selectors>*/
2677
2678         // custom pseudos
2679
2680         'enabled': function(node){
2681                 return (node.disabled === false);
2682         },
2683
2684         'disabled': function(node){
2685                 return (node.disabled === true);
2686         },
2687
2688         'checked': function(node){
2689                 return node.checked || node.selected;
2690         },
2691
2692         'focus': function(node){
2693                 return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
2694         },
2695
2696         'root': function(node){
2697                 return (node === this.root);
2698         },
2699         
2700         'selected': function(node){
2701                 return node.selected;
2702         }
2703
2704         /*</pseudo-selectors>*/
2705 };
2706
2707 for (var p in pseudos) local['pseudo:' + p] = pseudos[p];
2708
2709 // attributes methods
2710
2711 local.attributeGetters = {
2712
2713         'class': function(){
2714                 return ('className' in this) ? this.className : this.getAttribute('class');
2715         },
2716
2717         'for': function(){
2718                 return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
2719         },
2720
2721         'href': function(){
2722                 return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
2723         },
2724
2725         'style': function(){
2726                 return (this.style) ? this.style.cssText : this.getAttribute('style');
2727         }
2728
2729 };
2730
2731 local.getAttribute = function(node, name){
2732         // FIXME: check if getAttribute() will get input elements on a form on this browser
2733         // getAttribute is faster than getAttributeNode().nodeValue
2734         var method = this.attributeGetters[name];
2735         if (method) return method.call(node);
2736         var attributeNode = node.getAttributeNode(name);
2737         return attributeNode ? attributeNode.nodeValue : null;
2738 };
2739
2740 // overrides
2741
2742 local.overrides = [];
2743
2744 local.override = function(regexp, method){
2745         this.overrides.push({regexp: regexp, method: method});
2746 };
2747
2748 /*<overrides>*/
2749
2750 /*<query-selector-override>*/
2751
2752 var reEmptyAttribute = /\[.*[*$^]=(?:["']{2})?\]/;
2753
2754 local.override(/./, function(expression, found, first){ //querySelectorAll override
2755
2756         if (!this.querySelectorAll || this.nodeType != 9 || !local.isHTMLDocument || local.brokenMixedCaseQSA ||
2757         (local.brokenCheckedQSA && expression.indexOf(':checked') > -1) ||
2758         (local.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) || Slick.disableQSA) return false;
2759
2760         var nodes, node;
2761         try {
2762                 if (first) return this.querySelector(expression) || null;
2763                 else nodes = this.querySelectorAll(expression);
2764         } catch(error){
2765                 return false;
2766         }
2767
2768         var i, hasOthers = !!(found.length);
2769
2770         if (local.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
2771                 if (node.nodeName > '@' && (!hasOthers || !local.uniques[local.getUIDHTML(node)])) found.push(node);
2772         } else for (i = 0; node = nodes[i++];){
2773                 if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node);
2774         }
2775
2776         if (hasOthers) local.sort(found);
2777
2778         return true;
2779
2780 });
2781
2782 /*</query-selector-override>*/
2783
2784 /*<tag-override>*/
2785
2786 local.override(/^[\w-]+$|^\*$/, function(expression, found, first){ // tag override
2787         var tag = expression;
2788         if (tag == '*' && local.brokenStarGEBTN) return false;
2789
2790         var nodes = this.getElementsByTagName(tag);
2791
2792         if (first) return nodes[0] || null;
2793         var i, node, hasOthers = !!(found.length);
2794
2795         for (i = 0; node = nodes[i++];){
2796                 if (!hasOthers || !local.uniques[local.getUID(node)]) found.push(node);
2797         }
2798
2799         if (hasOthers) local.sort(found);
2800
2801         return true;
2802 });
2803
2804 /*</tag-override>*/
2805
2806 /*<class-override>*/
2807
2808 local.override(/^\.[\w-]+$/, function(expression, found, first){ // class override
2809         if (!local.isHTMLDocument || (!this.getElementsByClassName && this.querySelectorAll)) return false;
2810
2811         var nodes, node, i, hasOthers = !!(found && found.length), className = expression.substring(1);
2812         if (this.getElementsByClassName && !local.brokenGEBCN){
2813                 nodes = this.getElementsByClassName(className);
2814                 if (first) return nodes[0] || null;
2815                 for (i = 0; node = nodes[i++];){
2816                         if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node);
2817                 }
2818         } else {
2819                 var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(className) +'(\\s|$)');
2820                 nodes = this.getElementsByTagName('*');
2821                 for (i = 0; node = nodes[i++];){
2822                         className = node.className;
2823                         if (!className || !matchClass.test(className)) continue;
2824                         if (first) return node;
2825                         if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node);
2826                 }
2827         }
2828         if (hasOthers) local.sort(found);
2829         return (first) ? null : true;
2830 });
2831
2832 /*</class-override>*/
2833
2834 /*<id-override>*/
2835
2836 local.override(/^#[\w-]+$/, function(expression, found, first){ // ID override
2837         if (!local.isHTMLDocument || this.nodeType != 9) return false;
2838
2839         var id = expression.substring(1), el = this.getElementById(id);
2840         if (!el) return found;
2841         if (local.idGetsName && el.getAttributeNode('id').nodeValue != id) return false;
2842         if (first) return el || null;
2843         var hasOthers = !!(found.length);
2844         if (!hasOthers || !local.uniques[local.getUIDHTML(el)]) found.push(el);
2845         if (hasOthers) local.sort(found);
2846         return true;
2847 });
2848
2849 /*</id-override>*/
2850
2851 /*</overrides>*/
2852
2853 if (typeof document != 'undefined') local.setDocument(document);
2854
2855 // Slick
2856
2857 var Slick = local.Slick = (this.Slick || {});
2858
2859 Slick.version = '0.9dev';
2860
2861 // Slick finder
2862
2863 Slick.search = function(context, expression, append){
2864         return local.search(context, expression, append);
2865 };
2866
2867 Slick.find = function(context, expression){
2868         return local.search(context, expression, null, true);
2869 };
2870
2871 // Slick containment checker
2872
2873 Slick.contains = function(container, node){
2874         local.setDocument(container);
2875         return local.contains(container, node);
2876 };
2877
2878 // Slick attribute getter
2879
2880 Slick.getAttribute = function(node, name){
2881         return local.getAttribute(node, name);
2882 };
2883
2884 // Slick matcher
2885
2886 Slick.match = function(node, selector){
2887         if (!(node && selector)) return false;
2888         if (!selector || selector === node) return true;
2889         if (typeof selector != 'string') return false;
2890         local.setDocument(node);
2891         return local.matchNode(node, selector);
2892 };
2893
2894 // Slick attribute accessor
2895
2896 Slick.defineAttributeGetter = function(name, fn){
2897         local.attributeGetters[name] = fn;
2898         return this;
2899 };
2900
2901 Slick.lookupAttributeGetter = function(name){
2902         return local.attributeGetters[name];
2903 };
2904
2905 // Slick pseudo accessor
2906
2907 Slick.definePseudo = function(name, fn){
2908         local['pseudo:' + name] = function(node, argument){
2909                 return fn.call(node, argument);
2910         };
2911         return this;
2912 };
2913
2914 Slick.lookupPseudo = function(name){
2915         var pseudo = local['pseudo:' + name];
2916         if (pseudo) return function(argument){
2917                 return pseudo.call(this, argument);
2918         };
2919         return null;
2920 };
2921
2922 // Slick overrides accessor
2923
2924 Slick.override = function(regexp, fn){
2925         local.override(regexp, fn);
2926         return this;
2927 };
2928
2929 Slick.isXML = local.isXML;
2930
2931 Slick.uidOf = function(node){
2932         return local.getUIDHTML(node);
2933 };
2934
2935 if (!this.Slick) this.Slick = Slick;
2936
2937 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
2938
2939
2940 /*
2941 ---
2942
2943 name: Element
2944
2945 description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements.
2946
2947 license: MIT-style license.
2948
2949 requires: [Window, Document, Array, String, Function, Number, Slick.Parser, Slick.Finder]
2950
2951 provides: [Element, Elements, $, $$, Iframe, Selectors]
2952
2953 ...
2954 */
2955
2956 var Element = function(tag, props){
2957         var konstructor = Element.Constructors[tag];
2958         if (konstructor) return konstructor(props);
2959         if (typeof tag != 'string') return document.id(tag).set(props);
2960
2961         if (!props) props = {};
2962
2963         if (!tag.test(/^[\w-]+$/)){
2964                 var parsed = Slick.parse(tag).expressions[0][0];
2965                 tag = (parsed.tag == '*') ? 'div' : parsed.tag;
2966                 if (parsed.id && props.id == null) props.id = parsed.id;
2967
2968                 var attributes = parsed.attributes;
2969                 if (attributes) for (var i = 0, l = attributes.length; i < l; i++){
2970                         var attr = attributes[i];
2971                         if (attr.value != null && attr.operator == '=' && props[attr.key] == null)
2972                                 props[attr.key] = attr.value;
2973                 }
2974
2975                 if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' ');
2976         }
2977
2978         return document.newElement(tag, props);
2979 };
2980
2981 if (Browser.Element) Element.prototype = Browser.Element.prototype;
2982
2983 new Type('Element', Element).mirror(function(name){
2984         if (Array.prototype[name]) return;
2985
2986         var obj = {};
2987         obj[name] = function(){
2988                 var results = [], args = arguments, elements = true;
2989                 for (var i = 0, l = this.length; i < l; i++){
2990                         var element = this[i], result = results[i] = element[name].apply(element, args);
2991                         elements = (elements && typeOf(result) == 'element');
2992                 }
2993                 return (elements) ? new Elements(results) : results;
2994         };
2995
2996         Elements.implement(obj);
2997 });
2998
2999 if (!Browser.Element){
3000         Element.parent = Object;
3001
3002         Element.Prototype = {'$family': Function.from('element').hide()};
3003
3004         Element.mirror(function(name, method){
3005                 Element.Prototype[name] = method;
3006         });
3007 }
3008
3009 Element.Constructors = {};
3010
3011 //<1.2compat>
3012
3013 Element.Constructors = new Hash;
3014
3015 //</1.2compat>
3016
3017 var IFrame = new Type('IFrame', function(){
3018         var params = Array.link(arguments, {
3019                 properties: Type.isObject,
3020                 iframe: function(obj){
3021                         return (obj != null);
3022                 }
3023         });
3024
3025         var props = params.properties || {}, iframe;
3026         if (params.iframe) iframe = document.id(params.iframe);
3027         var onload = props.onload || function(){};
3028         delete props.onload;
3029         props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick();
3030         iframe = new Element(iframe || 'iframe', props);
3031
3032         var onLoad = function(){
3033                 onload.call(iframe.contentWindow);
3034         };
3035         
3036         if (window.frames[props.id]) onLoad();
3037         else iframe.addListener('load', onLoad);
3038         return iframe;
3039 });
3040
3041 var Elements = this.Elements = function(nodes){
3042         if (nodes && nodes.length){
3043                 var uniques = {}, node;
3044                 for (var i = 0; node = nodes[i++];){
3045                         var uid = Slick.uidOf(node);
3046                         if (!uniques[uid]){
3047                                 uniques[uid] = true;
3048                                 this.push(node);
3049                         }
3050                 }
3051         }
3052 };
3053
3054 Elements.prototype = {length: 0};
3055 Elements.parent = Array;
3056
3057 new Type('Elements', Elements).implement({
3058
3059         filter: function(filter, bind){
3060                 if (!filter) return this;
3061                 return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){
3062                         return item.match(filter);
3063                 } : filter, bind));
3064         }.protect(),
3065
3066         push: function(){
3067                 var length = this.length;
3068                 for (var i = 0, l = arguments.length; i < l; i++){
3069                         var item = document.id(arguments[i]);
3070                         if (item) this[length++] = item;
3071                 }
3072                 return (this.length = length);
3073         }.protect(),
3074
3075         concat: function(){
3076                 var newElements = new Elements(this);
3077                 for (var i = 0, l = arguments.length; i < l; i++){
3078                         var item = arguments[i];
3079                         if (Type.isEnumerable(item)) newElements.append(item);
3080                         else newElements.push(item);
3081                 }
3082                 return newElements;
3083         }.protect(),
3084
3085         append: function(collection){
3086                 for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]);
3087                 return this;
3088         }.protect(),
3089
3090         empty: function(){
3091                 while (this.length) delete this[--this.length];
3092                 return this;
3093         }.protect()
3094
3095 });
3096
3097 (function(){
3098
3099 // FF, IE
3100 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2};
3101
3102 splice.call(object, 1, 1);
3103 if (object[1] == 1) Elements.implement('splice', function(){
3104         var length = this.length;
3105         splice.apply(this, arguments);
3106         while (length >= this.length) delete this[length--];
3107         return this;
3108 }.protect());
3109
3110 Elements.implement(Array.prototype);
3111
3112 Array.mirror(Elements);
3113
3114 /*<ltIE8>*/
3115 var createElementAcceptsHTML;
3116 try {
3117         var x = document.createElement('<input name=x>');
3118         createElementAcceptsHTML = (x.name == 'x');
3119 } catch(e){}
3120
3121 var escapeQuotes = function(html){
3122         return ('' + html).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
3123 };
3124 /*</ltIE8>*/
3125
3126 Document.implement({
3127
3128         newElement: function(tag, props){
3129                 if (props && props.checked != null) props.defaultChecked = props.checked;
3130                 /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
3131                 if (createElementAcceptsHTML && props){
3132                         tag = '<' + tag;
3133                         if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
3134                         if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
3135                         tag += '>';
3136                         delete props.name;
3137                         delete props.type;
3138                 }
3139                 /*</ltIE8>*/
3140                 return this.id(this.createElement(tag)).set(props);
3141         }
3142
3143 });
3144
3145 })();
3146
3147 Document.implement({
3148
3149         newTextNode: function(text){
3150                 return this.createTextNode(text);
3151         },
3152
3153         getDocument: function(){
3154                 return this;
3155         },
3156
3157         getWindow: function(){
3158                 return this.window;
3159         },
3160
3161         id: (function(){
3162
3163                 var types = {
3164
3165                         string: function(id, nocash, doc){
3166                                 id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1'));
3167                                 return (id) ? types.element(id, nocash) : null;
3168                         },
3169
3170                         element: function(el, nocash){
3171                                 $uid(el);
3172                                 if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
3173                                         Object.append(el, Element.Prototype);
3174                                 }
3175                                 return el;
3176                         },
3177
3178                         object: function(obj, nocash, doc){
3179                                 if (obj.toElement) return types.element(obj.toElement(doc), nocash);
3180                                 return null;
3181                         }
3182
3183                 };
3184
3185                 types.textnode = types.whitespace = types.window = types.document = function(zero){
3186                         return zero;
3187                 };
3188
3189                 return function(el, nocash, doc){
3190                         if (el && el.$family && el.uid) return el;
3191                         var type = typeOf(el);
3192                         return (types[type]) ? types[type](el, nocash, doc || document) : null;
3193                 };
3194
3195         })()
3196
3197 });
3198
3199 if (window.$ == null) Window.implement('$', function(el, nc){
3200         return document.id(el, nc, this.document);
3201 });
3202
3203 Window.implement({
3204
3205         getDocument: function(){
3206                 return this.document;
3207         },
3208
3209         getWindow: function(){
3210                 return this;
3211         }
3212
3213 });
3214
3215 [Document, Element].invoke('implement', {
3216
3217         getElements: function(expression){
3218                 return Slick.search(this, expression, new Elements);
3219         },
3220
3221         getElement: function(expression){
3222                 return document.id(Slick.find(this, expression));
3223         }
3224
3225 });
3226
3227 //<1.2compat>
3228
3229 (function(search, find, match){
3230
3231         this.Selectors = {};
3232         var pseudos = this.Selectors.Pseudo = new Hash();
3233
3234         var addSlickPseudos = function(){
3235                 for (var name in pseudos) if (pseudos.hasOwnProperty(name)){
3236                         Slick.definePseudo(name, pseudos[name]);
3237                         delete pseudos[name];
3238                 }
3239         };
3240
3241         Slick.search = function(context, expression, append){
3242                 addSlickPseudos();
3243                 return search.call(this, context, expression, append);
3244         };
3245
3246         Slick.find = function(context, expression){
3247                 addSlickPseudos();
3248                 return find.call(this, context, expression);
3249         };
3250
3251         Slick.match = function(node, selector){
3252                 addSlickPseudos();
3253                 return match.call(this, node, selector);
3254         };
3255
3256 })(Slick.search, Slick.find, Slick.match);
3257
3258 if (window.$$ == null) Window.implement('$$', function(selector){
3259         var elements = new Elements;
3260         if (arguments.length == 1 && typeof selector == 'string') return Slick.search(this.document, selector, elements);
3261         var args = Array.flatten(arguments);
3262         for (var i = 0, l = args.length; i < l; i++){
3263                 var item = args[i];
3264                 switch (typeOf(item)){
3265                         case 'element': elements.push(item); break;
3266                         case 'string': Slick.search(this.document, item, elements);
3267                 }
3268         }
3269         return elements;
3270 });
3271
3272 //</1.2compat>
3273
3274 if (window.$$ == null) Window.implement('$$', function(selector){
3275         if (arguments.length == 1){
3276                 if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements);
3277                 else if (Type.isEnumerable(selector)) return new Elements(selector);
3278         }
3279         return new Elements(arguments);
3280 });
3281
3282 (function(){
3283
3284 var collected = {}, storage = {};
3285 var props = {input: 'checked', option: 'selected', textarea: 'value'};
3286
3287 var get = function(uid){
3288         return (storage[uid] || (storage[uid] = {}));
3289 };
3290
3291 var clean = function(item){
3292         if (item.removeEvents) item.removeEvents();
3293         if (item.clearAttributes) item.clearAttributes();
3294         var uid = item.uid;
3295         if (uid != null){
3296                 delete collected[uid];
3297                 delete storage[uid];
3298         }
3299         return item;
3300 };
3301
3302 var camels = ['defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly',
3303         'rowSpan', 'tabIndex', 'useMap'
3304 ];
3305 var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readOnly', 'multiple', 'selected',
3306         'noresize', 'defer'
3307 ];
3308  var attributes = {
3309         'html': 'innerHTML',
3310         'class': 'className',
3311         'for': 'htmlFor',
3312         'text': (function(){
3313                 var temp = document.createElement('div');
3314                 return (temp.innerText == null) ? 'textContent' : 'innerText';
3315         })()
3316 };
3317 var readOnly = ['type'];
3318 var expandos = ['value', 'defaultValue'];
3319 var uriAttrs = /^(?:href|src|usemap)$/i;
3320
3321 bools = bools.associate(bools);
3322 camels = camels.associate(camels.map(String.toLowerCase));
3323 readOnly = readOnly.associate(readOnly);
3324
3325 Object.append(attributes, expandos.associate(expandos));
3326
3327 var inserters = {
3328
3329         before: function(context, element){
3330                 var parent = element.parentNode;
3331                 if (parent) parent.insertBefore(context, element);
3332         },
3333
3334         after: function(context, element){
3335                 var parent = element.parentNode;
3336                 if (parent) parent.insertBefore(context, element.nextSibling);
3337         },
3338
3339         bottom: function(context, element){
3340                 element.appendChild(context);
3341         },
3342
3343         top: function(context, element){
3344                 element.insertBefore(context, element.firstChild);
3345         }
3346
3347 };
3348
3349 inserters.inside = inserters.bottom;
3350
3351 //<1.2compat>
3352
3353 Object.each(inserters, function(inserter, where){
3354
3355         where = where.capitalize();
3356
3357         var methods = {};
3358
3359         methods['inject' + where] = function(el){
3360                 inserter(this, document.id(el, true));
3361                 return this;
3362         };
3363
3364         methods['grab' + where] = function(el){
3365                 inserter(document.id(el, true), this);
3366                 return this;
3367         };
3368
3369         Element.implement(methods);
3370
3371 });
3372
3373 //</1.2compat>
3374
3375 var injectCombinator = function(expression, combinator){
3376         if (!expression) return combinator;
3377
3378         expression = Slick.parse(expression);
3379
3380         var expressions = expression.expressions;
3381         for (var i = expressions.length; i--;)
3382                 expressions[i][0].combinator = combinator;
3383
3384         return expression;
3385 };
3386
3387 Element.implement({
3388
3389         set: function(prop, value){
3390                 var property = Element.Properties[prop];
3391                 (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
3392         }.overloadSetter(),
3393
3394         get: function(prop){
3395                 var property = Element.Properties[prop];
3396                 return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
3397         }.overloadGetter(),
3398
3399         erase: function(prop){
3400                 var property = Element.Properties[prop];
3401                 (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
3402                 return this;
3403         },
3404
3405         setProperty: function(attribute, value){
3406                 attribute = camels[attribute] || attribute;
3407                 if (value == null) return this.removeProperty(attribute);
3408                 var key = attributes[attribute];
3409                 (key) ? this[key] = value :
3410                         (bools[attribute]) ? this[attribute] = !!value : this.setAttribute(attribute, '' + value);
3411                 return this;
3412         },
3413
3414         setProperties: function(attributes){
3415                 for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
3416                 return this;
3417         },
3418
3419         getProperty: function(attribute){
3420                 attribute = camels[attribute] || attribute;
3421                 var key = attributes[attribute] || readOnly[attribute];
3422                 return (key) ? this[key] :
3423                         (bools[attribute]) ? !!this[attribute] :
3424                         (uriAttrs.test(attribute) ? this.getAttribute(attribute, 2) :
3425                         (key = this.getAttributeNode(attribute)) ? key.nodeValue : null) || null;
3426         },
3427
3428         getProperties: function(){
3429                 var args = Array.from(arguments);
3430                 return args.map(this.getProperty, this).associate(args);
3431         },
3432
3433         removeProperty: function(attribute){
3434                 attribute = camels[attribute] || attribute;
3435                 var key = attributes[attribute];
3436                 (key) ? this[key] = '' :
3437                         (bools[attribute]) ? this[attribute] = false : this.removeAttribute(attribute);
3438                 return this;
3439         },
3440
3441         removeProperties: function(){
3442                 Array.each(arguments, this.removeProperty, this);
3443                 return this;
3444         },
3445
3446         hasClass: function(className){
3447                 return this.className.clean().contains(className, ' ');
3448         },
3449
3450         addClass: function(className){
3451                 if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
3452                 return this;
3453         },
3454
3455         removeClass: function(className){
3456                 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
3457                 return this;
3458         },
3459
3460         toggleClass: function(className, force){
3461                 if (force == null) force = !this.hasClass(className);
3462                 return (force) ? this.addClass(className) : this.removeClass(className);
3463         },
3464
3465         adopt: function(){
3466                 var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length;
3467                 if (length > 1) parent = fragment = document.createDocumentFragment();
3468
3469                 for (var i = 0; i < length; i++){
3470            &nb