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