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