Moved ricoLocale_xx files to their parent directory (ricoClient/js). Moved files...
[infodrom/rico3] / minsrc / prototype.js
1 /*  Prototype JavaScript framework, version 1.7
2  *  (c) 2005-2010 Sam Stephenson
3  *
4  *  Prototype is freely distributable under the terms of an MIT-style license.
5  *  For details, see the Prototype web site: http://www.prototypejs.org/
6  *
7  *--------------------------------------------------------------------------*/
8
9 var Prototype = {
10
11   Version: '1.7',
12
13   Browser: (function(){
14     var ua = navigator.userAgent;
15     var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
16     return {
17       IE:             !!window.attachEvent && !isOpera,
18       Opera:          isOpera,
19       WebKit:         ua.indexOf('AppleWebKit/') > -1,
20       Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
21       MobileSafari:   /Apple.*Mobile/.test(ua)
22     }
23   })(),
24
25   BrowserFeatures: {
26     XPath: !!document.evaluate,
27
28     SelectorsAPI: !!document.querySelector,
29
30     ElementExtensions: (function() {
31       var constructor = window.Element || window.HTMLElement;
32       return !!(constructor && constructor.prototype);
33     })(),
34     SpecificElementExtensions: (function() {
35       if (typeof window.HTMLDivElement !== 'undefined')
36         return true;
37
38       var div = document.createElement('div'),
39           form = document.createElement('form'),
40           isSupported = false;
41
42       if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
43         isSupported = true;
44       }
45
46       div = form = null;
47
48       return isSupported;
49     })()
50   },
51
52   ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
53   JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
54
55   emptyFunction: function() { },
56
57   K: function(x) { return x }
58 };
59
60 if (Prototype.Browser.MobileSafari)
61   Prototype.BrowserFeatures.SpecificElementExtensions = false;
62
63
64 var Abstract = { };
65
66
67 var Try = {
68   these: function() {
69     var returnValue;
70
71     for (var i = 0, length = arguments.length; i < length; i++) {
72       var lambda = arguments[i];
73       try {
74         returnValue = lambda();
75         break;
76       } catch (e) { }
77     }
78
79     return returnValue;
80   }
81 };
82
83 /* Based on Alex Arnell's inheritance implementation. */
84
85 var Class = (function() {
86
87   var IS_DONTENUM_BUGGY = (function(){
88     for (var p in { toString: 1 }) {
89       if (p === 'toString') return false;
90     }
91     return true;
92   })();
93
94   function subclass() {};
95   function create() {
96     var parent = null, properties = $A(arguments);
97     if (Object.isFunction(properties[0]))
98       parent = properties.shift();
99
100     function klass() {
101       this.initialize.apply(this, arguments);
102     }
103
104     Object.extend(klass, Class.Methods);
105     klass.superclass = parent;
106     klass.subclasses = [];
107
108     if (parent) {
109       subclass.prototype = parent.prototype;
110       klass.prototype = new subclass;
111       parent.subclasses.push(klass);
112     }
113
114     for (var i = 0, length = properties.length; i < length; i++)
115       klass.addMethods(properties[i]);
116
117     if (!klass.prototype.initialize)
118       klass.prototype.initialize = Prototype.emptyFunction;
119
120     klass.prototype.constructor = klass;
121     return klass;
122   }
123
124   function addMethods(source) {
125     var ancestor   = this.superclass && this.superclass.prototype,
126         properties = Object.keys(source);
127
128     if (IS_DONTENUM_BUGGY) {
129       if (source.toString != Object.prototype.toString)
130         properties.push("toString");
131       if (source.valueOf != Object.prototype.valueOf)
132         properties.push("valueOf");
133     }
134
135     for (var i = 0, length = properties.length; i < length; i++) {
136       var property = properties[i], value = source[property];
137       if (ancestor && Object.isFunction(value) &&
138           value.argumentNames()[0] == "$super") {
139         var method = value;
140         value = (function(m) {
141           return function() { return ancestor[m].apply(this, arguments); };
142         })(property).wrap(method);
143
144         value.valueOf = method.valueOf.bind(method);
145         value.toString = method.toString.bind(method);
146       }
147       this.prototype[property] = value;
148     }
149
150     return this;
151   }
152
153   return {
154     create: create,
155     Methods: {
156       addMethods: addMethods
157     }
158   };
159 })();
160 (function() {
161
162   var _toString = Object.prototype.toString,
163       NULL_TYPE = 'Null',
164       UNDEFINED_TYPE = 'Undefined',
165       BOOLEAN_TYPE = 'Boolean',
166       NUMBER_TYPE = 'Number',
167       STRING_TYPE = 'String',
168       OBJECT_TYPE = 'Object',
169       FUNCTION_CLASS = '[object Function]',
170       BOOLEAN_CLASS = '[object Boolean]',
171       NUMBER_CLASS = '[object Number]',
172       STRING_CLASS = '[object String]',
173       ARRAY_CLASS = '[object Array]',
174       DATE_CLASS = '[object Date]',
175       NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
176         typeof JSON.stringify === 'function' &&
177         JSON.stringify(0) === '0' &&
178         typeof JSON.stringify(Prototype.K) === 'undefined';
179
180   function Type(o) {
181     switch(o) {
182       case null: return NULL_TYPE;
183       case (void 0): return UNDEFINED_TYPE;
184     }
185     var type = typeof o;
186     switch(type) {
187       case 'boolean': return BOOLEAN_TYPE;
188       case 'number':  return NUMBER_TYPE;
189       case 'string':  return STRING_TYPE;
190     }
191     return OBJECT_TYPE;
192   }
193
194   function extend(destination, source) {
195     for (var property in source)
196       destination[property] = source[property];
197     return destination;
198   }
199
200   function inspect(object) {
201     try {
202       if (isUndefined(object)) return 'undefined';
203       if (object === null) return 'null';
204       return object.inspect ? object.inspect() : String(object);
205     } catch (e) {
206       if (e instanceof RangeError) return '...';
207       throw e;
208     }
209   }
210
211   function toJSON(value) {
212     return Str('', { '': value }, []);
213   }
214
215   function Str(key, holder, stack) {
216     var value = holder[key],
217         type = typeof value;
218
219     if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
220       value = value.toJSON(key);
221     }
222
223     var _class = _toString.call(value);
224
225     switch (_class) {
226       case NUMBER_CLASS:
227       case BOOLEAN_CLASS:
228       case STRING_CLASS:
229         value = value.valueOf();
230     }
231
232     switch (value) {
233       case null: return 'null';
234       case true: return 'true';
235       case false: return 'false';
236     }
237
238     type = typeof value;
239     switch (type) {
240       case 'string':
241         return value.inspect(true);
242       case 'number':
243         return isFinite(value) ? String(value) : 'null';
244       case 'object':
245
246         for (var i = 0, length = stack.length; i < length; i++) {
247           if (stack[i] === value) { throw new TypeError(); }
248         }
249         stack.push(value);
250
251         var partial = [];
252         if (_class === ARRAY_CLASS) {
253           for (var i = 0, length = value.length; i < length; i++) {
254             var str = Str(i, value, stack);
255             partial.push(typeof str === 'undefined' ? 'null' : str);
256           }
257           partial = '[' + partial.join(',') + ']';
258         } else {
259           var keys = Object.keys(value);
260           for (var i = 0, length = keys.length; i < length; i++) {
261             var key = keys[i], str = Str(key, value, stack);
262             if (typeof str !== "undefined") {
263                partial.push(key.inspect(true)+ ':' + str);
264              }
265           }
266           partial = '{' + partial.join(',') + '}';
267         }
268         stack.pop();
269         return partial;
270     }
271   }
272
273   function stringify(object) {
274     return JSON.stringify(object);
275   }
276
277   function toQueryString(object) {
278     return $H(object).toQueryString();
279   }
280
281   function toHTML(object) {
282     return object && object.toHTML ? object.toHTML() : String.interpret(object);
283   }
284
285   function keys(object) {
286     if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
287     var results = [];
288     for (var property in object) {
289       if (object.hasOwnProperty(property)) {
290         results.push(property);
291       }
292     }
293     return results;
294   }
295
296   function values(object) {
297     var results = [];
298     for (var property in object)
299       results.push(object[property]);
300     return results;
301   }
302
303   function clone(object) {
304     return extend({ }, object);
305   }
306
307   function isElement(object) {
308     return !!(object && object.nodeType == 1);
309   }
310
311   function isArray(object) {
312     return _toString.call(object) === ARRAY_CLASS;
313   }
314
315   var hasNativeIsArray = (typeof Array.isArray == 'function')
316     && Array.isArray([]) && !Array.isArray({});
317
318   if (hasNativeIsArray) {
319     isArray = Array.isArray;
320   }
321
322   function isHash(object) {
323     return object instanceof Hash;
324   }
325
326   function isFunction(object) {
327     return _toString.call(object) === FUNCTION_CLASS;
328   }
329
330   function isString(object) {
331     return _toString.call(object) === STRING_CLASS;
332   }
333
334   function isNumber(object) {
335     return _toString.call(object) === NUMBER_CLASS;
336   }
337
338   function isDate(object) {
339     return _toString.call(object) === DATE_CLASS;
340   }
341
342   function isUndefined(object) {
343     return typeof object === "undefined";
344   }
345
346   extend(Object, {
347     extend:        extend,
348     inspect:       inspect,
349     toJSON:        NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
350     toQueryString: toQueryString,
351     toHTML:        toHTML,
352     keys:          Object.keys || keys,
353     values:        values,
354     clone:         clone,
355     isElement:     isElement,
356     isArray:       isArray,
357     isHash:        isHash,
358     isFunction:    isFunction,
359     isString:      isString,
360     isNumber:      isNumber,
361     isDate:        isDate,
362     isUndefined:   isUndefined
363   });
364 })();
365 Object.extend(Function.prototype, (function() {
366   var slice = Array.prototype.slice;
367
368   function update(array, args) {
369     var arrayLength = array.length, length = args.length;
370     while (length--) array[arrayLength + length] = args[length];
371     return array;
372   }
373
374   function merge(array, args) {
375     array = slice.call(array, 0);
376     return update(array, args);
377   }
378
379   function argumentNames() {
380     var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
381       .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
382       .replace(/\s+/g, '').split(',');
383     return names.length == 1 && !names[0] ? [] : names;
384   }
385
386   function bind(context) {
387     if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
388     var __method = this, args = slice.call(arguments, 1);
389     return function() {
390       var a = merge(args, arguments);
391       return __method.apply(context, a);
392     }
393   }
394
395   function bindAsEventListener(context) {
396     var __method = this, args = slice.call(arguments, 1);
397     return function(event) {
398       var a = update([event || window.event], args);
399       return __method.apply(context, a);
400     }
401   }
402
403   function curry() {
404     if (!arguments.length) return this;
405     var __method = this, args = slice.call(arguments, 0);
406     return function() {
407       var a = merge(args, arguments);
408       return __method.apply(this, a);
409     }
410   }
411
412   function delay(timeout) {
413     var __method = this, args = slice.call(arguments, 1);
414     timeout = timeout * 1000;
415     return window.setTimeout(function() {
416       return __method.apply(__method, args);
417     }, timeout);
418   }
419
420   function defer() {
421     var args = update([0.01], arguments);
422     return this.delay.apply(this, args);
423   }
424
425   function wrap(wrapper) {
426     var __method = this;
427     return function() {
428       var a = update([__method.bind(this)], arguments);
429       return wrapper.apply(this, a);
430     }
431   }
432
433   function methodize() {
434     if (this._methodized) return this._methodized;
435     var __method = this;
436     return this._methodized = function() {
437       var a = update([this], arguments);
438       return __method.apply(null, a);
439     };
440   }
441
442   return {
443     argumentNames:       argumentNames,
444     bind:                bind,
445     bindAsEventListener: bindAsEventListener,
446     curry:               curry,
447     delay:               delay,
448     defer:               defer,
449     wrap:                wrap,
450     methodize:           methodize
451   }
452 })());
453
454
455
456 (function(proto) {
457
458
459   function toISOString() {
460     return this.getUTCFullYear() + '-' +
461       (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
462       this.getUTCDate().toPaddedString(2) + 'T' +
463       this.getUTCHours().toPaddedString(2) + ':' +
464       this.getUTCMinutes().toPaddedString(2) + ':' +
465       this.getUTCSeconds().toPaddedString(2) + 'Z';
466   }
467
468
469   function toJSON() {
470     return this.toISOString();
471   }
472
473   if (!proto.toISOString) proto.toISOString = toISOString;
474   if (!proto.toJSON) proto.toJSON = toJSON;
475
476 })(Date.prototype);
477
478
479 RegExp.prototype.match = RegExp.prototype.test;
480
481 RegExp.escape = function(str) {
482   return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
483 };
484 var PeriodicalExecuter = Class.create({
485   initialize: function(callback, frequency) {
486     this.callback = callback;
487     this.frequency = frequency;
488     this.currentlyExecuting = false;
489
490     this.registerCallback();
491   },
492
493   registerCallback: function() {
494     this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
495   },
496
497   execute: function() {
498     this.callback(this);
499   },
500
501   stop: function() {
502     if (!this.timer) return;
503     clearInterval(this.timer);
504     this.timer = null;
505   },
506
507   onTimerEvent: function() {
508     if (!this.currentlyExecuting) {
509       try {
510         this.currentlyExecuting = true;
511         this.execute();
512         this.currentlyExecuting = false;
513       } catch(e) {
514         this.currentlyExecuting = false;
515         throw e;
516       }
517     }
518   }
519 });
520 Object.extend(String, {
521   interpret: function(value) {
522     return value == null ? '' : String(value);
523   },
524   specialChar: {
525     '\b': '\\b',
526     '\t': '\\t',
527     '\n': '\\n',
528     '\f': '\\f',
529     '\r': '\\r',
530     '\\': '\\\\'
531   }
532 });
533
534 Object.extend(String.prototype, (function() {
535   var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
536     typeof JSON.parse === 'function' &&
537     JSON.parse('{"test": true}').test;
538
539   function prepareReplacement(replacement) {
540     if (Object.isFunction(replacement)) return replacement;
541     var template = new Template(replacement);
542     return function(match) { return template.evaluate(match) };
543   }
544
545   function gsub(pattern, replacement) {
546     var result = '', source = this, match;
547     replacement = prepareReplacement(replacement);
548
549     if (Object.isString(pattern))
550       pattern = RegExp.escape(pattern);
551
552     if (!(pattern.length || pattern.source)) {
553       replacement = replacement('');
554       return replacement + source.split('').join(replacement) + replacement;
555     }
556
557     while (source.length > 0) {
558       if (match = source.match(pattern)) {
559         result += source.slice(0, match.index);
560         result += String.interpret(replacement(match));
561         source  = source.slice(match.index + match[0].length);
562       } else {
563         result += source, source = '';
564       }
565     }
566     return result;
567   }
568
569   function sub(pattern, replacement, count) {
570     replacement = prepareReplacement(replacement);
571     count = Object.isUndefined(count) ? 1 : count;
572
573     return this.gsub(pattern, function(match) {
574       if (--count < 0) return match[0];
575       return replacement(match);
576     });
577   }
578
579   function scan(pattern, iterator) {
580     this.gsub(pattern, iterator);
581     return String(this);
582   }
583
584   function truncate(length, truncation) {
585     length = length || 30;
586     truncation = Object.isUndefined(truncation) ? '...' : truncation;
587     return this.length > length ?
588       this.slice(0, length - truncation.length) + truncation : String(this);
589   }
590
591   function strip() {
592     return this.replace(/^\s+/, '').replace(/\s+$/, '');
593   }
594
595   function stripTags() {
596     return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
597   }
598
599   function stripScripts() {
600     return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
601   }
602
603   function extractScripts() {
604     var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
605         matchOne = new RegExp(Prototype.ScriptFragment, 'im');
606     return (this.match(matchAll) || []).map(function(scriptTag) {
607       return (scriptTag.match(matchOne) || ['', ''])[1];
608     });
609   }
610
611   function evalScripts() {
612     return this.extractScripts().map(function(script) { return eval(script) });
613   }
614
615   function escapeHTML() {
616     return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
617   }
618
619   function unescapeHTML() {
620     return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
621   }
622
623
624   function toQueryParams(separator) {
625     var match = this.strip().match(/([^?#]*)(#.*)?$/);
626     if (!match) return { };
627
628     return match[1].split(separator || '&').inject({ }, function(hash, pair) {
629       if ((pair = pair.split('='))[0]) {
630         var key = decodeURIComponent(pair.shift()),
631             value = pair.length > 1 ? pair.join('=') : pair[0];
632
633         if (value != undefined) value = decodeURIComponent(value);
634
635         if (key in hash) {
636           if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
637           hash[key].push(value);
638         }
639         else hash[key] = value;
640       }
641       return hash;
642     });
643   }
644
645   function toArray() {
646     return this.split('');
647   }
648
649   function succ() {
650     return this.slice(0, this.length - 1) +
651       String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
652   }
653
654   function times(count) {
655     return count < 1 ? '' : new Array(count + 1).join(this);
656   }
657
658   function camelize() {
659     return this.replace(/-+(.)?/g, function(match, chr) {
660       return chr ? chr.toUpperCase() : '';
661     });
662   }
663
664   function capitalize() {
665     return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
666   }
667
668   function underscore() {
669     return this.replace(/::/g, '/')
670                .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
671                .replace(/([a-z\d])([A-Z])/g, '$1_$2')
672                .replace(/-/g, '_')
673                .toLowerCase();
674   }
675
676   function dasherize() {
677     return this.replace(/_/g, '-');
678   }
679
680   function inspect(useDoubleQuotes) {
681     var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
682       if (character in String.specialChar) {
683         return String.specialChar[character];
684       }
685       return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
686     });
687     if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
688     return "'" + escapedString.replace(/'/g, '\\\'') + "'";
689   }
690
691   function unfilterJSON(filter) {
692     return this.replace(filter || Prototype.JSONFilter, '$1');
693   }
694
695   function isJSON() {
696     var str = this;
697     if (str.blank()) return false;
698     str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
699     str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
700     str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
701     return (/^[\],:{}\s]*$/).test(str);
702   }
703
704   function evalJSON(sanitize) {
705     var json = this.unfilterJSON(),
706         cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
707     if (cx.test(json)) {
708       json = json.replace(cx, function (a) {
709         return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
710       });
711     }
712     try {
713       if (!sanitize || json.isJSON()) return eval('(' + json + ')');
714     } catch (e) { }
715     throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
716   }
717
718   function parseJSON() {
719     var json = this.unfilterJSON();
720     return JSON.parse(json);
721   }
722
723   function include(pattern) {
724     return this.indexOf(pattern) > -1;
725   }
726
727   function startsWith(pattern) {
728     return this.lastIndexOf(pattern, 0) === 0;
729   }
730
731   function endsWith(pattern) {
732     var d = this.length - pattern.length;
733     return d >= 0 && this.indexOf(pattern, d) === d;
734   }
735
736   function empty() {
737     return this == '';
738   }
739
740   function blank() {
741     return /^\s*$/.test(this);
742   }
743
744   function interpolate(object, pattern) {
745     return new Template(this, pattern).evaluate(object);
746   }
747
748   return {
749     gsub:           gsub,
750     sub:            sub,
751     scan:           scan,
752     truncate:       truncate,
753     strip:          String.prototype.trim || strip,
754     stripTags:      stripTags,
755     stripScripts:   stripScripts,
756     extractScripts: extractScripts,
757     evalScripts:    evalScripts,
758     escapeHTML:     escapeHTML,
759     unescapeHTML:   unescapeHTML,
760     toQueryParams:  toQueryParams,
761     parseQuery:     toQueryParams,
762     toArray:        toArray,
763     succ:           succ,
764     times:          times,
765     camelize:       camelize,
766     capitalize:     capitalize,
767     underscore:     underscore,
768     dasherize:      dasherize,
769     inspect:        inspect,
770     unfilterJSON:   unfilterJSON,
771     isJSON:         isJSON,
772     evalJSON:       NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
773     include:        include,
774     startsWith:     startsWith,
775     endsWith:       endsWith,
776     empty:          empty,
777     blank:          blank,
778     interpolate:    interpolate
779   };
780 })());
781
782 var Template = Class.create({
783   initialize: function(template, pattern) {
784     this.template = template.toString();
785     this.pattern = pattern || Template.Pattern;
786   },
787
788   evaluate: function(object) {
789     if (object && Object.isFunction(object.toTemplateReplacements))
790       object = object.toTemplateReplacements();
791
792     return this.template.gsub(this.pattern, function(match) {
793       if (object == null) return (match[1] + '');
794
795       var before = match[1] || '';
796       if (before == '\\') return match[2];
797
798       var ctx = object, expr = match[3],
799           pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
800
801       match = pattern.exec(expr);
802       if (match == null) return before;
803
804       while (match != null) {
805         var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
806         ctx = ctx[comp];
807         if (null == ctx || '' == match[3]) break;
808         expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
809         match = pattern.exec(expr);
810       }
811
812       return before + String.interpret(ctx);
813     });
814   }
815 });
816 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
817
818 var $break = { };
819
820 var Enumerable = (function() {
821   function each(iterator, context) {
822     var index = 0;
823     try {
824       this._each(function(value) {
825         iterator.call(context, value, index++);
826       });
827     } catch (e) {
828       if (e != $break) throw e;
829     }
830     return this;
831   }
832
833   function eachSlice(number, iterator, context) {
834     var index = -number, slices = [], array = this.toArray();
835     if (number < 1) return array;
836     while ((index += number) < array.length)
837       slices.push(array.slice(index, index+number));
838     return slices.collect(iterator, context);
839   }
840
841   function all(iterator, context) {
842     iterator = iterator || Prototype.K;
843     var result = true;
844     this.each(function(value, index) {
845       result = result && !!iterator.call(context, value, index);
846       if (!result) throw $break;
847     });
848     return result;
849   }
850
851   function any(iterator, context) {
852     iterator = iterator || Prototype.K;
853     var result = false;
854     this.each(function(value, index) {
855       if (result = !!iterator.call(context, value, index))
856         throw $break;
857     });
858     return result;
859   }
860
861   function collect(iterator, context) {
862     iterator = iterator || Prototype.K;
863     var results = [];
864     this.each(function(value, index) {
865       results.push(iterator.call(context, value, index));
866     });
867     return results;
868   }
869
870   function detect(iterator, context) {
871     var result;
872     this.each(function(value, index) {
873       if (iterator.call(context, value, index)) {
874         result = value;
875         throw $break;
876       }
877     });
878     return result;
879   }
880
881   function findAll(iterator, context) {
882     var results = [];
883     this.each(function(value, index) {
884       if (iterator.call(context, value, index))
885         results.push(value);
886     });
887     return results;
888   }
889
890   function grep(filter, iterator, context) {
891     iterator = iterator || Prototype.K;
892     var results = [];
893
894     if (Object.isString(filter))
895       filter = new RegExp(RegExp.escape(filter));
896
897     this.each(function(value, index) {
898       if (filter.match(value))
899         results.push(iterator.call(context, value, index));
900     });
901     return results;
902   }
903
904   function include(object) {
905     if (Object.isFunction(this.indexOf))
906       if (this.indexOf(object) != -1) return true;
907
908     var found = false;
909     this.each(function(value) {
910       if (value == object) {
911         found = true;
912         throw $break;
913       }
914     });
915     return found;
916   }
917
918   function inGroupsOf(number, fillWith) {
919     fillWith = Object.isUndefined(fillWith) ? null : fillWith;
920     return this.eachSlice(number, function(slice) {
921       while(slice.length < number) slice.push(fillWith);
922       return slice;
923     });
924   }
925
926   function inject(memo, iterator, context) {
927     this.each(function(value, index) {
928       memo = iterator.call(context, memo, value, index);
929     });
930     return memo;
931   }
932
933   function invoke(method) {
934     var args = $A(arguments).slice(1);
935     return this.map(function(value) {
936       return value[method].apply(value, args);
937     });
938   }
939
940   function max(iterator, context) {
941     iterator = iterator || Prototype.K;
942     var result;
943     this.each(function(value, index) {
944       value = iterator.call(context, value, index);
945       if (result == null || value >= result)
946         result = value;
947     });
948     return result;
949   }
950
951   function min(iterator, context) {
952     iterator = iterator || Prototype.K;
953     var result;
954     this.each(function(value, index) {
955       value = iterator.call(context, value, index);
956       if (result == null || value < result)
957         result = value;
958     });
959     return result;
960   }
961
962   function partition(iterator, context) {
963     iterator = iterator || Prototype.K;
964     var trues = [], falses = [];
965     this.each(function(value, index) {
966       (iterator.call(context, value, index) ?
967         trues : falses).push(value);
968     });
969     return [trues, falses];
970   }
971
972   function pluck(property) {
973     var results = [];
974     this.each(function(value) {
975       results.push(value[property]);
976     });
977     return results;
978   }
979
980   function reject(iterator, context) {
981     var results = [];
982     this.each(function(value, index) {
983       if (!iterator.call(context, value, index))
984         results.push(value);
985     });
986     return results;
987   }
988
989   function sortBy(iterator, context) {
990     return this.map(function(value, index) {
991       return {
992         value: value,
993         criteria: iterator.call(context, value, index)
994       };
995     }).sort(function(left, right) {
996       var a = left.criteria, b = right.criteria;
997       return a < b ? -1 : a > b ? 1 : 0;
998     }).pluck('value');
999   }
1000
1001   function toArray() {
1002     return this.map();
1003   }
1004
1005   function zip() {
1006     var iterator = Prototype.K, args = $A(arguments);
1007     if (Object.isFunction(args.last()))
1008       iterator = args.pop();
1009
1010     var collections = [this].concat(args).map($A);
1011     return this.map(function(value, index) {
1012       return iterator(collections.pluck(index));
1013     });
1014   }
1015
1016   function size() {
1017     return this.toArray().length;
1018   }
1019
1020   function inspect() {
1021     return '#<Enumerable:' + this.toArray().inspect() + '>';
1022   }
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032   return {
1033     each:       each,
1034     eachSlice:  eachSlice,
1035     all:        all,
1036     every:      all,
1037     any:        any,
1038     some:       any,
1039     collect:    collect,
1040     map:        collect,
1041     detect:     detect,
1042     findAll:    findAll,
1043     select:     findAll,
1044     filter:     findAll,
1045     grep:       grep,
1046     include:    include,
1047     member:     include,
1048     inGroupsOf: inGroupsOf,
1049     inject:     inject,
1050     invoke:     invoke,
1051     max:        max,
1052     min:        min,
1053     partition:  partition,
1054     pluck:      pluck,
1055     reject:     reject,
1056     sortBy:     sortBy,
1057     toArray:    toArray,
1058     entries:    toArray,
1059     zip:        zip,
1060     size:       size,
1061     inspect:    inspect,
1062     find:       detect
1063   };
1064 })();
1065
1066 function $A(iterable) {
1067   if (!iterable) return [];
1068   if ('toArray' in Object(iterable)) return iterable.toArray();
1069   var length = iterable.length || 0, results = new Array(length);
1070   while (length--) results[length] = iterable[length];
1071   return results;
1072 }
1073
1074
1075 function $w(string) {
1076   if (!Object.isString(string)) return [];
1077   string = string.strip();
1078   return string ? string.split(/\s+/) : [];
1079 }
1080
1081 Array.from = $A;
1082
1083
1084 (function() {
1085   var arrayProto = Array.prototype,
1086       slice = arrayProto.slice,
1087       _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
1088
1089   function each(iterator, context) {
1090     for (var i = 0, length = this.length >>> 0; i < length; i++) {
1091       if (i in this) iterator.call(context, this[i], i, this);
1092     }
1093   }
1094   if (!_each) _each = each;
1095
1096   function clear() {
1097     this.length = 0;
1098     return this;
1099   }
1100
1101   function first() {
1102     return this[0];
1103   }
1104
1105   function last() {
1106     return this[this.length - 1];
1107   }
1108
1109   function compact() {
1110     return this.select(function(value) {
1111       return value != null;
1112     });
1113   }
1114
1115   function flatten() {
1116     return this.inject([], function(array, value) {
1117       if (Object.isArray(value))
1118         return array.concat(value.flatten());
1119       array.push(value);
1120       return array;
1121     });
1122   }
1123
1124   function without() {
1125     var values = slice.call(arguments, 0);
1126     return this.select(function(value) {
1127       return !values.include(value);
1128     });
1129   }
1130
1131   function reverse(inline) {
1132     return (inline === false ? this.toArray() : this)._reverse();
1133   }
1134
1135   function uniq(sorted) {
1136     return this.inject([], function(array, value, index) {
1137       if (0 == index || (sorted ? array.last() != value : !array.include(value)))
1138         array.push(value);
1139       return array;
1140     });
1141   }
1142
1143   function intersect(array) {
1144     return this.uniq().findAll(function(item) {
1145       return array.detect(function(value) { return item === value });
1146     });
1147   }
1148
1149
1150   function clone() {
1151     return slice.call(this, 0);
1152   }
1153
1154   function size() {
1155     return this.length;
1156   }
1157
1158   function inspect() {
1159     return '[' + this.map(Object.inspect).join(', ') + ']';
1160   }
1161
1162   function indexOf(item, i) {
1163     i || (i = 0);
1164     var length = this.length;
1165     if (i < 0) i = length + i;
1166     for (; i < length; i++)
1167       if (this[i] === item) return i;
1168     return -1;
1169   }
1170
1171   function lastIndexOf(item, i) {
1172     i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
1173     var n = this.slice(0, i).reverse().indexOf(item);
1174     return (n < 0) ? n : i - n - 1;
1175   }
1176
1177   function concat() {
1178     var array = slice.call(this, 0), item;
1179     for (var i = 0, length = arguments.length; i < length; i++) {
1180       item = arguments[i];
1181       if (Object.isArray(item) && !('callee' in item)) {
1182         for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
1183           array.push(item[j]);
1184       } else {
1185         array.push(item);
1186       }
1187     }
1188     return array;
1189   }
1190
1191   Object.extend(arrayProto, Enumerable);
1192
1193   if (!arrayProto._reverse)
1194     arrayProto._reverse = arrayProto.reverse;
1195
1196   Object.extend(arrayProto, {
1197     _each:     _each,
1198     clear:     clear,
1199     first:     first,
1200     last:      last,
1201     compact:   compact,
1202     flatten:   flatten,
1203     without:   without,
1204     reverse:   reverse,
1205     uniq:      uniq,
1206     intersect: intersect,
1207     clone:     clone,
1208     toArray:   clone,
1209     size:      size,
1210     inspect:   inspect
1211   });
1212
1213   var CONCAT_ARGUMENTS_BUGGY = (function() {
1214     return [].concat(arguments)[0][0] !== 1;
1215   })(1,2)
1216
1217   if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
1218
1219   if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
1220   if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
1221 })();
1222 function $H(object) {
1223   return new Hash(object);
1224 };
1225
1226 var Hash = Class.create(Enumerable, (function() {
1227   function initialize(object) {
1228     this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1229   }
1230
1231
1232   function _each(iterator) {
1233     for (var key in this._object) {
1234       var value = this._object[key], pair = [key, value];
1235       pair.key = key;
1236       pair.value = value;
1237       iterator(pair);
1238     }
1239   }
1240
1241   function set(key, value) {
1242     return this._object[key] = value;
1243   }
1244
1245   function get(key) {
1246     if (this._object[key] !== Object.prototype[key])
1247       return this._object[key];
1248   }
1249
1250   function unset(key) {
1251     var value = this._object[key];
1252     delete this._object[key];
1253     return value;
1254   }
1255
1256   function toObject() {
1257     return Object.clone(this._object);
1258   }
1259
1260
1261
1262   function keys() {
1263     return this.pluck('key');
1264   }
1265
1266   function values() {
1267     return this.pluck('value');
1268   }
1269
1270   function index(value) {
1271     var match = this.detect(function(pair) {
1272       return pair.value === value;
1273     });
1274     return match && match.key;
1275   }
1276
1277   function merge(object) {
1278     return this.clone().update(object);
1279   }
1280
1281   function update(object) {
1282     return new Hash(object).inject(this, function(result, pair) {
1283       result.set(pair.key, pair.value);
1284       return result;
1285     });
1286   }
1287
1288   function toQueryPair(key, value) {
1289     if (Object.isUndefined(value)) return key;
1290     return key + '=' + encodeURIComponent(String.interpret(value));
1291   }
1292
1293   function toQueryString() {
1294     return this.inject([], function(results, pair) {
1295       var key = encodeURIComponent(pair.key), values = pair.value;
1296
1297       if (values && typeof values == 'object') {
1298         if (Object.isArray(values)) {
1299           var queryValues = [];
1300           for (var i = 0, len = values.length, value; i < len; i++) {
1301             value = values[i];
1302             queryValues.push(toQueryPair(key, value));
1303           }
1304           return results.concat(queryValues);
1305         }
1306       } else results.push(toQueryPair(key, values));
1307       return results;
1308     }).join('&');
1309   }
1310
1311   function inspect() {
1312     return '#<Hash:{' + this.map(function(pair) {
1313       return pair.map(Object.inspect).join(': ');
1314     }).join(', ') + '}>';
1315   }
1316
1317   function clone() {
1318     return new Hash(this);
1319   }
1320
1321   return {
1322     initialize:             initialize,
1323     _each:                  _each,
1324     set:                    set,
1325     get:                    get,
1326     unset:                  unset,
1327     toObject:               toObject,
1328     toTemplateReplacements: toObject,
1329     keys:                   keys,
1330     values:                 values,
1331     index:                  index,
1332     merge:                  merge,
1333     update:                 update,
1334     toQueryString:          toQueryString,
1335     inspect:                inspect,
1336     toJSON:                 toObject,
1337     clone:                  clone
1338   };
1339 })());
1340
1341 Hash.from = $H;
1342 Object.extend(Number.prototype, (function() {
1343   function toColorPart() {
1344     return this.toPaddedString(2, 16);
1345   }
1346
1347   function succ() {
1348     return this + 1;
1349   }
1350
1351   function times(iterator, context) {
1352     $R(0, this, true).each(iterator, context);
1353     return this;
1354   }
1355
1356   function toPaddedString(length, radix) {
1357     var string = this.toString(radix || 10);
1358     return '0'.times(length - string.length) + string;
1359   }
1360
1361   function abs() {
1362     return Math.abs(this);
1363   }
1364
1365   function round() {
1366     return Math.round(this);
1367   }
1368
1369   function ceil() {
1370     return Math.ceil(this);
1371   }
1372
1373   function floor() {
1374     return Math.floor(this);
1375   }
1376
1377   return {
1378     toColorPart:    toColorPart,
1379     succ:           succ,
1380     times:          times,
1381     toPaddedString: toPaddedString,
1382     abs:            abs,
1383     round:          round,
1384     ceil:           ceil,
1385     floor:          floor
1386   };
1387 })());
1388
1389 function $R(start, end, exclusive) {
1390   return new ObjectRange(start, end, exclusive);
1391 }
1392
1393 var ObjectRange = Class.create(Enumerable, (function() {
1394   function initialize(start, end, exclusive) {
1395     this.start = start;
1396     this.end = end;
1397     this.exclusive = exclusive;
1398   }
1399
1400   function _each(iterator) {
1401     var value = this.start;
1402     while (this.include(value)) {
1403       iterator(value);
1404       value = value.succ();
1405     }
1406   }
1407
1408   function include(value) {
1409     if (value < this.start)
1410       return false;
1411     if (this.exclusive)
1412       return value < this.end;
1413     return value <= this.end;
1414   }
1415
1416   return {
1417     initialize: initialize,
1418     _each:      _each,
1419     include:    include
1420   };
1421 })());
1422
1423
1424
1425 var Ajax = {
1426   getTransport: function() {
1427     return Try.these(
1428       function() {return new XMLHttpRequest()},
1429       function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1430       function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1431     ) || false;
1432   },
1433
1434   activeRequestCount: 0
1435 };
1436
1437 Ajax.Responders = {
1438   responders: [],
1439
1440   _each: function(iterator) {
1441     this.responders._each(iterator);
1442   },
1443
1444   register: function(responder) {
1445     if (!this.include(responder))
1446       this.responders.push(responder);
1447   },
1448
1449   unregister: function(responder) {
1450     this.responders = this.responders.without(responder);
1451   },
1452
1453   dispatch: function(callback, request, transport, json) {
1454     this.each(function(responder) {
1455       if (Object.isFunction(responder[callback])) {
1456         try {
1457           responder[callback].apply(responder, [request, transport, json]);
1458         } catch (e) { }
1459       }
1460     });
1461   }
1462 };
1463
1464 Object.extend(Ajax.Responders, Enumerable);
1465
1466 Ajax.Responders.register({
1467   onCreate:   function() { Ajax.activeRequestCount++ },
1468   onComplete: function() { Ajax.activeRequestCount-- }
1469 });
1470 Ajax.Base = Class.create({
1471   initialize: function(options) {
1472     this.options = {
1473       method:       'post',
1474       asynchronous: true,
1475       contentType:  'application/x-www-form-urlencoded',
1476       encoding:     'UTF-8',
1477       parameters:   '',
1478       evalJSON:     true,
1479       evalJS:       true
1480     };
1481     Object.extend(this.options, options || { });
1482
1483     this.options.method = this.options.method.toLowerCase();
1484
1485     if (Object.isHash(this.options.parameters))
1486       this.options.parameters = this.options.parameters.toObject();
1487   }
1488 });
1489 Ajax.Request = Class.create(Ajax.Base, {
1490   _complete: false,
1491
1492   initialize: function($super, url, options) {
1493     $super(options);
1494     this.transport = Ajax.getTransport();
1495     this.request(url);
1496   },
1497
1498   request: function(url) {
1499     this.url = url;
1500     this.method = this.options.method;
1501     var params = Object.isString(this.options.parameters) ?
1502           this.options.parameters :
1503           Object.toQueryString(this.options.parameters);
1504
1505     if (!['get', 'post'].include(this.method)) {
1506       params += (params ? '&' : '') + "_method=" + this.method;
1507       this.method = 'post';
1508     }
1509
1510     if (params && this.method === 'get') {
1511       this.url += (this.url.include('?') ? '&' : '?') + params;
1512     }
1513
1514     this.parameters = params.toQueryParams();
1515
1516     try {
1517       var response = new Ajax.Response(this);
1518       if (this.options.onCreate) this.options.onCreate(response);
1519       Ajax.Responders.dispatch('onCreate', this, response);
1520
1521       this.transport.open(this.method.toUpperCase(), this.url,
1522         this.options.asynchronous);
1523
1524       if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1525
1526       this.transport.onreadystatechange = this.onStateChange.bind(this);
1527       this.setRequestHeaders();
1528
1529       this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1530       this.transport.send(this.body);
1531
1532       /* Force Firefox to handle ready state 4 for synchronous requests */
1533       if (!this.options.asynchronous && this.transport.overrideMimeType)
1534         this.onStateChange();
1535
1536     }
1537     catch (e) {
1538       this.dispatchException(e);
1539     }
1540   },
1541
1542   onStateChange: function() {
1543     var readyState = this.transport.readyState;
1544     if (readyState > 1 && !((readyState == 4) && this._complete))
1545       this.respondToReadyState(this.transport.readyState);
1546   },
1547
1548   setRequestHeaders: function() {
1549     var headers = {
1550       'X-Requested-With': 'XMLHttpRequest',
1551       'X-Prototype-Version': Prototype.Version,
1552       'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1553     };
1554
1555     if (this.method == 'post') {
1556       headers['Content-type'] = this.options.contentType +
1557         (this.options.encoding ? '; charset=' + this.options.encoding : '');
1558
1559       /* Force "Connection: close" for older Mozilla browsers to work
1560        * around a bug where XMLHttpRequest sends an incorrect
1561        * Content-length header. See Mozilla Bugzilla #246651.
1562        */
1563       if (this.transport.overrideMimeType &&
1564           (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1565             headers['Connection'] = 'close';
1566     }
1567
1568     if (typeof this.options.requestHeaders == 'object') {
1569       var extras = this.options.requestHeaders;
1570
1571       if (Object.isFunction(extras.push))
1572         for (var i = 0, length = extras.length; i < length; i += 2)
1573           headers[extras[i]] = extras[i+1];
1574       else
1575         $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1576     }
1577
1578     for (var name in headers)
1579       this.transport.setRequestHeader(name, headers[name]);
1580   },
1581
1582   success: function() {
1583     var status = this.getStatus();
1584     return !status || (status >= 200 && status < 300) || status == 304;
1585   },
1586
1587   getStatus: function() {
1588     try {
1589       if (this.transport.status === 1223) return 204;
1590       return this.transport.status || 0;
1591     } catch (e) { return 0 }
1592   },
1593
1594   respondToReadyState: function(readyState) {
1595     var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
1596
1597     if (state == 'Complete') {
1598       try {
1599         this._complete = true;
1600         (this.options['on' + response.status]
1601          || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1602          || Prototype.emptyFunction)(response, response.headerJSON);
1603       } catch (e) {
1604         this.dispatchException(e);
1605       }
1606
1607       var contentType = response.getHeader('Content-type');
1608       if (this.options.evalJS == 'force'
1609           || (this.options.evalJS && this.isSameOrigin() && contentType
1610           && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1611         this.evalResponse();
1612     }
1613
1614     try {
1615       (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1616       Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
1617     } catch (e) {
1618       this.dispatchException(e);
1619     }
1620
1621     if (state == 'Complete') {
1622       this.transport.onreadystatechange = Prototype.emptyFunction;
1623     }
1624   },
1625
1626   isSameOrigin: function() {
1627     var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1628     return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1629       protocol: location.protocol,
1630       domain: document.domain,
1631       port: location.port ? ':' + location.port : ''
1632     }));
1633   },
1634
1635   getHeader: function(name) {
1636     try {
1637       return this.transport.getResponseHeader(name) || null;
1638     } catch (e) { return null; }
1639   },
1640
1641   evalResponse: function() {
1642     try {
1643       return eval((this.transport.responseText || '').unfilterJSON());
1644     } catch (e) {
1645       this.dispatchException(e);
1646     }
1647   },
1648
1649   dispatchException: function(exception) {
1650     (this.options.onException || Prototype.emptyFunction)(this, exception);
1651     Ajax.Responders.dispatch('onException', this, exception);
1652   }
1653 });
1654
1655 Ajax.Request.Events =
1656   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1657
1658
1659
1660
1661
1662
1663
1664
1665 Ajax.Response = Class.create({
1666   initialize: function(request){
1667     this.request = request;
1668     var transport  = this.transport  = request.transport,
1669         readyState = this.readyState = transport.readyState;
1670
1671     if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1672       this.status       = this.getStatus();
1673       this.statusText   = this.getStatusText();
1674       this.responseText = String.interpret(transport.responseText);
1675       this.headerJSON   = this._getHeaderJSON();
1676     }
1677
1678     if (readyState == 4) {
1679       var xml = transport.responseXML;
1680       this.responseXML  = Object.isUndefined(xml) ? null : xml;
1681       this.responseJSON = this._getResponseJSON();
1682     }
1683   },
1684
1685   status:      0,
1686
1687   statusText: '',
1688
1689   getStatus: Ajax.Request.prototype.getStatus,
1690
1691   getStatusText: function() {
1692     try {
1693       return this.transport.statusText || '';
1694     } catch (e) { return '' }
1695   },
1696
1697   getHeader: Ajax.Request.prototype.getHeader,
1698
1699   getAllHeaders: function() {
1700     try {
1701       return this.getAllResponseHeaders();
1702     } catch (e) { return null }
1703   },
1704
1705   getResponseHeader: function(name) {
1706     return this.transport.getResponseHeader(name);
1707   },
1708
1709   getAllResponseHeaders: function() {
1710     return this.transport.getAllResponseHeaders();
1711   },
1712
1713   _getHeaderJSON: function() {
1714     var json = this.getHeader('X-JSON');
1715     if (!json) return null;
1716     json = decodeURIComponent(escape(json));
1717     try {
1718       return json.evalJSON(this.request.options.sanitizeJSON ||
1719         !this.request.isSameOrigin());
1720     } catch (e) {
1721       this.request.dispatchException(e);
1722     }
1723   },
1724
1725   _getResponseJSON: function() {
1726     var options = this.request.options;
1727     if (!options.evalJSON || (options.evalJSON != 'force' &&
1728       !(this.getHeader('Content-type') || '').include('application/json')) ||
1729         this.responseText.blank())
1730           return null;
1731     try {
1732       return this.responseText.evalJSON(options.sanitizeJSON ||
1733         !this.request.isSameOrigin());
1734     } catch (e) {
1735       this.request.dispatchException(e);
1736     }
1737   }
1738 });
1739
1740 Ajax.Updater = Class.create(Ajax.Request, {
1741   initialize: function($super, container, url, options) {
1742     this.container = {
1743       success: (container.success || container),
1744       failure: (container.failure || (container.success ? null : container))
1745     };
1746
1747     options = Object.clone(options);
1748     var onComplete = options.onComplete;
1749     options.onComplete = (function(response, json) {
1750       this.updateContent(response.responseText);
1751       if (Object.isFunction(onComplete)) onComplete(response, json);
1752     }).bind(this);
1753
1754     $super(url, options);
1755   },
1756
1757   updateContent: function(responseText) {
1758     var receiver = this.container[this.success() ? 'success' : 'failure'],
1759         options = this.options;
1760
1761     if (!options.evalScripts) responseText = responseText.stripScripts();
1762
1763     if (receiver = $(receiver)) {
1764       if (options.insertion) {
1765         if (Object.isString(options.insertion)) {
1766           var insertion = { }; insertion[options.insertion] = responseText;
1767           receiver.insert(insertion);
1768         }
1769         else options.insertion(receiver, responseText);
1770       }
1771       else receiver.update(responseText);
1772     }
1773   }
1774 });
1775
1776 Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1777   initialize: function($super, container, url, options) {
1778     $super(options);
1779     this.onComplete = this.options.onComplete;
1780
1781     this.frequency = (this.options.frequency || 2);
1782     this.decay = (this.options.decay || 1);
1783
1784     this.updater = { };
1785     this.container = container;
1786     this.url = url;
1787
1788     this.start();
1789   },
1790
1791   start: function() {
1792     this.options.onComplete = this.updateComplete.bind(this);
1793     this.onTimerEvent();
1794   },
1795
1796   stop: function() {
1797     this.updater.options.onComplete = undefined;
1798     clearTimeout(this.timer);
1799     (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1800   },
1801
1802   updateComplete: function(response) {
1803     if (this.options.decay) {
1804       this.decay = (response.responseText == this.lastText ?
1805         this.decay * this.options.decay : 1);
1806
1807       this.lastText = response.responseText;
1808     }
1809     this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
1810   },
1811
1812   onTimerEvent: function() {
1813     this.updater = new Ajax.Updater(this.container, this.url, this.options);
1814   }
1815 });
1816
1817
1818 function $(element) {
1819   if (arguments.length > 1) {
1820     for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1821       elements.push($(arguments[i]));
1822     return elements;
1823   }
1824   if (Object.isString(element))
1825     element = document.getElementById(element);
1826   return Element.extend(element);
1827 }
1828
1829 if (Prototype.BrowserFeatures.XPath) {
1830   document._getElementsByXPath = function(expression, parentElement) {
1831     var results = [];
1832     var query = document.evaluate(expression, $(parentElement) || document,
1833       null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1834     for (var i = 0, length = query.snapshotLength; i < length; i++)
1835       results.push(Element.extend(query.snapshotItem(i)));
1836     return results;
1837   };
1838 }
1839
1840 /*--------------------------------------------------------------------------*/
1841
1842 if (!Node) var Node = { };
1843
1844 if (!Node.ELEMENT_NODE) {
1845   Object.extend(Node, {
1846     ELEMENT_NODE: 1,
1847     ATTRIBUTE_NODE: 2,
1848     TEXT_NODE: 3,
1849     CDATA_SECTION_NODE: 4,
1850     ENTITY_REFERENCE_NODE: 5,
1851     ENTITY_NODE: 6,
1852     PROCESSING_INSTRUCTION_NODE: 7,
1853     COMMENT_NODE: 8,
1854     DOCUMENT_NODE: 9,
1855     DOCUMENT_TYPE_NODE: 10,
1856     DOCUMENT_FRAGMENT_NODE: 11,
1857     NOTATION_NODE: 12
1858   });
1859 }
1860
1861
1862
1863 (function(global) {
1864   function shouldUseCache(tagName, attributes) {
1865     if (tagName === 'select') return false;
1866     if ('type' in attributes) return false;
1867     return true;
1868   }
1869
1870   var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
1871     try {
1872       var el = document.createElement('<input name="x">');
1873       return el.tagName.toLowerCase() === 'input' && el.name === 'x';
1874     }
1875     catch(err) {
1876       return false;
1877     }
1878   })();
1879
1880   var element = global.Element;
1881
1882   global.Element = function(tagName, attributes) {
1883     attributes = attributes || { };
1884     tagName = tagName.toLowerCase();
1885     var cache = Element.cache;
1886
1887     if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
1888       tagName = '<' + tagName + ' name="' + attributes.name + '">';
1889       delete attributes.name;
1890       return Element.writeAttribute(document.createElement(tagName), attributes);
1891     }
1892
1893     if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
1894
1895     var node = shouldUseCache(tagName, attributes) ?
1896      cache[tagName].cloneNode(false) : document.createElement(tagName);
1897
1898     return Element.writeAttribute(node, attributes);
1899   };
1900
1901   Object.extend(global.Element, element || { });
1902   if (element) global.Element.prototype = element.prototype;
1903
1904 })(this);
1905
1906 Element.idCounter = 1;
1907 Element.cache = { };
1908
1909 Element._purgeElement = function(element) {
1910   var uid = element._prototypeUID;
1911   if (uid) {
1912     Element.stopObserving(element);
1913     element._prototypeUID = void 0;
1914     delete Element.Storage[uid];
1915   }
1916 }
1917
1918 Element.Methods = {
1919   visible: function(element) {
1920     return $(element).style.display != 'none';
1921   },
1922
1923   toggle: function(element) {
1924     element = $(element);
1925     Element[Element.visible(element) ? 'hide' : 'show'](element);
1926     return element;
1927   },
1928
1929   hide: function(element) {
1930     element = $(element);
1931     element.style.display = 'none';
1932     return element;
1933   },
1934
1935   show: function(element) {
1936     element = $(element);
1937     element.style.display = '';
1938     return element;
1939   },
1940
1941   remove: function(element) {
1942     element = $(element);
1943     element.parentNode.removeChild(element);
1944     return element;
1945   },
1946
1947   update: (function(){
1948
1949     var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
1950       var el = document.createElement("select"),
1951           isBuggy = true;
1952       el.innerHTML = "<option value=\"test\">test</option>";
1953       if (el.options && el.options[0]) {
1954         isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
1955       }
1956       el = null;
1957       return isBuggy;
1958     })();
1959
1960     var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
1961       try {
1962         var el = document.createElement("table");
1963         if (el && el.tBodies) {
1964           el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
1965           var isBuggy = typeof el.tBodies[0] == "undefined";
1966           el = null;
1967           return isBuggy;
1968         }
1969       } catch (e) {
1970         return true;
1971       }
1972     })();
1973
1974     var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
1975       try {
1976         var el = document.createElement('div');
1977         el.innerHTML = "<link>";
1978         var isBuggy = (el.childNodes.length === 0);
1979         el = null;
1980         return isBuggy;
1981       } catch(e) {
1982         return true;
1983       }
1984     })();
1985
1986     var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
1987      TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
1988
1989     var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
1990       var s = document.createElement("script"),
1991           isBuggy = false;
1992       try {
1993         s.appendChild(document.createTextNode(""));
1994         isBuggy = !s.firstChild ||
1995           s.firstChild && s.firstChild.nodeType !== 3;
1996       } catch (e) {
1997         isBuggy = true;
1998       }
1999       s = null;
2000       return isBuggy;
2001     })();
2002
2003
2004     function update(element, content) {
2005       element = $(element);
2006       var purgeElement = Element._purgeElement;
2007
2008       var descendants = element.getElementsByTagName('*'),
2009        i = descendants.length;
2010       while (i--) purgeElement(descendants[i]);
2011
2012       if (content && content.toElement)
2013         content = content.toElement();
2014
2015       if (Object.isElement(content))
2016         return element.update().insert(content);
2017
2018       content = Object.toHTML(content);
2019
2020       var tagName = element.tagName.toUpperCase();
2021
2022       if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
2023         element.text = content;
2024         return element;
2025       }
2026
2027       if (ANY_INNERHTML_BUGGY) {
2028         if (tagName in Element._insertionTranslations.tags) {
2029           while (element.firstChild) {
2030             element.removeChild(element.firstChild);
2031           }
2032           Element._getContentFromAnonymousElement(tagName, content.stripScripts())
2033             .each(function(node) {
2034               element.appendChild(node)
2035             });
2036         } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
2037           while (element.firstChild) {
2038             element.removeChild(element.firstChild);
2039           }
2040           var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true);
2041           nodes.each(function(node) { element.appendChild(node) });
2042         }
2043         else {
2044           element.innerHTML = content.stripScripts();
2045         }
2046       }
2047       else {
2048         element.innerHTML = content.stripScripts();
2049       }
2050
2051       content.evalScripts.bind(content).defer();
2052       return element;
2053     }
2054
2055     return update;
2056   })(),
2057
2058   replace: function(element, content) {
2059     element = $(element);
2060     if (content && content.toElement) content = content.toElement();
2061     else if (!Object.isElement(content)) {
2062       content = Object.toHTML(content);
2063       var range = element.ownerDocument.createRange();
2064       range.selectNode(element);
2065       content.evalScripts.bind(content).defer();
2066       content = range.createContextualFragment(content.stripScripts());
2067     }
2068     element.parentNode.replaceChild(content, element);
2069     return element;
2070   },
2071
2072   insert: function(element, insertions) {
2073     element = $(element);
2074
2075     if (Object.isString(insertions) || Object.isNumber(insertions) ||
2076         Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
2077           insertions = {bottom:insertions};
2078
2079     var content, insert, tagName, childNodes;
2080
2081     for (var position in insertions) {
2082       content  = insertions[position];
2083       position = position.toLowerCase();
2084       insert = Element._insertionTranslations[position];
2085
2086       if (content && content.toElement) content = content.toElement();
2087       if (Object.isElement(content)) {
2088         insert(element, content);
2089         continue;
2090       }
2091
2092       content = Object.toHTML(content);
2093
2094       tagName = ((position == 'before' || position == 'after')
2095         ? element.parentNode : element).tagName.toUpperCase();
2096
2097       childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2098
2099       if (position == 'top' || position == 'after') childNodes.reverse();
2100       childNodes.each(insert.curry(element));
2101
2102       content.evalScripts.bind(content).defer();
2103     }
2104
2105     return element;
2106   },
2107
2108   wrap: function(element, wrapper, attributes) {
2109     element = $(element);
2110     if (Object.isElement(wrapper))
2111       $(wrapper).writeAttribute(attributes || { });
2112     else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
2113     else wrapper = new Element('div', wrapper);
2114     if (element.parentNode)
2115       element.parentNode.replaceChild(wrapper, element);
2116     wrapper.appendChild(element);
2117     return wrapper;
2118   },
2119
2120   inspect: function(element) {
2121     element = $(element);
2122     var result = '<' + element.tagName.toLowerCase();
2123     $H({'id': 'id', 'className': 'class'}).each(function(pair) {
2124       var property = pair.first(),
2125           attribute = pair.last(),
2126           value = (element[property] || '').toString();
2127       if (value) result += ' ' + attribute + '=' + value.inspect(true);
2128     });
2129     return result + '>';
2130   },
2131
2132   recursivelyCollect: function(element, property, maximumLength) {
2133     element = $(element);
2134     maximumLength = maximumLength || -1;
2135     var elements = [];
2136
2137     while (element = element[property]) {
2138       if (element.nodeType == 1)
2139         elements.push(Element.extend(element));
2140       if (elements.length == maximumLength)
2141         break;
2142     }
2143
2144     return elements;
2145   },
2146
2147   ancestors: function(element) {
2148     return Element.recursivelyCollect(element, 'parentNode');
2149   },
2150
2151   descendants: function(element) {
2152     return Element.select(element, "*");
2153   },
2154
2155   firstDescendant: function(element) {
2156     element = $(element).firstChild;
2157     while (element && element.nodeType != 1) element = element.nextSibling;
2158     return $(element);
2159   },
2160
2161   immediateDescendants: function(element) {
2162     var results = [], child = $(element).firstChild;
2163     while (child) {
2164       if (child.nodeType === 1) {
2165         results.push(Element.extend(child));
2166       }
2167       child = child.nextSibling;
2168     }
2169     return results;
2170   },
2171
2172   previousSiblings: function(element, maximumLength) {
2173     return Element.recursivelyCollect(element, 'previousSibling');
2174   },
2175
2176   nextSiblings: function(element) {
2177     return Element.recursivelyCollect(element, 'nextSibling');
2178   },
2179
2180   siblings: function(element) {
2181     element = $(element);
2182     return Element.previousSiblings(element).reverse()
2183       .concat(Element.nextSiblings(element));
2184   },
2185
2186   match: function(element, selector) {
2187     element = $(element);
2188     if (Object.isString(selector))
2189       return Prototype.Selector.match(element, selector);
2190     return selector.match(element);
2191   },
2192
2193   up: function(element, expression, index) {
2194     element = $(element);
2195     if (arguments.length == 1) return $(element.parentNode);
2196     var ancestors = Element.ancestors(element);
2197     return Object.isNumber(expression) ? ancestors[expression] :
2198       Prototype.Selector.find(ancestors, expression, index);
2199   },
2200
2201   down: function(element, expression, index) {
2202     element = $(element);
2203     if (arguments.length == 1) return Element.firstDescendant(element);
2204     return Object.isNumber(expression) ? Element.descendants(element)[expression] :
2205       Element.select(element, expression)[index || 0];
2206   },
2207
2208   previous: function(element, expression, index) {
2209     element = $(element);
2210     if (Object.isNumber(expression)) index = expression, expression = false;
2211     if (!Object.isNumber(index)) index = 0;
2212
2213     if (expression) {
2214       return Prototype.Selector.find(element.previousSiblings(), expression, index);
2215     } else {
2216       return element.recursivelyCollect("previousSibling", index + 1)[index];
2217     }
2218   },
2219
2220   next: function(element, expression, index) {
2221     element = $(element);
2222     if (Object.isNumber(expression)) index = expression, expression = false;
2223     if (!Object.isNumber(index)) index = 0;
2224
2225     if (expression) {
2226       return Prototype.Selector.find(element.nextSiblings(), expression, index);
2227     } else {
2228       var maximumLength = Object.isNumber(index) ? index + 1 : 1;
2229       return element.recursivelyCollect("nextSibling", index + 1)[index];
2230     }
2231   },
2232
2233
2234   select: function(element) {
2235     element = $(element);
2236     var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
2237     return Prototype.Selector.select(expressions, element);
2238   },
2239
2240   adjacent: function(element) {
2241     element = $(element);
2242     var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
2243     return Prototype.Selector.select(expressions, element.parentNode).without(element);
2244   },
2245
2246   identify: function(element) {
2247     element = $(element);
2248     var id = Element.readAttribute(element, 'id');
2249     if (id) return id;
2250     do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
2251     Element.writeAttribute(element, 'id', id);
2252     return id;
2253   },
2254
2255   readAttribute: function(element, name) {
2256     element = $(element);
2257     if (Prototype.Browser.IE) {
2258       var t = Element._attributeTranslations.read;
2259       if (t.values[name]) return t.values[name](element, name);
2260       if (t.names[name]) name = t.names[name];
2261       if (name.include(':')) {
2262         return (!element.attributes || !element.attributes[name]) ? null :
2263          element.attributes[name].value;
2264       }
2265     }
2266     return element.getAttribute(name);
2267   },
2268
2269   writeAttribute: function(element, name, value) {
2270     element = $(element);
2271     var attributes = { }, t = Element._attributeTranslations.write;
2272
2273     if (typeof name == 'object') attributes = name;
2274     else attributes[name] = Object.isUndefined(value) ? true : value;
2275
2276     for (var attr in attributes) {
2277       name = t.names[attr] || attr;
2278       value = attributes[attr];
2279       if (t.values[attr]) name = t.values[attr](element, value);
2280       if (value === false || value === null)
2281         element.removeAttribute(name);
2282       else if (value === true)
2283         element.setAttribute(name, name);
2284       else element.setAttribute(name, value);
2285     }
2286     return element;
2287   },
2288
2289   getHeight: function(element) {
2290     return Element.getDimensions(element).height;
2291   },
2292
2293   getWidth: function(element) {
2294     return Element.getDimensions(element).width;
2295   },
2296
2297   classNames: function(element) {
2298     return new Element.ClassNames(element);
2299   },
2300
2301   hasClassName: function(element, className) {
2302     if (!(element = $(element))) return;
2303     var elementClassName = element.className;
2304     return (elementClassName.length > 0 && (elementClassName == className ||
2305       new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
2306   },
2307
2308   addClassName: function(element, className) {
2309     if (!(element = $(element))) return;
2310     if (!Element.hasClassName(element, className))
2311       element.className += (element.className ? ' ' : '') + className;
2312     return element;
2313   },
2314
2315   removeClassName: function(element, className) {
2316     if (!(element = $(element))) return;
2317     element.className = element.className.replace(
2318       new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
2319     return element;
2320   },
2321
2322   toggleClassName: function(element, className) {
2323     if (!(element = $(element))) return;
2324     return Element[Element.hasClassName(element, className) ?
2325       'removeClassName' : 'addClassName'](element, className);
2326   },
2327
2328   cleanWhitespace: function(element) {
2329     element = $(element);
2330     var node = element.firstChild;
2331     while (node) {
2332       var nextNode = node.nextSibling;
2333       if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
2334         element.removeChild(node);
2335       node = nextNode;
2336     }
2337     return element;
2338   },
2339
2340   empty: function(element) {
2341     return $(element).innerHTML.blank();
2342   },
2343
2344   descendantOf: function(element, ancestor) {
2345     element = $(element), ancestor = $(ancestor);
2346
2347     if (element.compareDocumentPosition)
2348       return (element.compareDocumentPosition(ancestor) & 8) === 8;
2349
2350     if (ancestor.contains)
2351       return ancestor.contains(element) && ancestor !== element;
2352
2353     while (element = element.parentNode)
2354       if (element == ancestor) return true;
2355
2356     return false;
2357   },
2358
2359   scrollTo: function(element) {
2360     element = $(element);
2361     var pos = Element.cumulativeOffset(element);
2362     window.scrollTo(pos[0], pos[1]);
2363     return element;
2364   },
2365
2366   getStyle: function(element, style) {
2367     element = $(element);
2368     style = style == 'float' ? 'cssFloat' : style.camelize();
2369     var value = element.style[style];
2370     if (!value || value == 'auto') {
2371       var css = document.defaultView.getComputedStyle(element, null);
2372       value = css ? css[style] : null;
2373     }
2374     if (style == 'opacity') return value ? parseFloat(value) : 1.0;
2375     return value == 'auto' ? null : value;
2376   },
2377
2378   getOpacity: function(element) {
2379     return $(element).getStyle('opacity');
2380   },
2381
2382   setStyle: function(element, styles) {
2383     element = $(element);
2384     var elementStyle = element.style, match;
2385     if (Object.isString(styles)) {
2386       element.style.cssText += ';' + styles;
2387       return styles.include('opacity') ?
2388         element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
2389     }
2390     for (var property in styles)
2391       if (property == 'opacity') element.setOpacity(styles[property]);
2392       else
2393         elementStyle[(property == 'float' || property == 'cssFloat') ?
2394           (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
2395             property] = styles[property];
2396
2397     return element;
2398   },
2399
2400   setOpacity: function(element, value) {
2401     element = $(element);
2402     element.style.opacity = (value == 1 || value === '') ? '' :
2403       (value < 0.00001) ? 0 : value;
2404     return element;
2405   },
2406
2407   makePositioned: function(element) {
2408     element = $(element);
2409     var pos = Element.getStyle(element, 'position');
2410     if (pos == 'static' || !pos) {
2411       element._madePositioned = true;
2412       element.style.position = 'relative';
2413       if (Prototype.Browser.Opera) {
2414         element.style.top = 0;
2415         element.style.left = 0;
2416       }
2417     }
2418     return element;
2419   },
2420
2421   undoPositioned: function(element) {
2422     element = $(element);
2423     if (element._madePositioned) {
2424       element._madePositioned = undefined;
2425       element.style.position =
2426         element.style.top =
2427         element.style.left =
2428         element.style.bottom =
2429         element.style.right = '';
2430     }
2431     return element;
2432   },
2433
2434   makeClipping: function(element) {
2435     element = $(element);
2436     if (element._overflow) return element;
2437     element._overflow = Element.getStyle(element, 'overflow') || 'auto';
2438     if (element._overflow !== 'hidden')
2439       element.style.overflow = 'hidden';
2440     return element;
2441   },
2442
2443   undoClipping: function(element) {
2444     element = $(element);
2445     if (!element._overflow) return element;
2446     element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
2447     element._overflow = null;
2448     return element;
2449   },
2450
2451   clonePosition: function(element, source) {
2452     var options = Object.extend({
2453       setLeft:    true,
2454       setTop:     true,
2455       setWidth:   true,
2456       setHeight:  true,
2457       offsetTop:  0,
2458       offsetLeft: 0
2459     }, arguments[2] || { });
2460
2461     source = $(source);
2462     var p = Element.viewportOffset(source), delta = [0, 0], parent = null;
2463
2464     element = $(element);
2465
2466     if (Element.getStyle(element, 'position') == 'absolute') {
2467       parent = Element.getOffsetParent(element);
2468       delta = Element.viewportOffset(parent);
2469     }
2470
2471     if (parent == document.body) {
2472       delta[0] -= document.body.offsetLeft;
2473       delta[1] -= document.body.offsetTop;
2474     }
2475
2476     if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
2477     if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
2478     if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
2479     if (options.setHeight) element.style.height = source.offsetHeight + 'px';
2480     return element;
2481   }
2482 };
2483
2484 Object.extend(Element.Methods, {
2485   getElementsBySelector: Element.Methods.select,
2486
2487   childElements: Element.Methods.immediateDescendants
2488 });
2489
2490 Element._attributeTranslations = {
2491   write: {
2492     names: {
2493       className: 'class',
2494       htmlFor:   'for'
2495     },
2496     values: { }
2497   }
2498 };
2499
2500 if (Prototype.Browser.Opera) {
2501   Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2502     function(proceed, element, style) {
2503       switch (style) {
2504         case 'height': case 'width':
2505           if (!Element.visible(element)) return null;
2506
2507           var dim = parseInt(proceed(element, style), 10);
2508
2509           if (dim !== element['offset' + style.capitalize()])
2510             return dim + 'px';
2511
2512           var properties;
2513           if (style === 'height') {
2514             properties = ['border-top-width', 'padding-top',
2515              'padding-bottom', 'border-bottom-width'];
2516           }
2517           else {
2518             properties = ['border-left-width', 'padding-left',
2519              'padding-right', 'border-right-width'];
2520           }
2521           return properties.inject(dim, function(memo, property) {
2522             var val = proceed(element, property);
2523             return val === null ? memo : memo - parseInt(val, 10);
2524           }) + 'px';
2525         default: return proceed(element, style);
2526       }
2527     }
2528   );
2529
2530   Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2531     function(proceed, element, attribute) {
2532       if (attribute === 'title') return element.title;
2533       return proceed(element, attribute);
2534     }
2535   );
2536 }
2537
2538 else if (Prototype.Browser.IE) {
2539   Element.Methods.getStyle = function(element, style) {
2540     element = $(element);
2541     style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2542     var value = element.style[style];
2543     if (!value && element.currentStyle) value = element.currentStyle[style];
2544
2545     if (style == 'opacity') {
2546       if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
2547         if (value[1]) return parseFloat(value[1]) / 100;
2548       return 1.0;
2549     }
2550
2551     if (value == 'auto') {
2552       if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
2553         return element['offset' + style.capitalize()] + 'px';
2554       return null;
2555     }
2556     return value;
2557   };
2558
2559   Element.Methods.setOpacity = function(element, value) {
2560     function stripAlpha(filter){
2561       return filter.replace(/alpha\([^\)]*\)/gi,'');
2562     }
2563     element = $(element);
2564     var currentStyle = element.currentStyle;
2565     if ((currentStyle && !currentStyle.hasLayout) ||
2566       (!currentStyle && element.style.zoom == 'normal'))
2567         element.style.zoom = 1;
2568
2569     var filter = element.getStyle('filter'), style = element.style;
2570     if (value == 1 || value === '') {
2571       (filter = stripAlpha(filter)) ?
2572         style.filter = filter : style.removeAttribute('filter');
2573       return element;
2574     } else if (value < 0.00001) value = 0;
2575     style.filter = stripAlpha(filter) +
2576       'alpha(opacity=' + (value * 100) + ')';
2577     return element;
2578   };
2579
2580   Element._attributeTranslations = (function(){
2581
2582     var classProp = 'className',
2583         forProp = 'for',
2584         el = document.createElement('div');
2585
2586     el.setAttribute(classProp, 'x');
2587
2588     if (el.className !== 'x') {
2589       el.setAttribute('class', 'x');
2590       if (el.className === 'x') {
2591         classProp = 'class';
2592       }
2593     }
2594     el = null;
2595
2596     el = document.createElement('label');
2597     el.setAttribute(forProp, 'x');
2598     if (el.htmlFor !== 'x') {
2599       el.setAttribute('htmlFor', 'x');
2600       if (el.htmlFor === 'x') {
2601         forProp = 'htmlFor';
2602       }
2603     }
2604     el = null;
2605
2606     return {
2607       read: {
2608         names: {
2609           'class':      classProp,
2610           'className':  classProp,
2611           'for':        forProp,
2612           'htmlFor':    forProp
2613         },
2614         values: {
2615           _getAttr: function(element, attribute) {
2616             return element.getAttribute(attribute);
2617           },
2618           _getAttr2: function(element, attribute) {
2619             return element.getAttribute(attribute, 2);
2620           },
2621           _getAttrNode: function(element, attribute) {
2622             var node = element.getAttributeNode(attribute);
2623             return node ? node.value : "";
2624           },
2625           _getEv: (function(){
2626
2627             var el = document.createElement('div'), f;
2628             el.onclick = Prototype.emptyFunction;
2629             var value = el.getAttribute('onclick');
2630
2631             if (String(value).indexOf('{') > -1) {
2632               f = function(element, attribute) {
2633                 attribute = element.getAttribute(attribute);
2634                 if (!attribute) return null;
2635                 attribute = attribute.toString();
2636                 attribute = attribute.split('{')[1];
2637                 attribute = attribute.split('}')[0];
2638                 return attribute.strip();
2639               };
2640             }
2641             else if (value === '') {
2642               f = function(element, attribute) {
2643                 attribute = element.getAttribute(attribute);
2644                 if (!attribute) return null;
2645                 return attribute.strip();
2646               };
2647             }
2648             el = null;
2649             return f;
2650           })(),
2651           _flag: function(element, attribute) {
2652             return $(element).hasAttribute(attribute) ? attribute : null;
2653           },
2654           style: function(element) {
2655             return element.style.cssText.toLowerCase();
2656           },
2657           title: function(element) {
2658             return element.title;
2659           }
2660         }
2661       }
2662     }
2663   })();
2664
2665   Element._attributeTranslations.write = {
2666     names: Object.extend({
2667       cellpadding: 'cellPadding',
2668       cellspacing: 'cellSpacing'
2669     }, Element._attributeTranslations.read.names),
2670     values: {
2671       checked: function(element, value) {
2672         element.checked = !!value;
2673       },
2674
2675       style: function(element, value) {
2676         element.style.cssText = value ? value : '';
2677       }
2678     }
2679   };
2680
2681   Element._attributeTranslations.has = {};
2682
2683   $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2684       'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
2685     Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2686     Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2687   });
2688
2689   (function(v) {
2690     Object.extend(v, {
2691       href:        v._getAttr2,
2692       src:         v._getAttr2,
2693       type:        v._getAttr,
2694       action:      v._getAttrNode,
2695       disabled:    v._flag,
2696       checked:     v._flag,
2697       readonly:    v._flag,
2698       multiple:    v._flag,
2699       onload:      v._getEv,
2700       onunload:    v._getEv,
2701       onclick:     v._getEv,
2702       ondblclick:  v._getEv,
2703       onmousedown: v._getEv,
2704       onmouseup:   v._getEv,
2705       onmouseover: v._getEv,
2706       onmousemove: v._getEv,
2707       onmouseout:  v._getEv,
2708       onfocus:     v._getEv,
2709       onblur:      v._getEv,
2710       onkeypress:  v._getEv,
2711       onkeydown:   v._getEv,
2712       onkeyup:     v._getEv,
2713       onsubmit:    v._getEv,
2714       onreset:     v._getEv,
2715       onselect:    v._getEv,
2716       onchange:    v._getEv
2717     });
2718   })(Element._attributeTranslations.read.values);
2719
2720   if (Prototype.BrowserFeatures.ElementExtensions) {
2721     (function() {
2722       function _descendants(element) {
2723         var nodes = element.getElementsByTagName('*'), results = [];
2724         for (var i = 0, node; node = nodes[i]; i++)
2725           if (node.tagName !== "!") // Filter out comment nodes.
2726             results.push(node);
2727         return results;
2728       }
2729
2730       Element.Methods.down = function(element, expression, index) {
2731         element = $(element);
2732         if (arguments.length == 1) return element.firstDescendant();
2733         return Object.isNumber(expression) ? _descendants(element)[expression] :
2734           Element.select(element, expression)[index || 0];
2735       }
2736     })();
2737   }
2738
2739 }
2740
2741 else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
2742   Element.Methods.setOpacity = function(element, value) {
2743     element = $(element);
2744     element.style.opacity = (value == 1) ? 0.999999 :
2745       (value === '') ? '' : (value < 0.00001) ? 0 : value;
2746     return element;
2747   };
2748 }
2749
2750 else if (Prototype.Browser.WebKit) {
2751   Element.Methods.setOpacity = function(element, value) {
2752     element = $(element);
2753     element.style.opacity = (value == 1 || value === '') ? '' :
2754       (value < 0.00001) ? 0 : value;
2755
2756     if (value == 1)
2757       if (element.tagName.toUpperCase() == 'IMG' && element.width) {
2758         element.width++; element.width--;
2759       } else try {
2760         var n = document.createTextNode(' ');
2761         element.appendChild(n);
2762         element.removeChild(n);
2763       } catch (e) { }
2764
2765     return element;
2766   };
2767 }
2768
2769 if ('outerHTML' in document.documentElement) {
2770   Element.Methods.replace = function(element, content) {
2771     element = $(element);
2772
2773     if (content && content.toElement) content = content.toElement();
2774     if (Object.isElement(content)) {
2775       element.parentNode.replaceChild(content, element);
2776       return element;
2777     }
2778
2779     content = Object.toHTML(content);
2780     var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2781
2782     if (Element._insertionTranslations.tags[tagName]) {
2783       var nextSibling = element.next(),
2784           fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2785       parent.removeChild(element);
2786       if (nextSibling)
2787         fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
2788       else
2789         fragments.each(function(node) { parent.appendChild(node) });
2790     }
2791     else element.outerHTML = content.stripScripts();
2792
2793     content.evalScripts.bind(content).defer();
2794     return element;
2795   };
2796 }
2797
2798 Element._returnOffset = function(l, t) {
2799   var result = [l, t];
2800   result.left = l;
2801   result.top = t;
2802   return result;
2803 };
2804
2805 Element._getContentFromAnonymousElement = function(tagName, html, force) {
2806   var div = new Element('div'),
2807       t = Element._insertionTranslations.tags[tagName];
2808
2809   var workaround = false;
2810   if (t) workaround = true;
2811   else if (force) {
2812     workaround = true;
2813     t = ['', '', 0];
2814   }
2815
2816   if (workaround) {
2817     div.innerHTML = '&nbsp;' + t[0] + html + t[1];
2818     div.removeChild(div.firstChild);
2819     for (var i = t[2]; i--; ) {
2820       div = div.firstChild;
2821     }
2822   }
2823   else {
2824     div.innerHTML = html;
2825   }
2826   return $A(div.childNodes);
2827 };
2828
2829 Element._insertionTranslations = {
2830   before: function(element, node) {
2831     element.parentNode.insertBefore(node, element);
2832   },
2833   top: function(element, node) {
2834     element.insertBefore(node, element.firstChild);
2835   },
2836   bottom: function(element, node) {
2837     element.appendChild(node);
2838   },
2839   after: function(element, node) {
2840     element.parentNode.insertBefore(node, element.nextSibling);
2841   },
2842   tags: {
2843     TABLE:  ['<table>',                '</table>',                   1],
2844     TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
2845     TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
2846     TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2847     SELECT: ['<select>',               '</select>',                  1]
2848   }
2849 };
2850
2851 (function() {
2852   var tags = Element._insertionTranslations.tags;
2853   Object.extend(tags, {
2854     THEAD: tags.TBODY,
2855     TFOOT: tags.TBODY,
2856     TH:    tags.TD
2857   });
2858 })();
2859
2860 Element.Methods.Simulated = {
2861   hasAttribute: function(element, attribute) {
2862     attribute = Element._attributeTranslations.has[attribute] || attribute;
2863     var node = $(element).getAttributeNode(attribute);
2864     return !!(node && node.specified);
2865   }
2866 };
2867
2868 Element.Methods.ByTag = { };
2869
2870 Object.extend(Element, Element.Methods);
2871
2872 (function(div) {
2873
2874   if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
2875     window.HTMLElement = { };
2876     window.HTMLElement.prototype = div['__proto__'];
2877     Prototype.BrowserFeatures.ElementExtensions = true;
2878   }
2879
2880   div = null;
2881
2882 })(document.createElement('div'));
2883
2884 Element.extend = (function() {
2885
2886   function checkDeficiency(tagName) {
2887     if (typeof window.Element != 'undefined') {
2888       var proto = window.Element.prototype;
2889       if (proto) {
2890         var id = '_' + (Math.random()+'').slice(2),
2891             el = document.createElement(tagName);
2892         proto[id] = 'x';
2893         var isBuggy = (el[id] !== 'x');
2894         delete proto[id];
2895         el = null;
2896         return isBuggy;
2897       }
2898     }
2899     return false;
2900   }
2901
2902   function extendElementWith(element, methods) {
2903     for (var property in methods) {
2904       var value = methods[property];
2905       if (Object.isFunction(value) && !(property in element))
2906         element[property] = value.methodize();
2907     }
2908   }
2909
2910   var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
2911
2912   if (Prototype.BrowserFeatures.SpecificElementExtensions) {
2913     if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
2914       return function(element) {
2915         if (element && typeof element._extendedByPrototype == 'undefined') {
2916           var t = element.tagName;
2917           if (t && (/^(?:object|applet|embed)$/i.test(t))) {
2918             extendElementWith(element, Element.Methods);
2919             extendElementWith(element, Element.Methods.Simulated);
2920             extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
2921           }
2922         }
2923         return element;
2924       }
2925     }
2926     return Prototype.K;
2927   }
2928
2929   var Methods = { }, ByTag = Element.Methods.ByTag;
2930
2931   var extend = Object.extend(function(element) {
2932     if (!element || typeof element._extendedByPrototype != 'undefined' ||
2933         element.nodeType != 1 || element == window) return element;
2934
2935     var methods = Object.clone(Methods),
2936         tagName = element.tagName.toUpperCase();
2937
2938     if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
2939
2940     extendElementWith(element, methods);
2941
2942     element._extendedByPrototype = Prototype.emptyFunction;
2943     return element;
2944
2945   }, {
2946     refresh: function() {
2947       if (!Prototype.BrowserFeatures.ElementExtensions) {
2948         Object.extend(Methods, Element.Methods);
2949         Object.extend(Methods, Element.Methods.Simulated);
2950       }
2951     }
2952   });
2953
2954   extend.refresh();
2955   return extend;
2956 })();
2957
2958 if (document.documentElement.hasAttribute) {
2959   Element.hasAttribute = function(element, attribute) {
2960     return element.hasAttribute(attribute);
2961   };
2962 }
2963 else {
2964   Element.hasAttribute = Element.Methods.Simulated.hasAttribute;
2965 }
2966
2967 Element.addMethods = function(methods) {
2968   var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
2969
2970   if (!methods) {
2971     Object.extend(Form, Form.Methods);
2972     Object.extend(Form.Element, Form.Element.Methods);
2973     Object.extend(Element.Methods.ByTag, {
2974       "FORM":     Object.clone(Form.Methods),
2975       "INPUT":    Object.clone(Form.Element.Methods),
2976       "SELECT":   Object.clone(Form.Element.Methods),
2977       "TEXTAREA": Object.clone(Form.Element.Methods),
2978       "BUTTON":   Object.clone(Form.Element.Methods)
2979     });
2980   }
2981
2982   if (arguments.length == 2) {
2983     var tagName = methods;
2984     methods = arguments[1];
2985   }
2986
2987   if (!tagName) Object.extend(Element.Methods, methods || { });
2988   else {
2989     if (Object.isArray(tagName)) tagName.each(extend);
2990     else extend(tagName);
2991   }
2992
2993   function extend(tagName) {
2994     tagName = tagName.toUpperCase();
2995     if (!Element.Methods.ByTag[tagName])
2996       Element.Methods.ByTag[tagName] = { };
2997     Object.extend(Element.Methods.ByTag[tagName], methods);
2998   }
2999
3000   function copy(methods, destination, onlyIfAbsent) {
3001     onlyIfAbsent = onlyIfAbsent || false;
3002     for (var property in methods) {
3003       var value = methods[property];
3004       if (!Object.isFunction(value)) continue;
3005       if (!onlyIfAbsent || !(property in destination))
3006         destination[property] = value.methodize();
3007     }
3008   }
3009
3010   function findDOMClass(tagName) {
3011     var klass;
3012     var trans = {
3013       "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3014       "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3015       "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3016       "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3017       "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3018       "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3019       "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3020       "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3021       "FrameSet", "IFRAME": "IFrame"
3022     };
3023     if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
3024     if (window[klass]) return window[klass];
3025     klass = 'HTML' + tagName + 'Element';
3026     if (window[klass]) return window[klass];
3027     klass = 'HTML' + tagName.capitalize() + 'Element';
3028     if (window[klass]) return window[klass];
3029
3030     var element = document.createElement(tagName),
3031         proto = element['__proto__'] || element.constructor.prototype;
3032
3033     element = null;
3034     return proto;
3035   }
3036
3037   var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
3038    Element.prototype;
3039
3040   if (F.ElementExtensions) {
3041     copy(Element.Methods, elementPrototype);
3042     copy(Element.Methods.Simulated, elementPrototype, true);
3043   }
3044
3045   if (F.SpecificElementExtensions) {
3046     for (var tag in Element.Methods.ByTag) {
3047       var klass = findDOMClass(tag);
3048       if (Object.isUndefined(klass)) continue;
3049       copy(T[tag], klass.prototype);
3050     }
3051   }
3052
3053   Object.extend(Element, Element.Methods);
3054   delete Element.ByTag;
3055
3056   if (Element.extend.refresh) Element.extend.refresh();
3057   Element.cache = { };
3058 };
3059
3060
3061 document.viewport = {
3062
3063   getDimensions: function() {
3064     return { width: this.getWidth(), height: this.getHeight() };
3065   },
3066
3067   getScrollOffsets: function() {
3068     return Element._returnOffset(
3069       window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
3070       window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);
3071   }
3072 };
3073
3074 (function(viewport) {
3075   var B = Prototype.Browser, doc = document, element, property = {};
3076
3077   function getRootElement() {
3078     if (B.WebKit && !doc.evaluate)
3079       return document;
3080
3081     if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
3082       return document.body;
3083
3084     return document.documentElement;
3085   }
3086
3087   function define(D) {
3088     if (!element) element = getRootElement();
3089
3090     property[D] = 'client' + D;
3091
3092     viewport['get' + D] = function() { return element[property[D]] };
3093     return viewport['get' + D]();
3094   }
3095
3096   viewport.getWidth  = define.curry('Width');
3097
3098   viewport.getHeight = define.curry('Height');
3099 })(document.viewport);
3100
3101
3102 Element.Storage = {
3103   UID: 1
3104 };
3105
3106 Element.addMethods({
3107   getStorage: function(element) {
3108     if (!(element = $(element))) return;
3109
3110     var uid;
3111     if (element === window) {
3112       uid = 0;
3113     } else {
3114       if (typeof element._prototypeUID === "undefined")
3115         element._prototypeUID = Element.Storage.UID++;
3116       uid = element._prototypeUID;
3117     }
3118
3119     if (!Element.Storage[uid])
3120       Element.Storage[uid] = $H();
3121
3122     return Element.Storage[uid];
3123   },
3124
3125   store: function(element, key, value) {
3126     if (!(element = $(element))) return;
3127
3128     if (arguments.length === 2) {
3129       Element.getStorage(element).update(key);
3130     } else {
3131       Element.getStorage(element).set(key, value);
3132     }
3133
3134     return element;
3135   },
3136
3137   retrieve: function(element, key, defaultValue) {
3138     if (!(element = $(element))) return;
3139     var hash = Element.getStorage(element), value = hash.get(key);
3140
3141     if (Object.isUndefined(value)) {
3142       hash.set(key, defaultValue);
3143       value = defaultValue;
3144     }
3145
3146     return value;
3147   },
3148
3149   clone: function(element, deep) {
3150     if (!(element = $(element))) return;
3151     var clone = element.cloneNode(deep);
3152     clone._prototypeUID = void 0;
3153     if (deep) {
3154       var descendants = Element.select(clone, '*'),
3155           i = descendants.length;
3156       while (i--) {
3157         descendants[i]._prototypeUID = void 0;
3158       }
3159     }
3160     return Element.extend(clone);
3161   },
3162
3163   purge: function(element) {
3164     if (!(element = $(element))) return;
3165     var purgeElement = Element._purgeElement;
3166
3167     purgeElement(element);
3168
3169     var descendants = element.getElementsByTagName('*'),
3170      i = descendants.length;
3171
3172     while (i--) purgeElement(descendants[i]);
3173
3174     return null;
3175   }
3176 });
3177
3178 (function() {
3179
3180   function toDecimal(pctString) {
3181     var match = pctString.match(/^(\d+)%?$/i);
3182     if (!match) return null;
3183     return (Number(match[1]) / 100);
3184   }
3185
3186   function getPixelValue(value, property, context) {
3187     var element = null;
3188     if (Object.isElement(value)) {
3189       element = value;
3190       value = element.getStyle(property);
3191     }
3192
3193     if (value === null) {
3194       return null;
3195     }
3196
3197     if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
3198       return window.parseFloat(value);
3199     }
3200
3201     var isPercentage = value.include('%'), isViewport = (context === document.viewport);
3202
3203     if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
3204       var style = element.style.left, rStyle = element.runtimeStyle.left;
3205       element.runtimeStyle.left = element.currentStyle.left;
3206       element.style.left = value || 0;
3207       value = element.style.pixelLeft;
3208       element.style.left = style;
3209       element.runtimeStyle.left = rStyle;
3210
3211       return value;
3212     }
3213
3214     if (element && isPercentage) {
3215       context = context || element.parentNode;
3216       var decimal = toDecimal(value);
3217       var whole = null;
3218       var position = element.getStyle('position');
3219
3220       var isHorizontal = property.include('left') || property.include('right') ||
3221        property.include('width');
3222
3223       var isVertical =  property.include('top') || property.include('bottom') ||
3224         property.include('height');
3225
3226       if (context === document.viewport) {
3227         if (isHorizontal) {
3228           whole = document.viewport.getWidth();
3229         } else if (isVertical) {
3230           whole = document.viewport.getHeight();
3231         }
3232       } else {
3233         if (isHorizontal) {
3234           whole = $(context).measure('width');
3235         } else if (isVertical) {
3236           whole = $(context).measure('height');
3237         }
3238       }
3239
3240       return (whole === null) ? 0 : whole * decimal;
3241     }
3242
3243     return 0;
3244   }
3245
3246   function toCSSPixels(number) {
3247     if (Object.isString(number) && number.endsWith('px')) {
3248       return number;
3249     }
3250     return number + 'px';
3251   }
3252
3253   function isDisplayed(element) {
3254     var originalElement = element;
3255     while (element && element.parentNode) {
3256       var display = element.getStyle('display');
3257       if (display === 'none') {
3258         return false;
3259       }
3260       element = $(element.parentNode);
3261     }
3262     return true;
3263   }
3264
3265   var hasLayout = Prototype.K;
3266   if ('currentStyle' in document.documentElement) {
3267     hasLayout = function(element) {
3268       if (!element.currentStyle.hasLayout) {
3269         element.style.zoom = 1;
3270       }
3271       return element;
3272     };
3273   }
3274
3275   function cssNameFor(key) {
3276     if (key.include('border')) key = key + '-width';
3277     return key.camelize();
3278   }
3279
3280   Element.Layout = Class.create(Hash, {
3281     initialize: function($super, element, preCompute) {
3282       $super();
3283       this.element = $(element);
3284
3285       Element.Layout.PROPERTIES.each( function(property) {
3286         this._set(property, null);
3287       }, this);
3288
3289       if (preCompute) {
3290         this._preComputing = true;
3291         this._begin();
3292         Element.Layout.PROPERTIES.each( this._compute, this );
3293         this._end();
3294         this._preComputing = false;
3295       }
3296     },
3297
3298     _set: function(property, value) {
3299       return Hash.prototype.set.call(this, property, value);
3300     },
3301
3302     set: function(property, value) {
3303       throw "Properties of Element.Layout are read-only.";
3304     },
3305
3306     get: function($super, property) {
3307       var value = $super(property);
3308       return value === null ? this._compute(property) : value;
3309     },
3310
3311     _begin: function() {
3312       if (this._prepared) return;
3313
3314       var element = this.element;
3315       if (isDisplayed(element)) {
3316         this._prepared = true;
3317         return;
3318       }
3319
3320       var originalStyles = {
3321         position:   element.style.position   || '',
3322         width:      element.style.width      || '',
3323         visibility: element.style.visibility || '',
3324         display:    element.style.display    || ''
3325       };
3326
3327       element.store('prototype_original_styles', originalStyles);
3328
3329       var position = element.getStyle('position'),
3330        width = element.getStyle('width');
3331
3332       if (width === "0px" || width === null) {
3333         element.style.display = 'block';
3334         width = element.getStyle('width');
3335       }
3336
3337       var context = (position === 'fixed') ? document.viewport :
3338        element.parentNode;
3339
3340       element.setStyle({
3341         position:   'absolute',
3342         visibility: 'hidden',
3343         display:    'block'
3344       });
3345
3346       var positionedWidth = element.getStyle('width');
3347
3348       var newWidth;
3349       if (width && (positionedWidth === width)) {
3350         newWidth = getPixelValue(element, 'width', context);
3351       } else if (position === 'absolute' || position === 'fixed') {
3352         newWidth = getPixelValue(element, 'width', context);
3353       } else {
3354         var parent = element.parentNode, pLayout = $(parent).getLayout();
3355
3356         newWidth = pLayout.get('width') -
3357          this.get('margin-left') -
3358          this.get('border-left') -
3359          this.get('padding-left') -
3360          this.get('padding-right') -
3361          this.get('border-right') -
3362          this.get('margin-right');
3363       }
3364
3365       element.setStyle({ width: newWidth + 'px' });
3366
3367       this._prepared = true;
3368     },
3369
3370     _end: function() {
3371       var element = this.element;
3372       var originalStyles = element.retrieve('prototype_original_styles');
3373       element.store('prototype_original_styles', null);
3374       element.setStyle(originalStyles);
3375       this._prepared = false;
3376     },
3377
3378     _compute: function(property) {
3379       var COMPUTATIONS = Element.Layout.COMPUTATIONS;
3380       if (!(property in COMPUTATIONS)) {
3381         throw "Property not found.";
3382       }
3383
3384       return this._set(property, COMPUTATIONS[property].call(this, this.element));
3385     },
3386
3387     toObject: function() {
3388       var args = $A(arguments);
3389       var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3390        args.join(' ').split(' ');
3391       var obj = {};
3392       keys.each( function(key) {
3393         if (!Element.Layout.PROPERTIES.include(key)) return;
3394         var value = this.get(key);
3395         if (value != null) obj[key] = value;
3396       }, this);
3397       return obj;
3398     },
3399
3400     toHash: function() {
3401       var obj = this.toObject.apply(this, arguments);
3402       return new Hash(obj);
3403     },
3404
3405     toCSS: function() {
3406       var args = $A(arguments);
3407       var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3408        args.join(' ').split(' ');
3409       var css = {};
3410
3411       keys.each( function(key) {
3412         if (!Element.Layout.PROPERTIES.include(key)) return;
3413         if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
3414
3415         var value = this.get(key);
3416         if (value != null) css[cssNameFor(key)] = value + 'px';
3417       }, this);
3418       return css;
3419     },
3420
3421     inspect: function() {
3422       return "#<Element.Layout>";
3423     }
3424   });
3425
3426   Object.extend(Element.Layout, {
3427     PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
3428
3429     COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3430
3431     COMPUTATIONS: {
3432       'height': function(element) {
3433         if (!this._preComputing) this._begin();
3434
3435         var bHeight = this.get('border-box-height');
3436         if (bHeight <= 0) {
3437           if (!this._preComputing) this._end();
3438           return 0;
3439         }
3440
3441         var bTop = this.get('border-top'),
3442          bBottom = this.get('border-bottom');
3443
3444         var pTop = this.get('padding-top'),
3445          pBottom = this.get('padding-bottom');
3446
3447         if (!this._preComputing) this._end();
3448
3449         return bHeight - bTop - bBottom - pTop - pBottom;
3450       },
3451
3452       'width': function(element) {
3453         if (!this._preComputing) this._begin();
3454
3455         var bWidth = this.get('border-box-width');
3456         if (bWidth <= 0) {
3457           if (!this._preComputing) this._end();
3458           return 0;
3459         }
3460
3461         var bLeft = this.get('border-left'),
3462          bRight = this.get('border-right');
3463
3464         var pLeft = this.get('padding-left'),
3465          pRight = this.get('padding-right');
3466
3467         if (!this._preComputing) this._end();
3468
3469         return bWidth - bLeft - bRight - pLeft - pRight;
3470       },
3471
3472       'padding-box-height': function(element) {
3473         var height = this.get('height'),
3474          pTop = this.get('padding-top'),
3475          pBottom = this.get('padding-bottom');
3476
3477         return height + pTop + pBottom;
3478       },
3479
3480       'padding-box-width': function(element) {
3481         var width = this.get('width'),
3482          pLeft = this.get('padding-left'),
3483          pRight = this.get('padding-right');
3484
3485         return width + pLeft + pRight;
3486       },
3487
3488       'border-box-height': function(element) {
3489         if (!this._preComputing) this._begin();
3490         var height = element.offsetHeight;
3491         if (!this._preComputing) this._end();
3492         return height;
3493       },
3494
3495       'border-box-width': function(element) {
3496         if (!this._preComputing) this._begin();
3497         var width = element.offsetWidth;
3498         if (!this._preComputing) this._end();
3499         return width;
3500       },
3501
3502       'margin-box-height': function(element) {
3503         var bHeight = this.get('border-box-height'),
3504          mTop = this.get('margin-top'),
3505          mBottom = this.get('margin-bottom');
3506
3507         if (bHeight <= 0) return 0;
3508
3509         return bHeight + mTop + mBottom;
3510       },
3511
3512       'margin-box-width': function(element) {
3513         var bWidth = this.get('border-box-width'),
3514          mLeft = this.get('margin-left'),
3515          mRight = this.get('margin-right');
3516
3517         if (bWidth <= 0) return 0;
3518
3519         return bWidth + mLeft + mRight;
3520       },
3521
3522       'top': function(element) {
3523         var offset = element.positionedOffset();
3524         return offset.top;
3525       },
3526
3527       'bottom': function(element) {
3528         var offset = element.positionedOffset(),
3529          parent = element.getOffsetParent(),
3530          pHeight = parent.measure('height');
3531
3532         var mHeight = this.get('border-box-height');
3533
3534         return pHeight - mHeight - offset.top;
3535       },
3536
3537       'left': function(element) {
3538         var offset = element.positionedOffset();
3539         return offset.left;
3540       },
3541
3542       'right': function(element) {
3543         var offset = element.positionedOffset(),
3544          parent = element.getOffsetParent(),
3545          pWidth = parent.measure('width');
3546
3547         var mWidth = this.get('border-box-width');
3548
3549         return pWidth - mWidth - offset.left;
3550       },
3551
3552       'padding-top': function(element) {
3553         return getPixelValue(element, 'paddingTop');
3554       },
3555
3556       'padding-bottom': function(element) {
3557         return getPixelValue(element, 'paddingBottom');
3558       },
3559
3560       'padding-left': function(element) {
3561         return getPixelValue(element, 'paddingLeft');
3562       },
3563
3564       'padding-right': function(element) {
3565         return getPixelValue(element, 'paddingRight');
3566       },
3567
3568       'border-top': function(element) {
3569         return getPixelValue(element, 'borderTopWidth');
3570       },
3571
3572       'border-bottom': function(element) {
3573         return getPixelValue(element, 'borderBottomWidth');
3574       },
3575
3576       'border-left': function(element) {
3577         return getPixelValue(element, 'borderLeftWidth');
3578       },
3579
3580       'border-right': function(element) {
3581         return getPixelValue(element, 'borderRightWidth');
3582       },
3583
3584       'margin-top': function(element) {
3585         return getPixelValue(element, 'marginTop');
3586       },
3587
3588       'margin-bottom': function(element) {
3589         return getPixelValue(element, 'marginBottom');
3590       },
3591
3592       'margin-left': function(element) {
3593         return getPixelValue(element, 'marginLeft');
3594       },
3595
3596       'margin-right': function(element) {
3597         return getPixelValue(element, 'marginRight');
3598       }
3599     }
3600   });
3601
3602   if ('getBoundingClientRect' in document.documentElement) {
3603     Object.extend(Element.Layout.COMPUTATIONS, {
3604       'right': function(element) {
3605         var parent = hasLayout(element.getOffsetParent());
3606         var rect = element.getBoundingClientRect(),
3607          pRect = parent.getBoundingClientRect();
3608
3609         return (pRect.right - rect.right).round();
3610       },
3611
3612       'bottom': function(element) {
3613         var parent = hasLayout(element.getOffsetParent());
3614         var rect = element.getBoundingClientRect(),
3615          pRect = parent.getBoundingClientRect();
3616
3617         return (pRect.bottom - rect.bottom).round();
3618       }
3619     });
3620   }
3621
3622   Element.Offset = Class.create({
3623     initialize: function(left, top) {
3624       this.left = left.round();
3625       this.top  = top.round();
3626
3627       this[0] = this.left;
3628       this[1] = this.top;
3629     },
3630
3631     relativeTo: function(offset) {
3632       return new Element.Offset(
3633         this.left - offset.left,
3634         this.top  - offset.top
3635       );
3636     },
3637
3638     inspect: function() {
3639       return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3640     },
3641
3642     toString: function() {
3643       return "[#{left}, #{top}]".interpolate(this);
3644     },
3645
3646     toArray: function() {
3647       return [this.left, this.top];
3648     }
3649   });
3650
3651   function getLayout(element, preCompute) {
3652     return new Element.Layout(element, preCompute);
3653   }
3654
3655   function measure(element, property) {
3656     return $(element).getLayout().get(property);
3657   }
3658
3659   function getDimensions(element) {
3660     element = $(element);
3661     var display = Element.getStyle(element, 'display');
3662
3663     if (display && display !== 'none') {
3664       return { width: element.offsetWidth, height: element.offsetHeight };
3665     }
3666
3667     var style = element.style;
3668     var originalStyles = {
3669       visibility: style.visibility,
3670       position:   style.position,
3671       display:    style.display
3672     };
3673
3674     var newStyles = {
3675       visibility: 'hidden',
3676       display:    'block'
3677     };
3678
3679     if (originalStyles.position !== 'fixed')
3680       newStyles.position = 'absolute';
3681
3682     Element.setStyle(element, newStyles);
3683
3684     var dimensions = {
3685       width:  element.offsetWidth,
3686       height: element.offsetHeight
3687     };
3688
3689     Element.setStyle(element, originalStyles);
3690
3691     return dimensions;
3692   }
3693
3694   function getOffsetParent(element) {
3695     element = $(element);
3696
3697     if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
3698       return $(document.body);
3699
3700     var isInline = (Element.getStyle(element, 'display') === 'inline');
3701     if (!isInline && element.offsetParent) return $(element.offsetParent);
3702
3703     while ((element = element.parentNode) && element !== document.body) {
3704       if (Element.getStyle(element, 'position') !== 'static') {
3705         return isHtml(element) ? $(document.body) : $(element);
3706       }
3707     }
3708
3709     return $(document.body);
3710   }
3711
3712
3713   function cumulativeOffset(element) {
3714     element = $(element);
3715     var valueT = 0, valueL = 0;
3716     if (element.parentNode) {
3717       do {
3718         valueT += element.offsetTop  || 0;
3719         valueL += element.offsetLeft || 0;
3720         element = element.offsetParent;
3721       } while (element);
3722     }
3723     return new Element.Offset(valueL, valueT);
3724   }
3725
3726   function positionedOffset(element) {
3727     element = $(element);
3728
3729     var layout = element.getLayout();
3730
3731     var valueT = 0, valueL = 0;
3732     do {
3733       valueT += element.offsetTop  || 0;
3734       valueL += element.offsetLeft || 0;
3735       element = element.offsetParent;
3736       if (element) {
3737         if (isBody(element)) break;
3738         var p = Element.getStyle(element, 'position');
3739         if (p !== 'static') break;
3740       }
3741     } while (element);
3742
3743     valueL -= layout.get('margin-top');
3744     valueT -= layout.get('margin-left');
3745
3746     return new Element.Offset(valueL, valueT);
3747   }
3748
3749   function cumulativeScrollOffset(element) {
3750     var valueT = 0, valueL = 0;
3751     do {
3752       valueT += element.scrollTop  || 0;
3753       valueL += element.scrollLeft || 0;
3754       element = element.parentNode;
3755     } while (element);
3756     return new Element.Offset(valueL, valueT);
3757   }
3758
3759   function viewportOffset(forElement) {
3760     element = $(element);
3761     var valueT = 0, valueL = 0, docBody = document.body;
3762
3763     var element = forElement;
3764     do {
3765       valueT += element.offsetTop  || 0;
3766       valueL += element.offsetLeft || 0;
3767       if (element.offsetParent == docBody &&
3768         Element.getStyle(element, 'position') == 'absolute') break;
3769     } while (element = element.offsetParent);
3770
3771     element = forElement;
3772     do {
3773       if (element != docBody) {
3774         valueT -= element.scrollTop  || 0;
3775         valueL -= element.scrollLeft || 0;
3776       }
3777     } while (element = element.parentNode);
3778     return new Element.Offset(valueL, valueT);
3779   }
3780
3781   function absolutize(element) {
3782     element = $(element);
3783
3784     if (Element.getStyle(element, 'position') === 'absolute') {
3785       return element;
3786     }
3787
3788     var offsetParent = getOffsetParent(element);
3789     var eOffset = element.viewportOffset(),
3790      pOffset = offsetParent.viewportOffset();
3791
3792     var offset = eOffset.relativeTo(pOffset);
3793     var layout = element.getLayout();
3794
3795     element.store('prototype_absolutize_original_styles', {
3796       left:   element.getStyle('left'),
3797       top:    element.getStyle('top'),
3798       width:  element.getStyle('width'),
3799       height: element.getStyle('height')
3800     });
3801
3802     element.setStyle({
3803       position: 'absolute',
3804       top:    offset.top + 'px',
3805       left:   offset.left + 'px',
3806       width:  layout.get('width') + 'px',
3807       height: layout.get('height') + 'px'
3808     });
3809
3810     return element;
3811   }
3812
3813   function relativize(element) {
3814     element = $(element);
3815     if (Element.getStyle(element, 'position') === 'relative') {
3816       return element;
3817     }
3818
3819     var originalStyles =
3820      element.retrieve('prototype_absolutize_original_styles');
3821
3822     if (originalStyles) element.setStyle(originalStyles);
3823     return element;
3824   }
3825
3826   if (Prototype.Browser.IE) {
3827     getOffsetParent = getOffsetParent.wrap(
3828       function(proceed, element) {
3829         element = $(element);
3830
3831         if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
3832           return $(document.body);
3833
3834         var position = element.getStyle('position');
3835         if (position !== 'static') return proceed(element);
3836
3837         element.setStyle({ position: 'relative' });
3838         var value = proceed(element);
3839         element.setStyle({ position: position });
3840         return value;
3841       }
3842     );
3843
3844     positionedOffset = positionedOffset.wrap(function(proceed, element) {
3845       element = $(element);
3846       if (!element.parentNode) return new Element.Offset(0, 0);
3847       var position = element.getStyle('position');
3848       if (position !== 'static') return proceed(element);
3849
3850       var offsetParent = element.getOffsetParent();
3851       if (offsetParent && offsetParent.getStyle('position') === 'fixed')
3852         hasLayout(offsetParent);
3853
3854       element.setStyle({ position: 'relative' });
3855       var value = proceed(element);
3856       element.setStyle({ position: position });
3857       return value;
3858     });
3859   } else if (Prototype.Browser.Webkit) {
3860     cumulativeOffset = function(element) {
3861       element = $(element);
3862       var valueT = 0, valueL = 0;
3863       do {
3864         valueT += element.offsetTop  || 0;
3865         valueL += element.offsetLeft || 0;
3866         if (element.offsetParent == document.body)
3867           if (Element.getStyle(element, 'position') == 'absolute') break;
3868
3869         element = element.offsetParent;
3870       } while (element);
3871
3872       return new Element.Offset(valueL, valueT);
3873     };
3874   }
3875
3876
3877   Element.addMethods({
3878     getLayout:              getLayout,
3879     measure:                measure,
3880     getDimensions:          getDimensions,
3881     getOffsetParent:        getOffsetParent,
3882     cumulativeOffset:       cumulativeOffset,
3883     positionedOffset:       positionedOffset,
3884     cumulativeScrollOffset: cumulativeScrollOffset,
3885     viewportOffset:         viewportOffset,
3886     absolutize:             absolutize,
3887     relativize:             relativize
3888   });
3889
3890   function isBody(element) {
3891     return element.nodeName.toUpperCase() === 'BODY';
3892   }
3893
3894   function isHtml(element) {
3895     return element.nodeName.toUpperCase() === 'HTML';
3896   }
3897
3898   function isDocument(element) {
3899     return element.nodeType === Node.DOCUMENT_NODE;
3900   }
3901
3902   function isDetached(element) {
3903     return element !== document.body &&
3904      !Element.descendantOf(element, document.body);
3905   }
3906
3907   if ('getBoundingClientRect' in document.documentElement) {
3908     Element.addMethods({
3909       viewportOffset: function(element) {
3910         element = $(element);
3911         if (isDetached(element)) return new Element.Offset(0, 0);
3912
3913         var rect = element.getBoundingClientRect(),
3914          docEl = document.documentElement;
3915         return new Element.Offset(rect.left - docEl.clientLeft,
3916          rect.top - docEl.clientTop);
3917       }
3918     });
3919   }
3920 })();
3921 window.$$ = function() {
3922   var expression = $A(arguments).join(', ');
3923   return Prototype.Selector.select(expression, document);
3924 };
3925
3926 Prototype.Selector = (function() {
3927
3928   function select() {
3929     throw new Error('Method "Prototype.Selector.select" must be defined.');
3930   }
3931
3932   function match() {
3933     throw new Error('Method "Prototype.Selector.match" must be defined.');
3934   }
3935
3936   function find(elements, expression, index) {
3937     index = index || 0;
3938     var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
3939
3940     for (i = 0; i < length; i++) {
3941       if (match(elements[i], expression) && index == matchIndex++) {
3942         return Element.extend(elements[i]);
3943       }
3944     }
3945   }
3946
3947   function extendElements(elements) {
3948     for (var i = 0, length = elements.length; i < length; i++) {
3949       Element.extend(elements[i]);
3950     }
3951     return elements;
3952   }
3953
3954
3955   var K = Prototype.K;
3956
3957   return {
3958     select: select,
3959     match: match,
3960     find: find,
3961     extendElements: (Element.extend === K) ? K : extendElements,
3962     extendElement: Element.extend
3963   };
3964 })();
3965 Prototype._original_property = window.Sizzle;
3966 /*!
3967  * Sizzle CSS Selector Engine - v1.0
3968  *  Copyright 2009, The Dojo Foundation
3969  *  Released under the MIT, BSD, and GPL Licenses.
3970  *  More information: http://sizzlejs.com/
3971  */
3972 (function(){
3973
3974 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
3975         done = 0,
3976         toString = Object.prototype.toString,
3977         hasDuplicate = false,
3978         baseHasDuplicate = true;
3979
3980 [0, 0].sort(function(){
3981         baseHasDuplicate = false;
3982         return 0;
3983 });
3984
3985 var Sizzle = function(selector, context, results, seed) {
3986         results = results || [];
3987         var origContext = context = context || document;
3988
3989         if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
3990                 return [];
3991         }
3992
3993         if ( !selector || typeof selector !== "string" ) {
3994                 return results;
3995         }
3996
3997         var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context),
3998                 soFar = selector;
3999
4000         while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
4001                 soFar = m[3];
4002
4003                 parts.push( m[1] );
4004
4005                 if ( m[2] ) {
4006                         extra = m[3];
4007                         break;
4008                 }
4009         }
4010
4011         if ( parts.length > 1 && origPOS.exec( selector ) ) {
4012                 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
4013                         set = posProcess( parts[0] + parts[1], context );
4014                 } else {
4015                         set = Expr.relative[ parts[0] ] ?
4016                                 [ context ] :
4017                                 Sizzle( parts.shift(), context );
4018
4019                         while ( parts.length ) {
4020                                 selector = parts.shift();
4021
4022                                 if ( Expr.relative[ selector ] )
4023                                         selector += parts.shift();
4024
4025                                 set = posProcess( selector, set );
4026                         }
4027                 }
4028         } else {
4029                 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
4030                                 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
4031                         var ret = Sizzle.find( parts.shift(), context, contextXML );
4032                         context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
4033                 }
4034
4035                 if ( context ) {
4036                         var ret = seed ?
4037                                 { expr: parts.pop(), set: makeArray(seed) } :
4038                                 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
4039                         set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
4040
4041                         if ( parts.length > 0 ) {
4042                                 checkSet = makeArray(set);
4043                         } else {
4044                                 prune = false;
4045                         }
4046
4047                         while ( parts.length ) {
4048                                 var cur = parts.pop(), pop = cur;
4049
4050                                 if ( !Expr.relative[ cur ] ) {
4051                                         cur = "";
4052                                 } else {
4053                                         pop = parts.pop();
4054                                 }
4055
4056                                 if ( pop == null ) {
4057                                         pop = context;
4058                                 }
4059
4060                                 Expr.relative[ cur ]( checkSet, pop, contextXML );
4061                         }
4062                 } else {
4063                         checkSet = parts = [];
4064                 }
4065         }
4066
4067         if ( !checkSet ) {
4068                 checkSet = set;
4069         }
4070
4071         if ( !checkSet ) {
4072                 throw "Syntax error, unrecognized expression: " + (cur || selector);
4073         }
4074
4075         if ( toString.call(checkSet) === "[object Array]" ) {
4076                 if ( !prune ) {
4077                         results.push.apply( results, checkSet );
4078                 } else if ( context && context.nodeType === 1 ) {
4079                         for ( var i = 0; checkSet[i] != null; i++ ) {
4080                                 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
4081                                         results.push( set[i] );
4082                                 }
4083                         }
4084                 } else {
4085                         for ( var i = 0; checkSet[i] != null; i++ ) {
4086                                 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
4087                                         results.push( set[i] );
4088                                 }
4089                         }
4090                 }
4091         } else {
4092                 makeArray( checkSet, results );
4093         }
4094
4095         if ( extra ) {
4096                 Sizzle( extra, origContext, results, seed );
4097                 Sizzle.uniqueSort( results );
4098         }
4099
4100         return results;
4101 };
4102
4103 Sizzle.uniqueSort = function(results){
4104         if ( sortOrder ) {
4105                 hasDuplicate = baseHasDuplicate;
4106                 results.sort(sortOrder);
4107
4108                 if ( hasDuplicate ) {
4109                         for ( var i = 1; i < results.length; i++ ) {
4110                                 if ( results[i] === results[i-1] ) {
4111                                         results.splice(i--, 1);
4112                                 }
4113                         }
4114                 }
4115         }
4116
4117         return results;
4118 };
4119
4120 Sizzle.matches = function(expr, set){
4121         return Sizzle(expr, null, null, set);
4122 };
4123
4124 Sizzle.find = function(expr, context, isXML){
4125         var set, match;
4126
4127         if ( !expr ) {
4128                 return [];
4129         }
4130
4131         for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
4132                 var type = Expr.order[i], match;
4133
4134                 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
4135                         var left = match[1];
4136                         match.splice(1,1);
4137
4138                         if ( left.substr( left.length - 1 ) !== "\\" ) {
4139                                 match[1] = (match[1] || "").replace(/\\/g, "");
4140                                 set = Expr.find[ type ]( match, context, isXML );
4141                                 if ( set != null ) {
4142                                         expr = expr.replace( Expr.match[ type ], "" );
4143                                         break;
4144                                 }
4145                         }
4146                 }
4147         }
4148
4149         if ( !set ) {
4150                 set = context.getElementsByTagName("*");
4151         }
4152
4153         return {set: set, expr: expr};
4154 };
4155
4156 Sizzle.filter = function(expr, set, inplace, not){
4157         var old = expr, result = [], curLoop = set, match, anyFound,
4158                 isXMLFilter = set && set[0] && isXML(set[0]);
4159
4160         while ( expr && set.length ) {
4161                 for ( var type in Expr.filter ) {
4162                         if ( (match = Expr.match[ type ].exec( expr )) != null ) {
4163                                 var filter = Expr.filter[ type ], found, item;
4164                                 anyFound = false;
4165
4166                                 if ( curLoop == result ) {
4167                                         result = [];
4168                                 }
4169
4170                                 if ( Expr.preFilter[ type ] ) {
4171                                         match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
4172
4173                                         if ( !match ) {
4174                                                 anyFound = found = true;
4175                                         } else if ( match === true ) {
4176                                                 continue;
4177                                         }
4178                                 }
4179
4180                                 if ( match ) {
4181                                         for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
4182                                                 if ( item ) {
4183                                                         found = filter( item, match, i, curLoop );
4184                                                         var pass = not ^ !!found;
4185
4186                                                         if ( inplace && found != null ) {
4187                                                                 if ( pass ) {
4188                                                                         anyFound = true;
4189                                                                 } else {
4190                                                                         curLoop[i] = false;
4191                                                                 }
4192                                                         } else if ( pass ) {
4193                                                                 result.push( item );
4194                                                                 anyFound = true;
4195                                                         }
4196                                                 }
4197                                         }
4198                                 }
4199
4200                                 if ( found !== undefined ) {
4201                                         if ( !inplace ) {
4202                                                 curLoop = result;
4203                                         }
4204
4205                                         expr = expr.replace( Expr.match[ type ], "" );
4206
4207                                         if ( !anyFound ) {
4208                                                 return [];
4209                                         }
4210
4211                                         break;
4212                                 }
4213                         }
4214                 }
4215
4216                 if ( expr == old ) {
4217                         if ( anyFound == null ) {
4218                                 throw "Syntax error, unrecognized expression: " + expr;
4219                         } else {
4220                                 break;
4221                         }
4222                 }
4223
4224                 old = expr;
4225         }
4226
4227         return curLoop;
4228 };
4229
4230 var Expr = Sizzle.selectors = {
4231         order: [ "ID", "NAME", "TAG" ],
4232         match: {
4233                 ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
4234                 CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
4235                 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
4236                 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
4237                 TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
4238                 CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
4239                 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
4240                 PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
4241         },
4242         leftMatch: {},
4243         attrMap: {
4244                 "class": "className",
4245                 "for": "htmlFor"
4246         },
4247         attrHandle: {
4248                 href: function(elem){
4249                         return elem.getAttribute("href");
4250                 }
4251         },
4252         relative: {
4253                 "+": function(checkSet, part, isXML){
4254                         var isPartStr = typeof part === "string",
4255                                 isTag = isPartStr && !/\W/.test(part),
4256                                 isPartStrNotTag = isPartStr && !isTag;
4257
4258                         if ( isTag && !isXML ) {
4259                                 part = part.toUpperCase();
4260                         }
4261
4262                         for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
4263                                 if ( (elem = checkSet[i]) ) {
4264                                         while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
4265
4266                                         checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
4267                                                 elem || false :
4268                                                 elem === part;
4269                                 }
4270                         }
4271
4272                         if ( isPartStrNotTag ) {
4273                                 Sizzle.filter( part, checkSet, true );
4274                         }
4275                 },
4276                 ">": function(checkSet, part, isXML){
4277                         var isPartStr = typeof part === "string";
4278
4279                         if ( isPartStr && !/\W/.test(part) ) {
4280                                 part = isXML ? part : part.toUpperCase();
4281
4282                                 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4283                                         var elem = checkSet[i];
4284                                         if ( elem ) {
4285                                                 var parent = elem.parentNode;
4286                                                 checkSet[i] = parent.nodeName === part ? parent : false;
4287                                         }
4288                                 }
4289                         } else {
4290                                 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4291                                         var elem = checkSet[i];
4292                                         if ( elem ) {
4293                                                 checkSet[i] = isPartStr ?
4294                                                         elem.parentNode :
4295                                                         elem.parentNode === part;
4296                                         }
4297                                 }
4298
4299                                 if ( isPartStr ) {
4300                                         Sizzle.filter( part, checkSet, true );
4301                                 }
4302                         }
4303                 },
4304                 "": function(checkSet, part, isXML){
4305                         var doneName = done++, checkFn = dirCheck;
4306
4307                         if ( !/\W/.test(part) ) {
4308                                 var nodeCheck = part = isXML ? part : part.toUpperCase();
4309                                 checkFn = dirNodeCheck;
4310                         }
4311
4312                         checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
4313                 },
4314                 "~": function(checkSet, part, isXML){
4315                         var doneName = done++, checkFn = dirCheck;
4316
4317                         if ( typeof part === "string" && !/\W/.test(part) ) {
4318                                 var nodeCheck = part = isXML ? part : part.toUpperCase();
4319                                 checkFn = dirNodeCheck;
4320                         }
4321
4322                         checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
4323                 }
4324         },
4325         find: {
4326                 ID: function(match, context, isXML){
4327                         if ( typeof context.getElementById !== "undefined" && !isXML ) {
4328                                 var m = context.getElementById(match[1]);
4329                                 return m ? [m] : [];
4330                         }
4331                 },
4332                 NAME: function(match, context, isXML){
4333                         if ( typeof context.getElementsByName !== "undefined" ) {
4334                                 var ret = [], results = context.getElementsByName(match[1]);
4335
4336                                 for ( var i = 0, l = results.length; i < l; i++ ) {
4337                                         if ( results[i].getAttribute("name") === match[1] ) {
4338                                                 ret.push( results[i] );
4339                                         }
4340                                 }
4341
4342                                 return ret.length === 0 ? null : ret;
4343                         }
4344                 },
4345                 TAG: function(match, context){
4346                         return context.getElementsByTagName(match[1]);
4347                 }
4348         },
4349         preFilter: {
4350                 CLASS: function(match, curLoop, inplace, result, not, isXML){
4351                         match = " " + match[1].replace(/\\/g, "") + " ";
4352
4353                         if ( isXML ) {
4354                                 return match;
4355                         }
4356
4357                         for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
4358                                 if ( elem ) {
4359                                         if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
4360                                                 if ( !inplace )
4361                                                         result.push( elem );
4362                                         } else if ( inplace ) {
4363                                                 curLoop[i] = false;
4364                                         }
4365                                 }
4366                         }
4367
4368                         return false;
4369                 },
4370                 ID: function(match){
4371                         return match[1].replace(/\\/g, "");
4372                 },
4373                 TAG: function(match, curLoop){
4374                         for ( var i = 0; curLoop[i] === false; i++ ){}
4375                         return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
4376                 },
4377                 CHILD: function(match){
4378                         if ( match[1] == "nth" ) {
4379                                 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
4380                                         match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
4381                                         !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
4382
4383                                 match[2] = (test[1] + (test[2] || 1)) - 0;
4384                                 match[3] = test[3] - 0;
4385                         }
4386
4387                         match[0] = done++;
4388
4389                         return match;
4390                 },
4391                 ATTR: function(match, curLoop, inplace, result, not, isXML){
4392                         var name = match[1].replace(/\\/g, "");
4393
4394                         if ( !isXML && Expr.attrMap[name] ) {
4395                                 match[1] = Expr.attrMap[name];
4396                         }
4397
4398                         if ( match[2] === "~=" ) {
4399                                 match[4] = " " + match[4] + " ";
4400                         }
4401
4402                         return match;
4403                 },
4404                 PSEUDO: function(match, curLoop, inplace, result, not){
4405                         if ( match[1] === "not" ) {
4406                                 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
4407                                         match[3] = Sizzle(match[3], null, null, curLoop);
4408                                 } else {
4409                                         var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
4410                                         if ( !inplace ) {
4411                                                 result.push.apply( result, ret );
4412                                         }
4413                                         return false;
4414                                 }
4415                         } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
4416                                 return true;
4417                         }
4418
4419                         return match;
4420                 },
4421                 POS: function(match){
4422                         match.unshift( true );
4423                         return match;
4424                 }
4425         },
4426         filters: {
4427                 enabled: function(elem){
4428                         return elem.disabled === false && elem.type !== "hidden";
4429                 },
4430                 disabled: function(elem){
4431                         return elem.disabled === true;
4432                 },
4433                 checked: function(elem){
4434                         return elem.checked === true;
4435                 },
4436                 selected: function(elem){
4437                         elem.parentNode.selectedIndex;
4438                         return elem.selected === true;
4439                 },
4440                 parent: function(elem){
4441                         return !!elem.firstChild;
4442                 },
4443                 empty: function(elem){
4444                         return !elem.firstChild;
4445                 },
4446                 has: function(elem, i, match){
4447                         return !!Sizzle( match[3], elem ).length;
4448                 },
4449                 header: function(elem){
4450                         return /h\d/i.test( elem.nodeName );
4451                 },
4452                 text: function(elem){
4453                         return "text" === elem.type;
4454                 },
4455                 radio: function(elem){
4456                         return "radio" === elem.type;
4457                 },
4458                 checkbox: function(elem){
4459                         return "checkbox" === elem.type;
4460                 },
4461                 file: function(elem){
4462                         return "file" === elem.type;
4463                 },
4464                 password: function(elem){
4465                         return "password" === elem.type;
4466                 },
4467                 submit: function(elem){
4468                         return "submit" === elem.type;
4469                 },
4470                 image: function(elem){
4471                         return "image" === elem.type;
4472                 },
4473                 reset: function(elem){
4474                         return "reset" === elem.type;
4475                 },
4476                 button: function(elem){
4477                         return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
4478                 },
4479                 input: function(elem){
4480                         return /input|select|textarea|button/i.test(elem.nodeName);
4481                 }
4482         },
4483         setFilters: {
4484                 first: function(elem, i){
4485                         return i === 0;
4486                 },
4487                 last: function(elem, i, match, array){
4488                         return i === array.length - 1;
4489                 },
4490                 even: function(elem, i){
4491                         return i % 2 === 0;
4492                 },
4493                 odd: function(elem, i){
4494                         return i % 2 === 1;
4495                 },
4496                 lt: function(elem, i, match){
4497                         return i < match[3] - 0;
4498                 },
4499                 gt: function(elem, i, match){
4500                         return i > match[3] - 0;
4501                 },
4502                 nth: function(elem, i, match){
4503                         return match[3] - 0 == i;
4504                 },
4505                 eq: function(elem, i, match){
4506                         return match[3] - 0 == i;
4507                 }
4508         },
4509         filter: {
4510                 PSEUDO: function(elem, match, i, array){
4511                         var name = match[1], filter = Expr.filters[ name ];
4512
4513                         if ( filter ) {
4514                                 return filter( elem, i, match, array );
4515                         } else if ( name === "contains" ) {
4516                                 return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
4517                         } else if ( name === "not" ) {
4518                                 var not = match[3];
4519
4520                                 for ( var i = 0, l = not.length; i < l; i++ ) {
4521                                         if ( not[i] === elem ) {
4522                                                 return false;
4523                                         }
4524                                 }
4525
4526                                 return true;
4527                         }
4528                 },
4529                 CHILD: function(elem, match){
4530                         var type = match[1], node = elem;
4531                         switch (type) {
4532                                 case 'only':
4533                                 case 'first':
4534                                         while ( (node = node.previousSibling) )  {
4535                                                 if ( node.nodeType === 1 ) return false;
4536                                         }
4537                                         if ( type == 'first') return true;
4538                                         node = elem;
4539                                 case 'last':
4540                                         while ( (node = node.nextSibling) )  {
4541                                                 if ( node.nodeType === 1 ) return false;
4542                                         }
4543                                         return true;
4544                                 case 'nth':
4545                                         var first = match[2], last = match[3];
4546
4547                                         if ( first == 1 && last == 0 ) {
4548                                                 return true;
4549                                         }
4550
4551                                         var doneName = match[0],
4552                                                 parent = elem.parentNode;
4553
4554                                         if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
4555                                                 var count = 0;
4556                                                 for ( node = parent.firstChild; node; node = node.nextSibling ) {
4557                                                         if ( node.nodeType === 1 ) {
4558                                                                 node.nodeIndex = ++count;
4559                                                         }
4560                                                 }
4561                                                 parent.sizcache = doneName;
4562                                         }
4563
4564                                         var diff = elem.nodeIndex - last;
4565                                         if ( first == 0 ) {
4566                                                 return diff == 0;
4567                                         } else {
4568                                                 return ( diff % first == 0 && diff / first >= 0 );
4569                                         }
4570                         }
4571                 },
4572                 ID: function(elem, match){
4573                         return elem.nodeType === 1 && elem.getAttribute("id") === match;
4574                 },
4575                 TAG: function(elem, match){
4576                         return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
4577                 },
4578                 CLASS: function(elem, match){
4579                         return (" " + (elem.className || elem.getAttribute("class")) + " ")
4580                                 .indexOf( match ) > -1;
4581                 },
4582                 ATTR: function(elem, match){
4583                         var name = match[1],
4584                                 result = Expr.attrHandle[ name ] ?
4585                                         Expr.attrHandle[ name ]( elem ) :
4586                                         elem[ name ] != null ?
4587                                                 elem[ name ] :
4588                                                 elem.getAttribute( name ),
4589                                 value = result + "",
4590                                 type = match[2],
4591                                 check = match[4];
4592
4593                         return result == null ?
4594                                 type === "!=" :
4595                                 type === "=" ?
4596                                 value === check :
4597                                 type === "*=" ?
4598                                 value.indexOf(check) >= 0 :
4599                                 type === "~=" ?
4600                                 (" " + value + " ").indexOf(check) >= 0 :
4601                                 !check ?
4602                                 value && result !== false :
4603                                 type === "!=" ?
4604                                 value != check :
4605                                 type === "^=" ?
4606                                 value.indexOf(check) === 0 :
4607                                 type === "$=" ?
4608                                 value.substr(value.length - check.length) === check :
4609                                 type === "|=" ?
4610                                 value === check || value.substr(0, check.length + 1) === check + "-" :
4611                                 false;
4612                 },
4613                 POS: function(elem, match, i, array){
4614                         var name = match[2], filter = Expr.setFilters[ name ];
4615
4616                         if ( filter ) {
4617                                 return filter( elem, i, match, array );
4618                         }
4619                 }
4620         }
4621 };
4622
4623 var origPOS = Expr.match.POS;
4624
4625 for ( var type in Expr.match ) {
4626         Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
4627         Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
4628 }
4629
4630 var makeArray = function(array, results) {
4631         array = Array.prototype.slice.call( array, 0 );
4632
4633         if ( results ) {
4634                 results.push.apply( results, array );
4635                 return results;
4636         }
4637
4638         return array;
4639 };
4640
4641 try {
4642         Array.prototype.slice.call( document.documentElement.childNodes, 0 );
4643
4644 } catch(e){
4645         makeArray = function(array, results) {
4646                 var ret = results || [];
4647
4648                 if ( toString.call(array) === "[object Array]" ) {
4649                         Array.prototype.push.apply( ret, array );
4650                 } else {
4651                         if ( typeof array.length === "number" ) {
4652                                 for ( var i = 0, l = array.length; i < l; i++ ) {
4653                                         ret.push( array[i] );
4654                                 }
4655                         } else {
4656                                 for ( var i = 0; array[i]; i++ ) {
4657                                         ret.push( array[i] );
4658                                 }
4659                         }
4660                 }
4661
4662                 return ret;
4663         };
4664 }
4665
4666 var sortOrder;
4667
4668 if ( document.documentElement.compareDocumentPosition ) {
4669         sortOrder = function( a, b ) {
4670                 if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
4671                         if ( a == b ) {
4672                                 hasDuplicate = true;
4673                         }
4674                         return 0;
4675                 }
4676
4677                 var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
4678                 if ( ret === 0 ) {
4679                         hasDuplicate = true;
4680                 }
4681                 return ret;
4682         };
4683 } else if ( "sourceIndex" in document.documentElement ) {
4684         sortOrder = function( a, b ) {
4685                 if ( !a.sourceIndex || !b.sourceIndex ) {
4686                         if ( a == b ) {
4687                                 hasDuplicate = true;
4688                         }
4689                         return 0;
4690                 }
4691
4692                 var ret = a.sourceIndex - b.sourceIndex;
4693                 if ( ret === 0 ) {
4694                         hasDuplicate = true;
4695                 }
4696                 return ret;
4697         };
4698 } else if ( document.createRange ) {
4699         sortOrder = function( a, b ) {
4700                 if ( !a.ownerDocument || !b.ownerDocument ) {
4701                         if ( a == b ) {
4702                                 hasDuplicate = true;
4703                         }
4704                         return 0;
4705                 }
4706
4707                 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
4708                 aRange.setStart(a, 0);
4709                 aRange.setEnd(a, 0);
4710                 bRange.setStart(b, 0);
4711                 bRange.setEnd(b, 0);
4712                 var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
4713                 if ( ret === 0 ) {
4714                         hasDuplicate = true;
4715                 }
4716                 return ret;
4717         };
4718 }
4719
4720 (function(){
4721         var form = document.createElement("div"),
4722                 id = "script" + (new Date).getTime();
4723         form.innerHTML = "<a name='" + id + "'/>";
4724
4725         var root = document.documentElement;
4726         root.insertBefore( form, root.firstChild );
4727
4728         if ( !!document.getElementById( id ) ) {
4729                 Expr.find.ID = function(match, context, isXML){
4730                         if ( typeof context.getElementById !== "undefined" && !isXML ) {
4731                                 var m = context.getElementById(match[1]);
4732                                 return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
4733                         }
4734                 };
4735
4736                 Expr.filter.ID = function(elem, match){
4737                         var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
4738                         return elem.nodeType === 1 && node && node.nodeValue === match;
4739                 };
4740         }
4741
4742         root.removeChild( form );
4743         root = form = null; // release memory in IE
4744 })();
4745
4746 (function(){
4747
4748         var div = document.createElement("div");
4749         div.appendChild( document.createComment("") );
4750
4751         if ( div.getElementsByTagName("*").length > 0 ) {
4752                 Expr.find.TAG = function(match, context){
4753                         var results = context.getElementsByTagName(match[1]);
4754
4755                         if ( match[1] === "*" ) {
4756                                 var tmp = [];
4757
4758                                 for ( var i = 0; results[i]; i++ ) {
4759                                         if ( results[i].nodeType === 1 ) {
4760                                                 tmp.push( results[i] );
4761                                         }
4762                                 }
4763
4764                                 results = tmp;
4765                         }
4766
4767                         return results;
4768                 };
4769         }
4770
4771         div.innerHTML = "<a href='#'></a>";
4772         if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
4773                         div.firstChild.getAttribute("href") !== "#" ) {
4774                 Expr.attrHandle.href = function(elem){
4775                         return elem.getAttribute("href", 2);
4776                 };
4777         }
4778
4779         div = null; // release memory in IE
4780 })();
4781
4782 if ( document.querySelectorAll ) (function(){
4783         var oldSizzle = Sizzle, div = document.createElement("div");
4784         div.innerHTML = "<p class='TEST'></p>";
4785
4786         if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
4787                 return;
4788         }
4789
4790         Sizzle = function(query, context, extra, seed){
4791                 context = context || document;
4792
4793                 if ( !seed && context.nodeType === 9 && !isXML(context) ) {
4794                         try {
4795                                 return makeArray( context.querySelectorAll(query), extra );
4796                         } catch(e){}
4797                 }
4798
4799                 return oldSizzle(query, context, extra, seed);
4800         };
4801
4802         for ( var prop in oldSizzle ) {
4803                 Sizzle[ prop ] = oldSizzle[ prop ];
4804         }
4805
4806         div = null; // release memory in IE
4807 })();
4808
4809 if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
4810         var div = document.createElement("div");
4811         div.innerHTML = "<div class='test e'></div><div class='test'></div>";
4812
4813         if ( div.getElementsByClassName("e").length === 0 )
4814                 return;
4815
4816         div.lastChild.className = "e";
4817
4818         if ( div.getElementsByClassName("e").length === 1 )
4819                 return;
4820
4821         Expr.order.splice(1, 0, "CLASS");
4822         Expr.find.CLASS = function(match, context, isXML) {
4823                 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
4824                         return context.getElementsByClassName(match[1]);
4825                 }
4826         };
4827
4828         div = null; // release memory in IE
4829 })();
4830
4831 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4832         var sibDir = dir == "previousSibling" && !isXML;
4833         for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4834                 var elem = checkSet[i];
4835                 if ( elem ) {
4836                         if ( sibDir && elem.nodeType === 1 ){
4837                                 elem.sizcache = doneName;
4838                                 elem.sizset = i;
4839                         }
4840                         elem = elem[dir];
4841                         var match = false;
4842
4843                         while ( elem ) {
4844                                 if ( elem.sizcache === doneName ) {
4845                                         match = checkSet[elem.sizset];
4846                                         break;
4847                                 }
4848
4849                                 if ( elem.nodeType === 1 && !isXML ){
4850                                         elem.sizcache = doneName;
4851                                         elem.sizset = i;
4852                                 }
4853
4854                                 if ( elem.nodeName === cur ) {
4855                                         match = elem;
4856                                         break;
4857                                 }
4858
4859                                 elem = elem[dir];
4860                         }
4861
4862                         checkSet[i] = match;
4863                 }
4864         }
4865 }
4866
4867 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4868         var sibDir = dir == "previousSibling" && !isXML;
4869         for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4870                 var elem = checkSet[i];
4871                 if ( elem ) {
4872                         if ( sibDir && elem.nodeType === 1 ) {
4873                                 elem.sizcache = doneName;
4874                                 elem.sizset = i;
4875                         }
4876                         elem = elem[dir];
4877                         var match = false;
4878
4879                         while ( elem ) {
4880                                 if ( elem.sizcache === doneName ) {
4881                                         match = checkSet[elem.sizset];
4882                                         break;
4883                                 }
4884
4885                                 if ( elem.nodeType === 1 ) {
4886                                         if ( !isXML ) {
4887                                                 elem.sizcache = doneName;
4888                                                 elem.sizset = i;
4889                                         }
4890                                         if ( typeof cur !== "string" ) {
4891                                                 if ( elem === cur ) {
4892                                                         match = true;
4893                                                         break;
4894                                                 }
4895
4896                                         } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
4897                                                 match = elem;
4898                                                 break;
4899                                         }
4900                                 }
4901
4902                                 elem = elem[dir];
4903                         }
4904
4905                         checkSet[i] = match;
4906                 }
4907         }
4908 }
4909
4910 var contains = document.compareDocumentPosition ?  function(a, b){
4911         return a.compareDocumentPosition(b) & 16;
4912 } : function(a, b){
4913         return a !== b && (a.contains ? a.contains(b) : true);
4914 };
4915
4916 var isXML = function(elem){
4917         return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
4918                 !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
4919 };
4920
4921 var posProcess = function(selector, context){
4922         var tmpSet = [], later = "", match,
4923                 root = context.nodeType ? [context] : context;
4924
4925         while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
4926                 later += match[0];
4927                 selector = selector.replace( Expr.match.PSEUDO, "" );
4928         }
4929
4930         selector = Expr.relative[selector] ? selector + "*" : selector;
4931
4932         for ( var i = 0, l = root.length; i < l; i++ ) {
4933                 Sizzle( selector, root[i], tmpSet );
4934         }
4935
4936         return Sizzle.filter( later, tmpSet );
4937 };
4938
4939
4940 window.Sizzle = Sizzle;
4941
4942 })();
4943
4944 ;(function(engine) {
4945   var extendElements = Prototype.Selector.extendElements;
4946
4947   function select(selector, scope) {
4948     return extendElements(engine(selector, scope || document));
4949   }
4950
4951   function match(element, selector) {
4952     return engine.matches(selector, [element]).length == 1;
4953   }
4954
4955   Prototype.Selector.engine = engine;
4956   Prototype.Selector.select = select;
4957   Prototype.Selector.match = match;
4958 })(Sizzle);
4959
4960 window.Sizzle = Prototype._original_property;
4961 delete Prototype._original_property;
4962
4963 var Form = {
4964   reset: function(form) {
4965     form = $(form);
4966     form.reset();
4967     return form;
4968   },
4969
4970   serializeElements: function(elements, options) {
4971     if (typeof options != 'object') options = { hash: !!options };
4972     else if (Object.isUndefined(options.hash)) options.hash = true;
4973     var key, value, submitted = false, submit = options.submit, accumulator, initial;
4974
4975     if (options.hash) {
4976       initial = {};
4977       accumulator = function(result, key, value) {
4978         if (key in result) {
4979           if (!Object.isArray(result[key])) result[key] = [result[key]];
4980           result[key].push(value);
4981         } else result[key] = value;
4982         return result;
4983       };
4984     } else {
4985       initial = '';
4986       accumulator = function(result, key, value) {
4987         return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
4988       }
4989     }
4990
4991     return elements.inject(initial, function(result, element) {
4992       if (!element.disabled && element.name) {
4993         key = element.name; value = $(element).getValue();
4994         if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
4995             submit !== false && (!submit || key == submit) && (submitted = true)))) {
4996           result = accumulator(result, key, value);
4997         }
4998       }
4999       return result;
5000     });
5001   }
5002 };
5003
5004 Form.Methods = {
5005   serialize: function(form, options) {
5006     return Form.serializeElements(Form.getElements(form), options);
5007   },
5008
5009   getElements: function(form) {
5010     var elements = $(form).getElementsByTagName('*'),
5011         element,
5012         arr = [ ],
5013         serializers = Form.Element.Serializers;
5014     for (var i = 0; element = elements[i]; i++) {
5015       arr.push(element);
5016     }
5017     return arr.inject([], function(elements, child) {
5018       if (serializers[child.tagName.toLowerCase()])
5019         elements.push(Element.extend(child));
5020       return elements;
5021     })
5022   },
5023
5024   getInputs: function(form, typeName, name) {
5025     form = $(form);
5026     var inputs = form.getElementsByTagName('input');
5027
5028     if (!typeName && !name) return $A(inputs).map(Element.extend);
5029
5030     for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
5031       var input = inputs[i];
5032       if ((typeName && input.type != typeName) || (name && input.name != name))
5033         continue;
5034       matchingInputs.push(Element.extend(input));
5035     }
5036
5037     return matchingInputs;
5038   },
5039
5040   disable: function(form) {
5041     form = $(form);
5042     Form.getElements(form).invoke('disable');
5043     return form;
5044   },
5045
5046   enable: function(form) {
5047     form = $(form);
5048     Form.getElements(form).invoke('enable');
5049     return form;
5050   },
5051
5052   findFirstElement: function(form) {
5053     var elements = $(form).getElements().findAll(function(element) {
5054       return 'hidden' != element.type && !element.disabled;
5055     });
5056     var firstByIndex = elements.findAll(function(element) {
5057       return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
5058     }).sortBy(function(element) { return element.tabIndex }).first();
5059
5060     return firstByIndex ? firstByIndex : elements.find(function(element) {
5061       return /^(?:input|select|textarea)$/i.test(element.tagName);
5062     });
5063   },
5064
5065   focusFirstElement: function(form) {
5066     form = $(form);
5067     var element = form.findFirstElement();
5068     if (element) element.activate();
5069     return form;
5070   },
5071
5072   request: function(form, options) {
5073     form = $(form), options = Object.clone(options || { });
5074
5075     var params = options.parameters, action = form.readAttribute('action') || '';
5076     if (action.blank()) action = window.location.href;
5077     options.parameters = form.serialize(true);
5078
5079     if (params) {
5080       if (Object.isString(params)) params = params.toQueryParams();
5081       Object.extend(options.parameters, params);
5082     }
5083
5084     if (form.hasAttribute('method') && !options.method)
5085       options.method = form.method;
5086
5087     return new Ajax.Request(action, options);
5088   }
5089 };
5090
5091 /*--------------------------------------------------------------------------*/
5092
5093
5094 Form.Element = {
5095   focus: function(element) {
5096     $(element).focus();
5097     return element;
5098   },
5099
5100   select: function(element) {
5101     $(element).select();
5102     return element;
5103   }
5104 };
5105
5106 Form.Element.Methods = {
5107
5108   serialize: function(element) {
5109     element = $(element);
5110     if (!element.disabled && element.name) {
5111       var value = element.getValue();
5112       if (value != undefined) {
5113         var pair = { };
5114         pair[element.name] = value;
5115         return Object.toQueryString(pair);
5116       }
5117     }
5118     return '';
5119   },
5120
5121   getValue: function(element) {
5122     element = $(element);
5123     var method = element.tagName.toLowerCase();
5124     return Form.Element.Serializers[method](element);
5125   },
5126
5127   setValue: function(element, value) {
5128     element = $(element);
5129     var method = element.tagName.toLowerCase();
5130     Form.Element.Serializers[method](element, value);
5131     return element;
5132   },
5133
5134   clear: function(element) {
5135     $(element).value = '';
5136     return element;
5137   },
5138
5139   present: function(element) {
5140     return $(element).value != '';
5141   },
5142
5143   activate: function(element) {
5144     element = $(element);
5145     try {
5146       element.focus();
5147       if (element.select && (element.tagName.toLowerCase() != 'input' ||
5148           !(/^(?:button|reset|submit)$/i.test(element.type))))
5149         element.select();
5150     } catch (e) { }
5151     return element;
5152   },
5153
5154   disable: function(element) {
5155     element = $(element);
5156     element.disabled = true;
5157     return element;
5158   },
5159
5160   enable: function(element) {
5161     element = $(element);
5162     element.disabled = false;
5163     return element;
5164   }
5165 };
5166
5167 /*--------------------------------------------------------------------------*/
5168
5169 var Field = Form.Element;
5170
5171 var $F = Form.Element.Methods.getValue;
5172
5173 /*--------------------------------------------------------------------------*/
5174
5175 Form.Element.Serializers = (function() {
5176   function input(element, value) {
5177     switch (element.type.toLowerCase()) {
5178       case 'checkbox':
5179       case 'radio':
5180         return inputSelector(element, value);
5181       default:
5182         return valueSelector(element, value);
5183     }
5184   }
5185
5186   function inputSelector(element, value) {
5187     if (Object.isUndefined(value))
5188       return element.checked ? element.value : null;
5189     else element.checked = !!value;
5190   }
5191
5192   function valueSelector(element, value) {
5193     if (Object.isUndefined(value)) return element.value;
5194     else element.value = value;
5195   }
5196
5197   function select(element, value) {
5198     if (Object.isUndefined(value))
5199       return (element.type === 'select-one' ? selectOne : selectMany)(element);
5200
5201     var opt, currentValue, single = !Object.isArray(value);
5202     for (var i = 0, length = element.length; i < length; i++) {
5203       opt = element.options[i];
5204       currentValue = this.optionValue(opt);
5205       if (single) {
5206         if (currentValue == value) {
5207           opt.selected = true;
5208           return;
5209         }
5210       }
5211       else opt.selected = value.include(currentValue);
5212     }
5213   }
5214
5215   function selectOne(element) {
5216     var index = element.selectedIndex;
5217     return index >= 0 ? optionValue(element.options[index]) : null;
5218   }
5219
5220   function selectMany(element) {
5221     var values, length = element.length;
5222     if (!length) return null;
5223
5224     for (var i = 0, values = []; i < length; i++) {
5225       var opt = element.options[i];
5226       if (opt.selected) values.push(optionValue(opt));
5227     }
5228     return values;
5229   }
5230
5231   function optionValue(opt) {
5232     return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
5233   }
5234
5235   return {
5236     input:         input,
5237     inputSelector: inputSelector,
5238     textarea:      valueSelector,
5239     select:        select,
5240     selectOne:     selectOne,
5241     selectMany:    selectMany,
5242     optionValue:   optionValue,
5243     button:        valueSelector
5244   };
5245 })();
5246
5247 /*--------------------------------------------------------------------------*/
5248
5249
5250 Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
5251   initialize: function($super, element, frequency, callback) {
5252     $super(callback, frequency);
5253     this.element   = $(element);
5254     this.lastValue = this.getValue();
5255   },
5256
5257   execute: function() {
5258     var value = this.getValue();
5259     if (Object.isString(this.lastValue) && Object.isString(value) ?
5260         this.lastValue != value : String(this.lastValue) != String(value)) {
5261       this.callback(this.element, value);
5262       this.lastValue = value;
5263     }
5264   }
5265 });
5266
5267 Form.Element.Observer = Class.create(Abstract.TimedObserver, {
5268   getValue: function() {
5269     return Form.Element.getValue(this.element);
5270   }
5271 });
5272
5273 Form.Observer = Class.create(Abstract.TimedObserver, {
5274   getValue: function() {
5275     return Form.serialize(this.element);
5276   }
5277 });
5278
5279 /*--------------------------------------------------------------------------*/
5280
5281 Abstract.EventObserver = Class.create({
5282   initialize: function(element, callback) {
5283     this.element  = $(element);
5284     this.callback = callback;
5285
5286     this.lastValue = this.getValue();
5287     if (this.element.tagName.toLowerCase() == 'form')
5288       this.registerFormCallbacks();
5289     else
5290       this.registerCallback(this.element);
5291   },
5292
5293   onElementEvent: function() {
5294     var value = this.getValue();
5295     if (this.lastValue != value) {
5296       this.callback(this.element, value);
5297       this.lastValue = value;
5298     }
5299   },
5300
5301   registerFormCallbacks: function() {
5302     Form.getElements(this.element).each(this.registerCallback, this);
5303   },
5304
5305   registerCallback: function(element) {
5306     if (element.type) {
5307       switch (element.type.toLowerCase()) {
5308         case 'checkbox':
5309         case 'radio':
5310           Event.observe(element, 'click', this.onElementEvent.bind(this));
5311           break;
5312         default:
5313           Event.observe(element, 'change', this.onElementEvent.bind(this));
5314           break;
5315       }
5316     }
5317   }
5318 });
5319
5320 Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
5321   getValue: function() {
5322     return Form.Element.getValue(this.element);
5323   }
5324 });
5325
5326 Form.EventObserver = Class.create(Abstract.EventObserver, {
5327   getValue: function() {
5328     return Form.serialize(this.element);
5329   }
5330 });
5331 (function() {
5332
5333   var Event = {
5334     KEY_BACKSPACE: 8,
5335     KEY_TAB:       9,
5336     KEY_RETURN:   13,
5337     KEY_ESC:      27,
5338     KEY_LEFT:     37,
5339     KEY_UP:       38,
5340     KEY_RIGHT:    39,
5341     KEY_DOWN:     40,
5342     KEY_DELETE:   46,
5343     KEY_HOME:     36,
5344     KEY_END:      35,
5345     KEY_PAGEUP:   33,
5346     KEY_PAGEDOWN: 34,
5347     KEY_INSERT:   45,
5348
5349     cache: {}
5350   };
5351
5352   var docEl = document.documentElement;
5353   var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
5354     && 'onmouseleave' in docEl;
5355
5356
5357
5358   var isIELegacyEvent = function(event) { return false; };
5359
5360   if (window.attachEvent) {
5361     if (window.addEventListener) {
5362       isIELegacyEvent = function(event) {
5363         return !(event instanceof window.Event);
5364       };
5365     } else {
5366       isIELegacyEvent = function(event) { return true; };
5367     }
5368   }
5369
5370   var _isButton;
5371
5372   function _isButtonForDOMEvents(event, code) {
5373     return event.which ? (event.which === code + 1) : (event.button === code);
5374   }
5375
5376   var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
5377   function _isButtonForLegacyEvents(event, code) {
5378     return event.button === legacyButtonMap[code];
5379   }
5380
5381   function _isButtonForWebKit(event, code) {
5382     switch (code) {
5383       case 0: return event.which == 1 && !event.metaKey;
5384       case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
5385       case 2: return event.which == 3;
5386       default: return false;
5387     }
5388   }
5389
5390   if (window.attachEvent) {
5391     if (!window.addEventListener) {
5392       _isButton = _isButtonForLegacyEvents;
5393     } else {
5394       _isButton = function(event, code) {
5395         return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
5396          _isButtonForDOMEvents(event, code);
5397       }
5398     }
5399   } else if (Prototype.Browser.WebKit) {
5400     _isButton = _isButtonForWebKit;
5401   } else {
5402     _isButton = _isButtonForDOMEvents;
5403   }
5404
5405   function isLeftClick(event)   { return _isButton(event, 0) }
5406
5407   function isMiddleClick(event) { return _isButton(event, 1) }
5408
5409   function isRightClick(event)  { return _isButton(event, 2) }
5410
5411   function element(event) {
5412     event = Event.extend(event);
5413
5414     var node = event.target, type = event.type,
5415      currentTarget = event.currentTarget;
5416
5417     if (currentTarget && currentTarget.tagName) {
5418       if (type === 'load' || type === 'error' ||
5419         (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
5420           && currentTarget.type === 'radio'))
5421             node = currentTarget;
5422     }
5423
5424     if (node.nodeType == Node.TEXT_NODE)
5425       node = node.parentNode;
5426
5427     return Element.extend(node);
5428   }
5429
5430   function findElement(event, expression) {
5431     var element = Event.element(event);
5432
5433     if (!expression) return element;
5434     while (element) {
5435       if (Object.isElement(element) && Prototype.Selector.match(element, expression)) {
5436         return Element.extend(element);
5437       }
5438       element = element.parentNode;
5439     }
5440   }
5441
5442   function pointer(event) {
5443     return { x: pointerX(event), y: pointerY(event) };
5444   }
5445
5446   function pointerX(event) {
5447     var docElement = document.documentElement,
5448      body = document.body || { scrollLeft: 0 };
5449
5450     return event.pageX || (event.clientX +
5451       (docElement.scrollLeft || body.scrollLeft) -
5452       (docElement.clientLeft || 0));
5453   }
5454
5455   function pointerY(event) {
5456     var docElement = document.documentElement,
5457      body = document.body || { scrollTop: 0 };
5458
5459     return  event.pageY || (event.clientY +
5460        (docElement.scrollTop || body.scrollTop) -
5461        (docElement.clientTop || 0));
5462   }
5463
5464
5465   function stop(event) {
5466     Event.extend(event);
5467     event.preventDefault();
5468     event.stopPropagation();
5469
5470     event.stopped = true;
5471   }
5472
5473
5474   Event.Methods = {
5475     isLeftClick:   isLeftClick,
5476     isMiddleClick: isMiddleClick,
5477     isRightClick:  isRightClick,
5478
5479     element:     element,
5480     findElement: findElement,
5481
5482     pointer:  pointer,
5483     pointerX: pointerX,
5484     pointerY: pointerY,
5485
5486     stop: stop
5487   };
5488
5489   var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
5490     m[name] = Event.Methods[name].methodize();
5491     return m;
5492   });
5493
5494   if (window.attachEvent) {
5495     function _relatedTarget(event) {
5496       var element;
5497       switch (event.type) {
5498         case 'mouseover':
5499         case 'mouseenter':
5500           element = event.fromElement;
5501           break;
5502         case 'mouseout':
5503         case 'mouseleave':
5504           element = event.toElement;
5505           break;
5506         default:
5507           return null;
5508       }
5509       return Element.extend(element);
5510     }
5511
5512     var additionalMethods = {
5513       stopPropagation: function() { this.cancelBubble = true },
5514       preventDefault:  function() { this.returnValue = false },
5515       inspect: function() { return '[object Event]' }
5516     };
5517
5518     Event.extend = function(event, element) {
5519       if (!event) return false;
5520
5521       if (!isIELegacyEvent(event)) return event;
5522
5523       if (event._extendedByPrototype) return event;
5524       event._extendedByPrototype = Prototype.emptyFunction;
5525
5526       var pointer = Event.pointer(event);
5527
5528       Object.extend(event, {
5529         target: event.srcElement || element,
5530         relatedTarget: _relatedTarget(event),
5531         pageX:  pointer.x,
5532         pageY:  pointer.y
5533       });
5534
5535       Object.extend(event, methods);
5536       Object.extend(event, additionalMethods);
5537
5538       return event;
5539     };
5540   } else {
5541     Event.extend = Prototype.K;
5542   }
5543
5544   if (window.addEventListener) {
5545     Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
5546     Object.extend(Event.prototype, methods);
5547   }
5548
5549   function _createResponder(element, eventName, handler) {
5550     var registry = Element.retrieve(element, 'prototype_event_registry');
5551
5552     if (Object.isUndefined(registry)) {
5553       CACHE.push(element);
5554       registry = Element.retrieve(element, 'prototype_event_registry', $H());
5555     }
5556
5557     var respondersForEvent = registry.get(eventName);
5558     if (Object.isUndefined(respondersForEvent)) {
5559       respondersForEvent = [];
5560       registry.set(eventName, respondersForEvent);
5561     }
5562
5563     if (respondersForEvent.pluck('handler').include(handler)) return false;
5564
5565     var responder;
5566     if (eventName.include(":")) {
5567       responder = function(event) {
5568         if (Object.isUndefined(event.eventName))
5569           return false;
5570
5571         if (event.eventName !== eventName)
5572           return false;
5573
5574         Event.extend(event, element);
5575         handler.call(element, event);
5576       };
5577     } else {
5578       if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
5579        (eventName === "mouseenter" || eventName === "mouseleave")) {
5580         if (eventName === "mouseenter" || eventName === "mouseleave") {
5581           responder = function(event) {
5582             Event.extend(event, element);
5583
5584             var parent = event.relatedTarget;
5585             while (parent && parent !== element) {
5586               try { parent = parent.parentNode; }
5587               catch(e) { parent = element; }
5588             }
5589
5590             if (parent === element) return;
5591
5592             handler.call(element, event);
5593           };
5594         }
5595       } else {
5596         responder = function(event) {
5597           Event.extend(event, element);
5598           handler.call(element, event);
5599         };
5600       }
5601     }
5602
5603     responder.handler = handler;
5604     respondersForEvent.push(responder);
5605     return responder;
5606   }
5607
5608   function _destroyCache() {
5609     for (var i = 0, length = CACHE.length; i < length; i++) {
5610       Event.stopObserving(CACHE[i]);
5611       CACHE[i] = null;
5612     }
5613   }
5614
5615   var CACHE = [];
5616
5617   if (Prototype.Browser.IE)
5618     window.attachEvent('onunload', _destroyCache);
5619
5620   if (Prototype.Browser.WebKit)
5621     window.addEventListener('unload', Prototype.emptyFunction, false);
5622
5623
5624   var _getDOMEventName = Prototype.K,
5625       translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
5626
5627   if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
5628     _getDOMEventName = function(eventName) {
5629       return (translations[eventName] || eventName);
5630     };
5631   }
5632
5633   function observe(element, eventName, handler) {
5634     element = $(element);
5635
5636     var responder = _createResponder(element, eventName, handler);
5637
5638     if (!responder) return element;
5639
5640     if (eventName.include(':')) {
5641       if (element.addEventListener)
5642         element.addEventListener("dataavailable", responder, false);
5643       else {
5644         element.attachEvent("ondataavailable", responder);
5645         element.attachEvent("onlosecapture", responder);
5646       }
5647     } else {
5648       var actualEventName = _getDOMEventName(eventName);
5649
5650       if (element.addEventListener)
5651         element.addEventListener(actualEventName, responder, false);
5652       else
5653         element.attachEvent("on" + actualEventName, responder);
5654     }
5655
5656     return element;
5657   }
5658
5659   function stopObserving(element, eventName, handler) {
5660     element = $(element);
5661
5662     var registry = Element.retrieve(element, 'prototype_event_registry');
5663     if (!registry) return element;
5664
5665     if (!eventName) {
5666       registry.each( function(pair) {
5667         var eventName = pair.key;
5668         stopObserving(element, eventName);
5669       });
5670       return element;
5671     }
5672
5673     var responders = registry.get(eventName);
5674     if (!responders) return element;
5675
5676     if (!handler) {
5677       responders.each(function(r) {
5678         stopObserving(element, eventName, r.handler);
5679       });
5680       return element;
5681     }
5682
5683     var i = responders.length, responder;
5684     while (i--) {
5685       if (responders[i].handler === handler) {
5686         responder = responders[i];
5687         break;
5688       }
5689     }
5690     if (!responder) return element;
5691
5692     if (eventName.include(':')) {
5693       if (element.removeEventListener)
5694         element.removeEventListener("dataavailable", responder, false);
5695       else {
5696         element.detachEvent("ondataavailable", responder);
5697         element.detachEvent("onlosecapture", responder);
5698       }
5699     } else {
5700       var actualEventName = _getDOMEventName(eventName);
5701       if (element.removeEventListener)
5702         element.removeEventListener(actualEventName, responder, false);
5703       else
5704         element.detachEvent('on' + actualEventName, responder);
5705     }
5706
5707     registry.set(eventName, responders.without(responder));
5708
5709     return element;
5710   }
5711
5712   function fire(element, eventName, memo, bubble) {
5713     element = $(element);
5714
5715     if (Object.isUndefined(bubble))
5716       bubble = true;
5717
5718     if (element == document && document.createEvent && !element.dispatchEvent)
5719       element = document.documentElement;
5720
5721     var event;
5722     if (document.createEvent) {
5723       event = document.createEvent('HTMLEvents');
5724       event.initEvent('dataavailable', bubble, true);
5725     } else {
5726       event = document.createEventObject();
5727       event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
5728     }
5729
5730     event.eventName = eventName;
5731     event.memo = memo || { };
5732
5733     if (document.createEvent)
5734       element.dispatchEvent(event);
5735     else
5736       element.fireEvent(event.eventType, event);
5737
5738     return Event.extend(event);
5739   }
5740
5741   Event.Handler = Class.create({
5742     initialize: function(element, eventName, selector, callback) {
5743       this.element   = $(element);
5744       this.eventName = eventName;
5745       this.selector  = selector;
5746       this.callback  = callback;
5747       this.handler   = this.handleEvent.bind(this);
5748     },
5749
5750     start: function() {
5751       Event.observe(this.element, this.eventName, this.handler);
5752       return this;
5753     },
5754
5755     stop: function() {
5756       Event.stopObserving(this.element, this.eventName, this.handler);
5757       return this;
5758     },
5759
5760     handleEvent: function(event) {
5761       var element = Event.findElement(event, this.selector);
5762       if (element) this.callback.call(this.element, event, element);
5763     }
5764   });
5765
5766   function on(element, eventName, selector, callback) {
5767     element = $(element);
5768     if (Object.isFunction(selector) && Object.isUndefined(callback)) {
5769       callback = selector, selector = null;
5770     }
5771
5772     return new Event.Handler(element, eventName, selector, callback).start();
5773   }
5774
5775   Object.extend(Event, Event.Methods);
5776
5777   Object.extend(Event, {
5778     fire:          fire,
5779     observe:       observe,
5780     stopObserving: stopObserving,
5781     on:            on
5782   });
5783
5784   Element.addMethods({
5785     fire:          fire,
5786
5787     observe:       observe,
5788
5789     stopObserving: stopObserving,
5790
5791     on:            on
5792   });
5793
5794   Object.extend(document, {
5795     fire:          fire.methodize(),
5796
5797     observe:       observe.methodize(),
5798
5799     stopObserving: stopObserving.methodize(),
5800
5801     on:            on.methodize(),
5802
5803     loaded:        false
5804   });
5805
5806   if (window.Event) Object.extend(window.Event, Event);
5807   else window.Event = Event;
5808 })();
5809
5810 (function() {
5811   /* Support for the DOMContentLoaded event is based on work by Dan Webb,
5812      Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
5813
5814   var timer;
5815
5816   function fireContentLoadedEvent() {
5817     if (document.loaded) return;
5818     if (timer) window.clearTimeout(timer);
5819     document.loaded = true;
5820     document.fire('dom:loaded');
5821   }
5822
5823   function checkReadyState() {
5824     if (document.readyState === 'complete') {
5825       document.stopObserving('readystatechange', checkReadyState);
5826       fireContentLoadedEvent();
5827     }
5828   }
5829
5830   function pollDoScroll() {
5831     try { document.documentElement.doScroll('left'); }
5832     catch(e) {
5833       timer = pollDoScroll.defer();
5834       return;
5835     }
5836     fireContentLoadedEvent();
5837   }
5838
5839   if (document.addEventListener) {
5840     document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
5841   } else {
5842     document.observe('readystatechange', checkReadyState);
5843     if (window == top)
5844       timer = pollDoScroll.defer();
5845   }
5846
5847   Event.observe(window, 'load', fireContentLoadedEvent);
5848 })();
5849
5850 Element.addMethods();
5851
5852 /*------------------------------- DEPRECATED -------------------------------*/
5853
5854 Hash.toQueryString = Object.toQueryString;
5855
5856 var Toggle = { display: Element.toggle };
5857
5858 Element.Methods.childOf = Element.Methods.descendantOf;
5859
5860 var Insertion = {
5861   Before: function(element, content) {
5862     return Element.insert(element, {before:content});
5863   },
5864
5865   Top: function(element, content) {
5866     return Element.insert(element, {top:content});
5867   },
5868
5869   Bottom: function(element, content) {
5870     return Element.insert(element, {bottom:content});
5871   },
5872
5873   After: function(element, content) {
5874     return Element.insert(element, {after:content});
5875   }
5876 };
5877
5878 var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
5879
5880 var Position = {
5881   includeScrollOffsets: false,
5882
5883   prepare: function() {
5884     this.deltaX =  window.pageXOffset
5885                 || document.documentElement.scrollLeft
5886                 || document.body.scrollLeft
5887                 || 0;
5888     this.deltaY =  window.pageYOffset
5889                 || document.documentElement.scrollTop
5890                 || document.body.scrollTop
5891                 || 0;
5892   },
5893
5894   within: function(element, x, y) {
5895     if (this.includeScrollOffsets)
5896       return this.withinIncludingScrolloffsets(element, x, y);
5897     this.xcomp = x;
5898     this.ycomp = y;
5899     this.offset = Element.cumulativeOffset(element);
5900
5901     return (y >= this.offset[1] &&
5902             y <  this.offset[1] + element.offsetHeight &&
5903             x >= this.offset[0] &&
5904             x <  this.offset[0] + element.offsetWidth);
5905   },
5906
5907   withinIncludingScrolloffsets: function(element, x, y) {
5908     var offsetcache = Element.cumulativeScrollOffset(element);
5909
5910     this.xcomp = x + offsetcache[0] - this.deltaX;
5911     this.ycomp = y + offsetcache[1] - this.deltaY;
5912     this.offset = Element.cumulativeOffset(element);
5913
5914     return (this.ycomp >= this.offset[1] &&
5915             this.ycomp <  this.offset[1] + element.offsetHeight &&
5916             this.xcomp >= this.offset[0] &&
5917             this.xcomp <  this.offset[0] + element.offsetWidth);
5918   },
5919
5920   overlap: function(mode, element) {
5921     if (!mode) return 0;
5922     if (mode == 'vertical')
5923       return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
5924         element.offsetHeight;
5925     if (mode == 'horizontal')
5926       return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
5927         element.offsetWidth;
5928   },
5929
5930
5931   cumulativeOffset: Element.Methods.cumulativeOffset,
5932
5933   positionedOffset: Element.Methods.positionedOffset,
5934
5935   absolutize: function(element) {
5936     Position.prepare();
5937     return Element.absolutize(element);
5938   },
5939
5940   relativize: function(element) {
5941     Position.prepare();
5942     return Element.relativize(element);
5943   },
5944
5945   realOffset: Element.Methods.cumulativeScrollOffset,
5946
5947   offsetParent: Element.Methods.getOffsetParent,
5948
5949   page: Element.Methods.viewportOffset,
5950
5951   clone: function(source, target, options) {
5952     options = options || { };
5953     return Element.clonePosition(target, source, options);
5954   }
5955 };
5956
5957 /*--------------------------------------------------------------------------*/
5958
5959 if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
5960   function iter(name) {
5961     return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
5962   }
5963
5964   instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
5965   function(element, className) {
5966     className = className.toString().strip();
5967     var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
5968     return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
5969   } : function(element, className) {
5970     className = className.toString().strip();
5971     var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
5972     if (!classNames && !className) return elements;
5973
5974     var nodes = $(element).getElementsByTagName('*');
5975     className = ' ' + className + ' ';
5976
5977     for (var i = 0, child, cn; child = nodes[i]; i++) {
5978       if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
5979           (classNames && classNames.all(function(name) {
5980             return !name.toString().blank() && cn.include(' ' + name + ' ');
5981           }))))
5982         elements.push(Element.extend(child));
5983     }
5984     return elements;
5985   };
5986
5987   return function(className, parentElement) {
5988     return $(parentElement || document.body).getElementsByClassName(className);
5989   };
5990 }(Element.Methods);
5991
5992 /*--------------------------------------------------------------------------*/
5993
5994 Element.ClassNames = Class.create();
5995 Element.ClassNames.prototype = {
5996   initialize: function(element) {
5997     this.element = $(element);
5998   },
5999
6000   _each: function(iterator) {
6001     this.element.className.split(/\s+/).select(function(name) {
6002       return name.length > 0;
6003     })._each(iterator);
6004   },
6005
6006   set: function(className) {
6007     this.element.className = className;
6008   },
6009
6010   add: function(classNameToAdd) {
6011     if (this.include(classNameToAdd)) return;
6012     this.set($A(this).concat(classNameToAdd).join(' '));
6013   },
6014
6015   remove: function(classNameToRemove) {
6016     if (!this.include(classNameToRemove)) return;
6017     this.set($A(this).without(classNameToRemove).join(' '));
6018   },
6019
6020   toString: function() {
6021     return $A(this).join(' ');
6022   }
6023 };
6024
6025 Object.extend(Element.ClassNames.prototype, Enumerable);
6026
6027 /*--------------------------------------------------------------------------*/
6028
6029 (function() {
6030   window.Selector = Class.create({
6031     initialize: function(expression) {
6032       this.expression = expression.strip();
6033     },
6034
6035     findElements: function(rootElement) {
6036       return Prototype.Selector.select(this.expression, rootElement);
6037     },
6038
6039     match: function(element) {
6040       return Prototype.Selector.match(element, this.expression);
6041     },
6042
6043     toString: function() {
6044       return this.expression;
6045     },
6046
6047     inspect: function() {
6048       return "#<Selector: " + this.expression + ">";
6049     }
6050   });
6051
6052   Object.extend(Selector, {
6053     matchElements: function(elements, expression) {
6054       var match = Prototype.Selector.match,
6055           results = [];
6056
6057       for (var i = 0, length = elements.length; i < length; i++) {
6058         var element = elements[i];
6059         if (match(element, expression)) {
6060           results.push(Element.extend(element));
6061         }
6062       }
6063       return results;
6064     },
6065
6066     findElement: function(elements, expression, index) {
6067       index = index || 0;
6068       var matchIndex = 0, element;
6069       for (var i = 0, length = elements.length; i < length; i++) {
6070         element = elements[i];
6071         if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
6072           return Element.extend(element);
6073         }
6074       }
6075     },
6076
6077     findChildElements: function(element, expressions) {
6078       var selector = expressions.toArray().join(', ');
6079       return Prototype.Selector.select(selector, element || document);
6080     }
6081   });
6082 })();