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,'&').replace(/</g,'<').replace(/>/g,'>');
617   }
618 
619   function unescapeHTML() {
620     return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/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       // SLA enable user/password
1522       if (('user' in this.options) && (this.options.user != null) &&
1523         ('password' in this.options) && (this.options.password != null)) {
1524           this.transport.open(this.method.toUpperCase(), this.url,
1525             this.options.asynchronous, this.options.user, this.options.password);
1526       } else {
1527           this.transport.open(this.method.toUpperCase(), this.url,
1528             this.options.asynchronous);
1529       }
1530 
1531       if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1532 
1533       this.transport.onreadystatechange = this.onStateChange.bind(this);
1534       this.setRequestHeaders();
1535 
1536       this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1537       this.transport.send(this.body);
1538 
1539       /* Force Firefox to handle ready state 4 for synchronous requests */
1540       if (!this.options.asynchronous && this.transport.overrideMimeType)
1541         this.onStateChange();
1542 
1543     }
1544     catch (e) {
1545       this.dispatchException(e);
1546     }
1547   },
1548 
1549   onStateChange: function() {
1550     var readyState = this.transport.readyState;
1551     if (readyState > 1 && !((readyState == 4) && this._complete))
1552       this.respondToReadyState(this.transport.readyState);
1553   },
1554 
1555   setRequestHeaders: function() {
1556     var headers = {
1557       'X-Requested-With': 'XMLHttpRequest',
1558       'X-Prototype-Version': Prototype.Version,
1559       'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1560     };
1561 
1562     if (this.method == 'post') {
1563       headers['Content-type'] = this.options.contentType +
1564         (this.options.encoding ? '; charset=' + this.options.encoding : '');
1565 
1566       /* Force "Connection: close" for older Mozilla browsers to work
1567        * around a bug where XMLHttpRequest sends an incorrect
1568        * Content-length header. See Mozilla Bugzilla #246651.
1569        */
1570       if (this.transport.overrideMimeType &&
1571           (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1572             headers['Connection'] = 'close';
1573     }
1574 
1575     if (typeof this.options.requestHeaders == 'object') {
1576       var extras = this.options.requestHeaders;
1577 
1578       if (Object.isFunction(extras.push))
1579         for (var i = 0, length = extras.length; i < length; i += 2)
1580           headers[extras[i]] = extras[i+1];
1581       else
1582         $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1583     }
1584 
1585     for (var name in headers)
1586       this.transport.setRequestHeader(name, headers[name]);
1587   },
1588 
1589   success: function() {
1590     var status = this.getStatus();
1591     return !status || (status >= 200 && status < 300) || status == 304;
1592   },
1593 
1594   getStatus: function() {
1595     try {
1596       if (this.transport.status === 1223) return 204;
1597       return this.transport.status || 0;
1598     } catch (e) { return 0 }
1599   },
1600 
1601   respondToReadyState: function(readyState) {
1602     var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
1603 
1604     if (state == 'Complete') {
1605       try {
1606         this._complete = true;
1607         (this.options['on' + response.status]
1608          || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1609          || Prototype.emptyFunction)(response, response.headerJSON);
1610       } catch (e) {
1611         this.dispatchException(e);
1612       }
1613 
1614       var contentType = response.getHeader('Content-type');
1615       if (this.options.evalJS == 'force'
1616           || (this.options.evalJS && this.isSameOrigin() && contentType
1617           && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1618         this.evalResponse();
1619     }
1620 
1621     try {
1622       (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1623       Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
1624     } catch (e) {
1625       this.dispatchException(e);
1626     }
1627 
1628     if (state == 'Complete') {
1629       this.transport.onreadystatechange = Prototype.emptyFunction;
1630     }
1631   },
1632 
1633   isSameOrigin: function() {
1634     var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1635     return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1636       protocol: location.protocol,
1637       domain: document.domain,
1638       port: location.port ? ':' + location.port : ''
1639     }));
1640   },
1641 
1642   getHeader: function(name) {
1643     try {
1644       return this.transport.getResponseHeader(name) || null;
1645     } catch (e) { return null; }
1646   },
1647 
1648   evalResponse: function() {
1649     try {
1650       return eval((this.transport.responseText || '').unfilterJSON());
1651     } catch (e) {
1652       this.dispatchException(e);
1653     }
1654   },
1655 
1656   dispatchException: function(exception) {
1657     (this.options.onException || Prototype.emptyFunction)(this, exception);
1658     Ajax.Responders.dispatch('onException', this, exception);
1659   }
1660 });
1661 
1662 Ajax.Request.Events =
1663   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1664 
1665 
1666 
1667 
1668 
1669 
1670 
1671 
1672 Ajax.Response = Class.create({
1673   initialize: function(request){
1674     this.request = request;
1675     var transport  = this.transport  = request.transport,
1676         readyState = this.readyState = transport.readyState;
1677 
1678     if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1679       this.status       = this.getStatus();
1680       this.statusText   = this.getStatusText();
1681       this.responseText = String.interpret(transport.responseText);
1682       this.headerJSON   = this._getHeaderJSON();
1683     }
1684 
1685     if (readyState == 4) {
1686       var xml = transport.responseXML;
1687       this.responseXML  = Object.isUndefined(xml) ? null : xml;
1688       this.responseJSON = this._getResponseJSON();
1689     }
1690   },
1691 
1692   status:      0,
1693 
1694   statusText: '',
1695 
1696   getStatus: Ajax.Request.prototype.getStatus,
1697 
1698   getStatusText: function() {
1699     try {
1700       return this.transport.statusText || '';
1701     } catch (e) { return '' }
1702   },
1703 
1704   getHeader: Ajax.Request.prototype.getHeader,
1705 
1706   getAllHeaders: function() {
1707     try {
1708       return this.getAllResponseHeaders();
1709     } catch (e) { return null }
1710   },
1711 
1712   getResponseHeader: function(name) {
1713     return this.transport.getResponseHeader(name);
1714   },
1715 
1716   getAllResponseHeaders: function() {
1717     return this.transport.getAllResponseHeaders();
1718   },
1719 
1720   _getHeaderJSON: function() {
1721     var json = this.getHeader('X-JSON');
1722     if (!json) return null;
1723     json = decodeURIComponent(escape(json));
1724     try {
1725       return json.evalJSON(this.request.options.sanitizeJSON ||
1726         !this.request.isSameOrigin());
1727     } catch (e) {
1728       this.request.dispatchException(e);
1729     }
1730   },
1731 
1732   _getResponseJSON: function() {
1733     var options = this.request.options;
1734     if (!options.evalJSON || (options.evalJSON != 'force' &&
1735       !(this.getHeader('Content-type') || '').include('application/json')) ||
1736         this.responseText.blank())
1737           return null;
1738     try {
1739       return this.responseText.evalJSON(options.sanitizeJSON ||
1740         !this.request.isSameOrigin());
1741     } catch (e) {
1742       this.request.dispatchException(e);
1743     }
1744   }
1745 });
1746 
1747 Ajax.Updater = Class.create(Ajax.Request, {
1748   initialize: function($super, container, url, options) {
1749     this.container = {
1750       success: (container.success || container),
1751       failure: (container.failure || (container.success ? null : container))
1752     };
1753 
1754     options = Object.clone(options);
1755     var onComplete = options.onComplete;
1756     options.onComplete = (function(response, json) {
1757       this.updateContent(response.responseText);
1758       if (Object.isFunction(onComplete)) onComplete(response, json);
1759     }).bind(this);
1760 
1761     $super(url, options);
1762   },
1763 
1764   updateContent: function(responseText) {
1765     var receiver = this.container[this.success() ? 'success' : 'failure'],
1766         options = this.options;
1767 
1768     if (!options.evalScripts) responseText = responseText.stripScripts();
1769 
1770     if (receiver = $(receiver)) {
1771       if (options.insertion) {
1772         if (Object.isString(options.insertion)) {
1773           var insertion = { }; insertion[options.insertion] = responseText;
1774           receiver.insert(insertion);
1775         }
1776         else options.insertion(receiver, responseText);
1777       }
1778       else receiver.update(responseText);
1779     }
1780   }
1781 });
1782 
1783 Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1784   initialize: function($super, container, url, options) {
1785     $super(options);
1786     this.onComplete = this.options.onComplete;
1787 
1788     this.frequency = (this.options.frequency || 2);
1789     this.decay = (this.options.decay || 1);
1790 
1791     this.updater = { };
1792     this.container = container;
1793     this.url = url;
1794 
1795     this.start();
1796   },
1797 
1798   start: function() {
1799     this.options.onComplete = this.updateComplete.bind(this);
1800     this.onTimerEvent();
1801   },
1802 
1803   stop: function() {
1804     this.updater.options.onComplete = undefined;
1805     clearTimeout(this.timer);
1806     (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1807   },
1808 
1809   updateComplete: function(response) {
1810     if (this.options.decay) {
1811       this.decay = (response.responseText == this.lastText ?
1812         this.decay * this.options.decay : 1);
1813 
1814       this.lastText = response.responseText;
1815     }
1816     this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
1817   },
1818 
1819   onTimerEvent: function() {
1820     this.updater = new Ajax.Updater(this.container, this.url, this.options);
1821   }
1822 });
1823 
1824 
1825 function $(element) {
1826   if (arguments.length > 1) {
1827     for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1828       elements.push($(arguments[i]));
1829     return elements;
1830   }
1831   if (Object.isString(element))
1832     element = document.getElementById(element);
1833   return Element.extend(element);
1834 }
1835 
1836 if (Prototype.BrowserFeatures.XPath) {
1837   document._getElementsByXPath = function(expression, parentElement) {
1838     var results = [];
1839     var query = document.evaluate(expression, $(parentElement) || document,
1840       null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1841     for (var i = 0, length = query.snapshotLength; i < length; i++)
1842       results.push(Element.extend(query.snapshotItem(i)));
1843     return results;
1844   };
1845 }
1846 
1847 /*--------------------------------------------------------------------------*/
1848 
1849 if (!Node) var Node = { };
1850 
1851 if (!Node.ELEMENT_NODE) {
1852   Object.extend(Node, {
1853     ELEMENT_NODE: 1,
1854     ATTRIBUTE_NODE: 2,
1855     TEXT_NODE: 3,
1856     CDATA_SECTION_NODE: 4,
1857     ENTITY_REFERENCE_NODE: 5,
1858     ENTITY_NODE: 6,
1859     PROCESSING_INSTRUCTION_NODE: 7,
1860     COMMENT_NODE: 8,
1861     DOCUMENT_NODE: 9,
1862     DOCUMENT_TYPE_NODE: 10,
1863     DOCUMENT_FRAGMENT_NODE: 11,
1864     NOTATION_NODE: 12
1865   });
1866 }
1867 
1868 
1869 
1870 (function(global) {
1871   function shouldUseCache(tagName, attributes) {
1872     if (tagName === 'select') return false;
1873     if ('type' in attributes) return false;
1874     return true;
1875   }
1876 
1877   var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
1878     try {
1879       var el = document.createElement('<input name="x">');
1880       return el.tagName.toLowerCase() === 'input' && el.name === 'x';
1881     }
1882     catch(err) {
1883       return false;
1884     }
1885   })();
1886 
1887   var element = global.Element;
1888 
1889   global.Element = function(tagName, attributes) {
1890     attributes = attributes || { };
1891     tagName = tagName.toLowerCase();
1892     var cache = Element.cache;
1893 
1894     if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
1895       tagName = '<' + tagName + ' name="' + attributes.name + '">';
1896       delete attributes.name;
1897       return Element.writeAttribute(document.createElement(tagName), attributes);
1898     }
1899 
1900     if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
1901 
1902     var node = shouldUseCache(tagName, attributes) ?
1903      cache[tagName].cloneNode(false) : document.createElement(tagName);
1904 
1905     return Element.writeAttribute(node, attributes);
1906   };
1907 
1908   Object.extend(global.Element, element || { });
1909   if (element) global.Element.prototype = element.prototype;
1910 
1911 })(this);
1912 
1913 Element.idCounter = 1;
1914 Element.cache = { };
1915 
1916 Element._purgeElement = function(element) {
1917   var uid = element._prototypeUID;
1918   if (uid) {
1919     Element.stopObserving(element);
1920     element._prototypeUID = void 0;
1921     delete Element.Storage[uid];
1922   }
1923 }
1924 
1925 Element.Methods = {
1926   visible: function(element) {
1927     return $(element).style.display != 'none';
1928   },
1929 
1930   toggle: function(element) {
1931     element = $(element);
1932     Element[Element.visible(element) ? 'hide' : 'show'](element);
1933     return element;
1934   },
1935 
1936   hide: function(element) {
1937     element = $(element);
1938     element.style.display = 'none';
1939     return element;
1940   },
1941 
1942   show: function(element) {
1943     element = $(element);
1944     element.style.display = '';
1945     return element;
1946   },
1947 
1948   remove: function(element) {
1949     element = $(element);
1950     element.parentNode.removeChild(element);
1951     return element;
1952   },
1953 
1954   update: (function(){
1955 
1956     var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
1957       var el = document.createElement("select"),
1958           isBuggy = true;
1959       el.innerHTML = "<option value=\"test\">test</option>";
1960       if (el.options && el.options[0]) {
1961         isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
1962       }
1963       el = null;
1964       return isBuggy;
1965     })();
1966 
1967     var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
1968       try {
1969         var el = document.createElement("table");
1970         if (el && el.tBodies) {
1971           el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
1972           var isBuggy = typeof el.tBodies[0] == "undefined";
1973           el = null;
1974           return isBuggy;
1975         }
1976       } catch (e) {
1977         return true;
1978       }
1979     })();
1980 
1981     var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
1982       try {
1983         var el = document.createElement('div');
1984         el.innerHTML = "<link>";
1985         var isBuggy = (el.childNodes.length === 0);
1986         el = null;
1987         return isBuggy;
1988       } catch(e) {
1989         return true;
1990       }
1991     })();
1992 
1993     var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
1994      TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
1995 
1996     var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
1997       var s = document.createElement("script"),
1998           isBuggy = false;
1999       try {
2000         s.appendChild(document.createTextNode(""));
2001         isBuggy = !s.firstChild ||
2002           s.firstChild && s.firstChild.nodeType !== 3;
2003       } catch (e) {
2004         isBuggy = true;
2005       }
2006       s = null;
2007       return isBuggy;
2008     })();
2009 
2010 
2011     function update(element, content) {
2012       element = $(element);
2013       var purgeElement = Element._purgeElement;
2014 
2015       var descendants = element.getElementsByTagName('*'),
2016        i = descendants.length;
2017       while (i--) purgeElement(descendants[i]);
2018 
2019       if (content && content.toElement)
2020         content = content.toElement();
2021 
2022       if (Object.isElement(content))
2023         return element.update().insert(content);
2024 
2025       content = Object.toHTML(content);
2026 
2027       var tagName = element.tagName.toUpperCase();
2028 
2029       if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
2030         element.text = content;
2031         return element;
2032       }
2033 
2034       if (ANY_INNERHTML_BUGGY) {
2035         if (tagName in Element._insertionTranslations.tags) {
2036           while (element.firstChild) {
2037             element.removeChild(element.firstChild);
2038           }
2039           Element._getContentFromAnonymousElement(tagName, content.stripScripts())
2040             .each(function(node) {
2041               element.appendChild(node)
2042             });
2043         } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
2044           while (element.firstChild) {
2045             element.removeChild(element.firstChild);
2046           }
2047           var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true);
2048           nodes.each(function(node) { element.appendChild(node) });
2049         }
2050         else {
2051           element.innerHTML = content.stripScripts();
2052         }
2053       }
2054       else {
2055         element.innerHTML = content.stripScripts();
2056       }
2057 
2058       content.evalScripts.bind(content).defer();
2059       return element;
2060     }
2061 
2062     return update;
2063   })(),
2064 
2065   replace: function(element, content) {
2066     element = $(element);
2067     if (content && content.toElement) content = content.toElement();
2068     else if (!Object.isElement(content)) {
2069       content = Object.toHTML(content);
2070       var range = element.ownerDocument.createRange();
2071       range.selectNode(element);
2072       content.evalScripts.bind(content).defer();
2073       content = range.createContextualFragment(content.stripScripts());
2074     }
2075     element.parentNode.replaceChild(content, element);
2076     return element;
2077   },
2078 
2079   insert: function(element, insertions) {
2080     element = $(element);
2081 
2082     if (Object.isString(insertions) || Object.isNumber(insertions) ||
2083         Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
2084           insertions = {bottom:insertions};
2085 
2086     var content, insert, tagName, childNodes;
2087 
2088     for (var position in insertions) {
2089       content  = insertions[position];
2090       position = position.toLowerCase();
2091       insert = Element._insertionTranslations[position];
2092 
2093       if (content && content.toElement) content = content.toElement();
2094       if (Object.isElement(content)) {
2095         insert(element, content);
2096         continue;
2097       }
2098 
2099       content = Object.toHTML(content);
2100 
2101       tagName = ((position == 'before' || position == 'after')
2102         ? element.parentNode : element).tagName.toUpperCase();
2103 
2104       childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2105 
2106       if (position == 'top' || position == 'after') childNodes.reverse();
2107       childNodes.each(insert.curry(element));
2108 
2109       content.evalScripts.bind(content).defer();
2110     }
2111 
2112     return element;
2113   },
2114 
2115   wrap: function(element, wrapper, attributes) {
2116     element = $(element);
2117     if (Object.isElement(wrapper))
2118       $(wrapper).writeAttribute(attributes || { });
2119     else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
2120     else wrapper = new Element('div', wrapper);
2121     if (element.parentNode)
2122       element.parentNode.replaceChild(wrapper, element);
2123     wrapper.appendChild(element);
2124     return wrapper;
2125   },
2126 
2127   inspect: function(element) {
2128     element = $(element);
2129     var result = '<' + element.tagName.toLowerCase();
2130     $H({'id': 'id', 'className': 'class'}).each(function(pair) {
2131       var property = pair.first(),
2132           attribute = pair.last(),
2133           value = (element[property] || '').toString();
2134       if (value) result += ' ' + attribute + '=' + value.inspect(true);
2135     });
2136     return result + '>';
2137   },
2138 
2139   recursivelyCollect: function(element, property, maximumLength) {
2140     element = $(element);
2141     maximumLength = maximumLength || -1;
2142     var elements = [];
2143 
2144     while (element = element[property]) {
2145       if (element.nodeType == 1)
2146         elements.push(Element.extend(element));
2147       if (elements.length == maximumLength)
2148         break;
2149     }
2150 
2151     return elements;
2152   },
2153 
2154   ancestors: function(element) {
2155     return Element.recursivelyCollect(element, 'parentNode');
2156   },
2157 
2158   descendants: function(element) {
2159     return Element.select(element, "*");
2160   },
2161 
2162   firstDescendant: function(element) {
2163     element = $(element).firstChild;
2164     while (element && element.nodeType != 1) element = element.nextSibling;
2165     return $(element);
2166   },
2167 
2168   immediateDescendants: function(element) {
2169     var results = [], child = $(element).firstChild;
2170     while (child) {
2171       if (child.nodeType === 1) {
2172         results.push(Element.extend(child));
2173       }
2174       child = child.nextSibling;
2175     }
2176     return results;
2177   },
2178 
2179   previousSiblings: function(element, maximumLength) {
2180     return Element.recursivelyCollect(element, 'previousSibling');
2181   },
2182 
2183   nextSiblings: function(element) {
2184     return Element.recursivelyCollect(element, 'nextSibling');
2185   },
2186 
2187   siblings: function(element) {
2188     element = $(element);
2189     return Element.previousSiblings(element).reverse()
2190       .concat(Element.nextSiblings(element));
2191   },
2192 
2193   match: function(element, selector) {
2194     element = $(element);
2195     if (Object.isString(selector))
2196       return Prototype.Selector.match(element, selector);
2197     return selector.match(element);
2198   },
2199 
2200   up: function(element, expression, index) {
2201     element = $(element);
2202     if (arguments.length == 1) return $(element.parentNode);
2203     var ancestors = Element.ancestors(element);
2204     return Object.isNumber(expression) ? ancestors[expression] :
2205       Prototype.Selector.find(ancestors, expression, index);
2206   },
2207 
2208   down: function(element, expression, index) {
2209     element = $(element);
2210     if (arguments.length == 1) return Element.firstDescendant(element);
2211     return Object.isNumber(expression) ? Element.descendants(element)[expression] :
2212       Element.select(element, expression)[index || 0];
2213   },
2214 
2215   previous: function(element, expression, index) {
2216     element = $(element);
2217     if (Object.isNumber(expression)) index = expression, expression = false;
2218     if (!Object.isNumber(index)) index = 0;
2219 
2220     if (expression) {
2221       return Prototype.Selector.find(element.previousSiblings(), expression, index);
2222     } else {
2223       return element.recursivelyCollect("previousSibling", index + 1)[index];
2224     }
2225   },
2226 
2227   next: function(element, expression, index) {
2228     element = $(element);
2229     if (Object.isNumber(expression)) index = expression, expression = false;
2230     if (!Object.isNumber(index)) index = 0;
2231 
2232     if (expression) {
2233       return Prototype.Selector.find(element.nextSiblings(), expression, index);
2234     } else {
2235       var maximumLength = Object.isNumber(index) ? index + 1 : 1;
2236       return element.recursivelyCollect("nextSibling", index + 1)[index];
2237     }
2238   },
2239 
2240 
2241   select: function(element) {
2242     element = $(element);
2243     var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
2244     return Prototype.Selector.select(expressions, element);
2245   },
2246 
2247   adjacent: function(element) {
2248     element = $(element);
2249     var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
2250     return Prototype.Selector.select(expressions, element.parentNode).without(element);
2251   },
2252 
2253   identify: function(element) {
2254     element = $(element);
2255     var id = Element.readAttribute(element, 'id');
2256     if (id) return id;
2257     do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
2258     Element.writeAttribute(element, 'id', id);
2259     return id;
2260   },
2261 
2262   readAttribute: function(element, name) {
2263     element = $(element);
2264     if (Prototype.Browser.IE) {
2265       var t = Element._attributeTranslations.read;
2266       if (t.values[name]) return t.values[name](element, name);
2267       if (t.names[name]) name = t.names[name];
2268       if (name.include(':')) {
2269         return (!element.attributes || !element.attributes[name]) ? null :
2270          element.attributes[name].value;
2271       }
2272     }
2273     return element.getAttribute(name);
2274   },
2275 
2276   writeAttribute: function(element, name, value) {
2277     element = $(element);
2278     var attributes = { }, t = Element._attributeTranslations.write;
2279 
2280     if (typeof name == 'object') attributes = name;
2281     else attributes[name] = Object.isUndefined(value) ? true : value;
2282 
2283     for (var attr in attributes) {
2284       name = t.names[attr] || attr;
2285       value = attributes[attr];
2286       if (t.values[attr]) name = t.values[attr](element, value);
2287       if (value === false || value === null)
2288         element.removeAttribute(name);
2289       else if (value === true)
2290         element.setAttribute(name, name);
2291       else element.setAttribute(name, value);
2292     }
2293     return element;
2294   },
2295 
2296   getHeight: function(element) {
2297     return Element.getDimensions(element).height;
2298   },
2299 
2300   getWidth: function(element) {
2301     return Element.getDimensions(element).width;
2302   },
2303 
2304   classNames: function(element) {
2305     return new Element.ClassNames(element);
2306   },
2307 
2308   hasClassName: function(element, className) {
2309     if (!(element = $(element))) return;
2310     var elementClassName = element.className;
2311     return (elementClassName.length > 0 && (elementClassName == className ||
2312       new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
2313   },
2314 
2315   addClassName: function(element, className) {
2316     if (!(element = $(element))) return;
2317     if (!Element.hasClassName(element, className))
2318       element.className += (element.className ? ' ' : '') + className;
2319     return element;
2320   },
2321 
2322   removeClassName: function(element, className) {
2323     if (!(element = $(element))) return;
2324     element.className = element.className.replace(
2325       new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
2326     return element;
2327   },
2328 
2329   toggleClassName: function(element, className) {
2330     if (!(element = $(element))) return;
2331     return Element[Element.hasClassName(element, className) ?
2332       'removeClassName' : 'addClassName'](element, className);
2333   },
2334 
2335   cleanWhitespace: function(element) {
2336     element = $(element);
2337     var node = element.firstChild;
2338     while (node) {
2339       var nextNode = node.nextSibling;
2340       if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
2341         element.removeChild(node);
2342       node = nextNode;
2343     }
2344     return element;
2345   },
2346 
2347   empty: function(element) {
2348     return $(element).innerHTML.blank();
2349   },
2350 
2351   descendantOf: function(element, ancestor) {
2352     element = $(element), ancestor = $(ancestor);
2353 
2354     if (element.compareDocumentPosition)
2355       return (element.compareDocumentPosition(ancestor) & 8) === 8;
2356 
2357     if (ancestor.contains)
2358       return ancestor.contains(element) && ancestor !== element;
2359 
2360     while (element = element.parentNode)
2361       if (element == ancestor) return true;
2362 
2363     return false;
2364   },
2365 
2366   scrollTo: function(element) {
2367     element = $(element);
2368     var pos = Element.cumulativeOffset(element);
2369     window.scrollTo(pos[0], pos[1]);
2370     return element;
2371   },
2372 
2373   getStyle: function(element, style) {
2374     element = $(element);
2375     style = style == 'float' ? 'cssFloat' : style.camelize();
2376     var value = element.style[style];
2377     if (!value || value == 'auto') {
2378       var css = document.defaultView.getComputedStyle(element, null);
2379       value = css ? css[style] : null;
2380     }
2381     if (style == 'opacity') return value ? parseFloat(value) : 1.0;
2382     return value == 'auto' ? null : value;
2383   },
2384 
2385   getOpacity: function(element) {
2386     return $(element).getStyle('opacity');
2387   },
2388 
2389   setStyle: function(element, styles) {
2390     element = $(element);
2391     var elementStyle = element.style, match;
2392     if (Object.isString(styles)) {
2393       element.style.cssText += ';' + styles;
2394       return styles.include('opacity') ?
2395         element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
2396     }
2397     for (var property in styles)
2398       if (property == 'opacity') element.setOpacity(styles[property]);
2399       else
2400         elementStyle[(property == 'float' || property == 'cssFloat') ?
2401           (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
2402             property] = styles[property];
2403 
2404     return element;
2405   },
2406 
2407   setOpacity: function(element, value) {
2408     element = $(element);
2409     element.style.opacity = (value == 1 || value === '') ? '' :
2410       (value < 0.00001) ? 0 : value;
2411     return element;
2412   },
2413 
2414   makePositioned: function(element) {
2415     element = $(element);
2416     var pos = Element.getStyle(element, 'position');
2417     if (pos == 'static' || !pos) {
2418       element._madePositioned = true;
2419       element.style.position = 'relative';
2420       if (Prototype.Browser.Opera) {
2421         element.style.top = 0;
2422         element.style.left = 0;
2423       }
2424     }
2425     return element;
2426   },
2427 
2428   undoPositioned: function(element) {
2429     element = $(element);
2430     if (element._madePositioned) {
2431       element._madePositioned = undefined;
2432       element.style.position =
2433         element.style.top =
2434         element.style.left =
2435         element.style.bottom =
2436         element.style.right = '';
2437     }
2438     return element;
2439   },
2440 
2441   makeClipping: function(element) {
2442     element = $(element);
2443     if (element._overflow) return element;
2444     element._overflow = Element.getStyle(element, 'overflow') || 'auto';
2445     if (element._overflow !== 'hidden')
2446       element.style.overflow = 'hidden';
2447     return element;
2448   },
2449 
2450   undoClipping: function(element) {
2451     element = $(element);
2452     if (!element._overflow) return element;
2453     element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
2454     element._overflow = null;
2455     return element;
2456   },
2457 
2458   clonePosition: function(element, source) {
2459     var options = Object.extend({
2460       setLeft:    true,
2461       setTop:     true,
2462       setWidth:   true,
2463       setHeight:  true,
2464       offsetTop:  0,
2465       offsetLeft: 0
2466     }, arguments[2] || { });
2467 
2468     source = $(source);
2469     var p = Element.viewportOffset(source), delta = [0, 0], parent = null;
2470 
2471     element = $(element);
2472 
2473     if (Element.getStyle(element, 'position') == 'absolute') {
2474       parent = Element.getOffsetParent(element);
2475       delta = Element.viewportOffset(parent);
2476     }
2477 
2478     if (parent == document.body) {
2479       delta[0] -= document.body.offsetLeft;
2480       delta[1] -= document.body.offsetTop;
2481     }
2482 
2483     if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
2484     if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
2485     if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
2486     if (options.setHeight) element.style.height = source.offsetHeight + 'px';
2487     return element;
2488   }
2489 };
2490 
2491 Object.extend(Element.Methods, {
2492   getElementsBySelector: Element.Methods.select,
2493 
2494   childElements: Element.Methods.immediateDescendants
2495 });
2496 
2497 Element._attributeTranslations = {
2498   write: {
2499     names: {
2500       className: 'class',
2501       htmlFor:   'for'
2502     },
2503     values: { }
2504   }
2505 };
2506 
2507 if (Prototype.Browser.Opera) {
2508   Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2509     function(proceed, element, style) {
2510       switch (style) {
2511         case 'height': case 'width':
2512           if (!Element.visible(element)) return null;
2513 
2514           var dim = parseInt(proceed(element, style), 10);
2515 
2516           if (dim !== element['offset' + style.capitalize()])
2517             return dim + 'px';
2518 
2519           var properties;
2520           if (style === 'height') {
2521             properties = ['border-top-width', 'padding-top',
2522              'padding-bottom', 'border-bottom-width'];
2523           }
2524           else {
2525             properties = ['border-left-width', 'padding-left',
2526              'padding-right', 'border-right-width'];
2527           }
2528           return properties.inject(dim, function(memo, property) {
2529             var val = proceed(element, property);
2530             return val === null ? memo : memo - parseInt(val, 10);
2531           }) + 'px';
2532         default: return proceed(element, style);
2533       }
2534     }
2535   );
2536 
2537   Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2538     function(proceed, element, attribute) {
2539       if (attribute === 'title') return element.title;
2540       return proceed(element, attribute);
2541     }
2542   );
2543 }
2544 
2545 else if (Prototype.Browser.IE) {
2546   Element.Methods.getStyle = function(element, style) {
2547     element = $(element);
2548     style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2549     var value = element.style[style];
2550     if (!value && element.currentStyle) value = element.currentStyle[style];
2551 
2552     if (style == 'opacity') {
2553       if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
2554         if (value[1]) return parseFloat(value[1]) / 100;
2555       return 1.0;
2556     }
2557 
2558     if (value == 'auto') {
2559       if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
2560         return element['offset' + style.capitalize()] + 'px';
2561       return null;
2562     }
2563     return value;
2564   };
2565 
2566   Element.Methods.setOpacity = function(element, value) {
2567     function stripAlpha(filter){
2568       return filter.replace(/alpha\([^\)]*\)/gi,'');
2569     }
2570     element = $(element);
2571     var currentStyle = element.currentStyle;
2572     if ((currentStyle && !currentStyle.hasLayout) ||
2573       (!currentStyle && element.style.zoom == 'normal'))
2574         element.style.zoom = 1;
2575 
2576     var filter = element.getStyle('filter'), style = element.style;
2577     if (value == 1 || value === '') {
2578       (filter = stripAlpha(filter)) ?
2579         style.filter = filter : style.removeAttribute('filter');
2580       return element;
2581     } else if (value < 0.00001) value = 0;
2582     style.filter = stripAlpha(filter) +
2583       'alpha(opacity=' + (value * 100) + ')';
2584     return element;
2585   };
2586 
2587   Element._attributeTranslations = (function(){
2588 
2589     var classProp = 'className',
2590         forProp = 'for',
2591         el = document.createElement('div');
2592 
2593     el.setAttribute(classProp, 'x');
2594 
2595     if (el.className !== 'x') {
2596       el.setAttribute('class', 'x');
2597       if (el.className === 'x') {
2598         classProp = 'class';
2599       }
2600     }
2601     el = null;
2602 
2603     el = document.createElement('label');
2604     el.setAttribute(forProp, 'x');
2605     if (el.htmlFor !== 'x') {
2606       el.setAttribute('htmlFor', 'x');
2607       if (el.htmlFor === 'x') {
2608         forProp = 'htmlFor';
2609       }
2610     }
2611     el = null;
2612 
2613     return {
2614       read: {
2615         names: {
2616           'class':      classProp,
2617           'className':  classProp,
2618           'for':        forProp,
2619           'htmlFor':    forProp
2620         },
2621         values: {
2622           _getAttr: function(element, attribute) {
2623             return element.getAttribute(attribute);
2624           },
2625           _getAttr2: function(element, attribute) {
2626             return element.getAttribute(attribute, 2);
2627           },
2628           _getAttrNode: function(element, attribute) {
2629             var node = element.getAttributeNode(attribute);
2630             return node ? node.value : "";
2631           },
2632           _getEv: (function(){
2633 
2634             var el = document.createElement('div'), f;
2635             el.onclick = Prototype.emptyFunction;
2636             var value = el.getAttribute('onclick');
2637 
2638             if (String(value).indexOf('{') > -1) {
2639               f = function(element, attribute) {
2640                 attribute = element.getAttribute(attribute);
2641                 if (!attribute) return null;
2642                 attribute = attribute.toString();
2643                 attribute = attribute.split('{')[1];
2644                 attribute = attribute.split('}')[0];
2645                 return attribute.strip();
2646               };
2647             }
2648             else if (value === '') {
2649               f = function(element, attribute) {
2650                 attribute = element.getAttribute(attribute);
2651                 if (!attribute) return null;
2652                 return attribute.strip();
2653               };
2654             }
2655             el = null;
2656             return f;
2657           })(),
2658           _flag: function(element, attribute) {
2659             return $(element).hasAttribute(attribute) ? attribute : null;
2660           },
2661           style: function(element) {
2662             return element.style.cssText.toLowerCase();
2663           },
2664           title: function(element) {
2665             return element.title;
2666           }
2667         }
2668       }
2669     }
2670   })();
2671 
2672   Element._attributeTranslations.write = {
2673     names: Object.extend({
2674       cellpadding: 'cellPadding',
2675       cellspacing: 'cellSpacing'
2676     }, Element._attributeTranslations.read.names),
2677     values: {
2678       checked: function(element, value) {
2679         element.checked = !!value;
2680       },
2681 
2682       style: function(element, value) {
2683         element.style.cssText = value ? value : '';
2684       }
2685     }
2686   };
2687 
2688   Element._attributeTranslations.has = {};
2689 
2690   $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2691       'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
2692     Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2693     Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2694   });
2695 
2696   (function(v) {
2697     Object.extend(v, {
2698       href:        v._getAttr2,
2699       src:         v._getAttr2,
2700       type:        v._getAttr,
2701       action:      v._getAttrNode,
2702       disabled:    v._flag,
2703       checked:     v._flag,
2704       readonly:    v._flag,
2705       multiple:    v._flag,
2706       onload:      v._getEv,
2707       onunload:    v._getEv,
2708       onclick:     v._getEv,
2709       ondblclick:  v._getEv,
2710       onmousedown: v._getEv,
2711       onmouseup:   v._getEv,
2712       onmouseover: v._getEv,
2713       onmousemove: v._getEv,
2714       onmouseout:  v._getEv,
2715       onfocus:     v._getEv,
2716       onblur:      v._getEv,
2717       onkeypress:  v._getEv,
2718       onkeydown:   v._getEv,
2719       onkeyup:     v._getEv,
2720       onsubmit:    v._getEv,
2721       onreset:     v._getEv,
2722       onselect:    v._getEv,
2723       onchange:    v._getEv
2724     });
2725   })(Element._attributeTranslations.read.values);
2726 
2727   if (Prototype.BrowserFeatures.ElementExtensions) {
2728     (function() {
2729       function _descendants(element) {
2730         var nodes = element.getElementsByTagName('*'), results = [];
2731         for (var i = 0, node; node = nodes[i]; i++)
2732           if (node.tagName !== "!") // Filter out comment nodes.
2733             results.push(node);
2734         return results;
2735       }
2736 
2737       Element.Methods.down = function(element, expression, index) {
2738         element = $(element);
2739         if (arguments.length == 1) return element.firstDescendant();
2740         return Object.isNumber(expression) ? _descendants(element)[expression] :
2741           Element.select(element, expression)[index || 0];
2742       }
2743     })();
2744   }
2745 
2746 }
2747 
2748 else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
2749   Element.Methods.setOpacity = function(element, value) {
2750     element = $(element);
2751     element.style.opacity = (value == 1) ? 0.999999 :
2752       (value === '') ? '' : (value < 0.00001) ? 0 : value;
2753     return element;
2754   };
2755 }
2756 
2757 else if (Prototype.Browser.WebKit) {
2758   Element.Methods.setOpacity = function(element, value) {
2759     element = $(element);
2760     element.style.opacity = (value == 1 || value === '') ? '' :
2761       (value < 0.00001) ? 0 : value;
2762 
2763     if (value == 1)
2764       if (element.tagName.toUpperCase() == 'IMG' && element.width) {
2765         element.width++; element.width--;
2766       } else try {
2767         var n = document.createTextNode(' ');
2768         element.appendChild(n);
2769         element.removeChild(n);
2770       } catch (e) { }
2771 
2772     return element;
2773   };
2774 }
2775 
2776 if ('outerHTML' in document.documentElement) {
2777   Element.Methods.replace = function(element, content) {
2778     element = $(element);
2779 
2780     if (content && content.toElement) content = content.toElement();
2781     if (Object.isElement(content)) {
2782       element.parentNode.replaceChild(content, element);
2783       return element;
2784     }
2785 
2786     content = Object.toHTML(content);
2787     var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2788 
2789     if (Element._insertionTranslations.tags[tagName]) {
2790       var nextSibling = element.next(),
2791           fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2792       parent.removeChild(element);
2793       if (nextSibling)
2794         fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
2795       else
2796         fragments.each(function(node) { parent.appendChild(node) });
2797     }
2798     else element.outerHTML = content.stripScripts();
2799 
2800     content.evalScripts.bind(content).defer();
2801     return element;
2802   };
2803 }
2804 
2805 Element._returnOffset = function(l, t) {
2806   var result = [l, t];
2807   result.left = l;
2808   result.top = t;
2809   return result;
2810 };
2811 
2812 Element._getContentFromAnonymousElement = function(tagName, html, force) {
2813   var div = new Element('div'),
2814       t = Element._insertionTranslations.tags[tagName];
2815 
2816   var workaround = false;
2817   if (t) workaround = true;
2818   else if (force) {
2819     workaround = true;
2820     t = ['', '', 0];
2821   }
2822 
2823   if (workaround) {
2824     div.innerHTML = ' ' + t[0] + html + t[1];
2825     div.removeChild(div.firstChild);
2826     for (var i = t[2]; i--; ) {
2827       div = div.firstChild;
2828     }
2829   }
2830   else {
2831     div.innerHTML = html;
2832   }
2833   return $A(div.childNodes);
2834 };
2835 
2836 Element._insertionTranslations = {
2837   before: function(element, node) {
2838     element.parentNode.insertBefore(node, element);
2839   },
2840   top: function(element, node) {
2841     element.insertBefore(node, element.firstChild);
2842   },
2843   bottom: function(element, node) {
2844     element.appendChild(node);
2845   },
2846   after: function(element, node) {
2847     element.parentNode.insertBefore(node, element.nextSibling);
2848   },
2849   tags: {
2850     TABLE:  ['<table>',                '</table>',                   1],
2851     TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
2852     TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
2853     TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2854     SELECT: ['<select>',               '</select>',                  1]
2855   }
2856 };
2857 
2858 (function() {
2859   var tags = Element._insertionTranslations.tags;
2860   Object.extend(tags, {
2861     THEAD: tags.TBODY,
2862     TFOOT: tags.TBODY,
2863     TH:    tags.TD
2864   });
2865 })();
2866 
2867 Element.Methods.Simulated = {
2868   hasAttribute: function(element, attribute) {
2869     attribute = Element._attributeTranslations.has[attribute] || attribute;
2870     var node = $(element).getAttributeNode(attribute);
2871     return !!(node && node.specified);
2872   }
2873 };
2874 
2875 Element.Methods.ByTag = { };
2876 
2877 Object.extend(Element, Element.Methods);
2878 
2879 (function(div) {
2880 
2881   if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
2882     window.HTMLElement = { };
2883     window.HTMLElement.prototype = div['__proto__'];
2884     Prototype.BrowserFeatures.ElementExtensions = true;
2885   }
2886 
2887   div = null;
2888 
2889 })(document.createElement('div'));
2890 
2891 Element.extend = (function() {
2892 
2893   function checkDeficiency(tagName) {
2894     if (typeof window.Element != 'undefined') {
2895       var proto = window.Element.prototype;
2896       if (proto) {
2897         var id = '_' + (Math.random()+'').slice(2),
2898             el = document.createElement(tagName);
2899         proto[id] = 'x';
2900         var isBuggy = (el[id] !== 'x');
2901         delete proto[id];
2902         el = null;
2903         return isBuggy;
2904       }
2905     }
2906     return false;
2907   }
2908 
2909   function extendElementWith(element, methods) {
2910     for (var property in methods) {
2911       var value = methods[property];
2912       if (Object.isFunction(value) && !(property in element))
2913         element[property] = value.methodize();
2914     }
2915   }
2916 
2917   var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
2918 
2919   if (Prototype.BrowserFeatures.SpecificElementExtensions) {
2920     if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
2921       return function(element) {
2922         if (element && typeof element._extendedByPrototype == 'undefined') {
2923           var t = element.tagName;
2924           if (t && (/^(?:object|applet|embed)$/i.test(t))) {
2925             extendElementWith(element, Element.Methods);
2926             extendElementWith(element, Element.Methods.Simulated);
2927             extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
2928           }
2929         }
2930         return element;
2931       }
2932     }
2933     return Prototype.K;
2934   }
2935 
2936   var Methods = { }, ByTag = Element.Methods.ByTag;
2937 
2938   var extend = Object.extend(function(element) {
2939     if (!element || typeof element._extendedByPrototype != 'undefined' ||
2940         element.nodeType != 1 || element == window) return element;
2941 
2942     var methods = Object.clone(Methods),
2943         tagName = element.tagName.toUpperCase();
2944 
2945     if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
2946 
2947     extendElementWith(element, methods);
2948 
2949     element._extendedByPrototype = Prototype.emptyFunction;
2950     return element;
2951 
2952   }, {
2953     refresh: function() {
2954       if (!Prototype.BrowserFeatures.ElementExtensions) {
2955         Object.extend(Methods, Element.Methods);
2956         Object.extend(Methods, Element.Methods.Simulated);
2957       }
2958     }
2959   });
2960 
2961   extend.refresh();
2962   return extend;
2963 })();
2964 
2965 if (document.documentElement.hasAttribute) {
2966   Element.hasAttribute = function(element, attribute) {
2967     return element.hasAttribute(attribute);
2968   };
2969 }
2970 else {
2971   Element.hasAttribute = Element.Methods.Simulated.hasAttribute;
2972 }
2973 
2974 Element.addMethods = function(methods) {
2975   var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
2976 
2977   if (!methods) {
2978     Object.extend(Form, Form.Methods);
2979     Object.extend(Form.Element, Form.Element.Methods);
2980     Object.extend(Element.Methods.ByTag, {
2981       "FORM":     Object.clone(Form.Methods),
2982       "INPUT":    Object.clone(Form.Element.Methods),
2983       "SELECT":   Object.clone(Form.Element.Methods),
2984       "TEXTAREA": Object.clone(Form.Element.Methods),
2985       "BUTTON":   Object.clone(Form.Element.Methods)
2986     });
2987   }
2988 
2989   if (arguments.length == 2) {
2990     var tagName = methods;
2991     methods = arguments[1];
2992   }
2993 
2994   if (!tagName) Object.extend(Element.Methods, methods || { });
2995   else {
2996     if (Object.isArray(tagName)) tagName.each(extend);
2997     else extend(tagName);
2998   }
2999 
3000   function extend(tagName) {
3001     tagName = tagName.toUpperCase();
3002     if (!Element.Methods.ByTag[tagName])
3003       Element.Methods.ByTag[tagName] = { };
3004     Object.extend(Element.Methods.ByTag[tagName], methods);
3005   }
3006 
3007   function copy(methods, destination, onlyIfAbsent) {
3008     onlyIfAbsent = onlyIfAbsent || false;
3009     for (var property in methods) {
3010       var value = methods[property];
3011       if (!Object.isFunction(value)) continue;
3012       if (!onlyIfAbsent || !(property in destination))
3013         destination[property] = value.methodize();
3014     }
3015   }
3016 
3017   function findDOMClass(tagName) {
3018     var klass;
3019     var trans = {
3020       "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3021       "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3022       "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3023       "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3024       "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3025       "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3026       "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3027       "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3028       "FrameSet", "IFRAME": "IFrame"
3029     };
3030     if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
3031     if (window[klass]) return window[klass];
3032     klass = 'HTML' + tagName + 'Element';
3033     if (window[klass]) return window[klass];
3034     klass = 'HTML' + tagName.capitalize() + 'Element';
3035     if (window[klass]) return window[klass];
3036 
3037     var element = document.createElement(tagName),
3038         proto = element['__proto__'] || element.constructor.prototype;
3039 
3040     element = null;
3041     return proto;
3042   }
3043 
3044   var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
3045    Element.prototype;
3046 
3047   if (F.ElementExtensions) {
3048     copy(Element.Methods, elementPrototype);
3049     copy(Element.Methods.Simulated, elementPrototype, true);
3050   }
3051 
3052   if (F.SpecificElementExtensions) {
3053     for (var tag in Element.Methods.ByTag) {
3054       var klass = findDOMClass(tag);
3055       if (Object.isUndefined(klass)) continue;
3056       copy(T[tag], klass.prototype);
3057     }
3058   }
3059 
3060   Object.extend(Element, Element.Methods);
3061   delete Element.ByTag;
3062 
3063   if (Element.extend.refresh) Element.extend.refresh();
3064   Element.cache = { };
3065 };
3066 
3067 
3068 document.viewport = {
3069 
3070   getDimensions: function() {
3071     return { width: this.getWidth(), height: this.getHeight() };
3072   },
3073 
3074   getScrollOffsets: function() {
3075     return Element._returnOffset(
3076       window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
3077       window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);
3078   }
3079 };
3080 
3081 (function(viewport) {
3082   var B = Prototype.Browser, doc = document, element, property = {};
3083 
3084   function getRootElement() {
3085     if (B.WebKit && !doc.evaluate)
3086       return document;
3087 
3088     if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
3089       return document.body;
3090 
3091     return document.documentElement;
3092   }
3093 
3094   function define(D) {
3095     if (!element) element = getRootElement();
3096 
3097     property[D] = 'client' + D;
3098 
3099     viewport['get' + D] = function() { return element[property[D]] };
3100     return viewport['get' + D]();
3101   }
3102 
3103   viewport.getWidth  = define.curry('Width');
3104 
3105   viewport.getHeight = define.curry('Height');
3106 })(document.viewport);
3107 
3108 
3109 Element.Storage = {
3110   UID: 1
3111 };
3112 
3113 Element.addMethods({
3114   getStorage: function(element) {
3115     if (!(element = $(element))) return;
3116 
3117     var uid;
3118     if (element === window) {
3119       uid = 0;
3120     } else {
3121       if (typeof element._prototypeUID === "undefined")
3122         element._prototypeUID = Element.Storage.UID++;
3123       uid = element._prototypeUID;
3124     }
3125 
3126     if (!Element.Storage[uid])
3127       Element.Storage[uid] = $H();
3128 
3129     return Element.Storage[uid];
3130   },
3131 
3132   store: function(element, key, value) {
3133     if (!(element = $(element))) return;
3134 
3135     if (arguments.length === 2) {
3136       Element.getStorage(element).update(key);
3137     } else {
3138       Element.getStorage(element).set(key, value);
3139     }
3140 
3141     return element;
3142   },
3143 
3144   retrieve: function(element, key, defaultValue) {
3145     if (!(element = $(element))) return;
3146     var hash = Element.getStorage(element), value = hash.get(key);
3147 
3148     if (Object.isUndefined(value)) {
3149       hash.set(key, defaultValue);
3150       value = defaultValue;
3151     }
3152 
3153     return value;
3154   },
3155 
3156   clone: function(element, deep) {
3157     if (!(element = $(element))) return;
3158     var clone = element.cloneNode(deep);
3159     clone._prototypeUID = void 0;
3160     if (deep) {
3161       var descendants = Element.select(clone, '*'),
3162           i = descendants.length;
3163       while (i--) {
3164         descendants[i]._prototypeUID = void 0;
3165       }
3166     }
3167     return Element.extend(clone);
3168   },
3169 
3170   purge: function(element) {
3171     if (!(element = $(element))) return;
3172     var purgeElement = Element._purgeElement;
3173 
3174     purgeElement(element);
3175 
3176     var descendants = element.getElementsByTagName('*'),
3177      i = descendants.length;
3178 
3179     while (i--) purgeElement(descendants[i]);
3180 
3181     return null;
3182   }
3183 });
3184 
3185 (function() {
3186 
3187   function toDecimal(pctString) {
3188     var match = pctString.match(/^(\d+)%?$/i);
3189     if (!match) return null;
3190     return (Number(match[1]) / 100);
3191   }
3192 
3193   function getPixelValue(value, property, context) {
3194     var element = null;
3195     if (Object.isElement(value)) {
3196       element = value;
3197       value = element.getStyle(property);
3198     }
3199 
3200     if (value === null) {
3201       return null;
3202     }
3203 
3204     if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
3205       return window.parseFloat(value);
3206     }
3207 
3208     var isPercentage = value.include('%'), isViewport = (context === document.viewport);
3209 
3210     if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
3211       var style = element.style.left, rStyle = element.runtimeStyle.left;
3212       element.runtimeStyle.left = element.currentStyle.left;
3213       element.style.left = value || 0;
3214       value = element.style.pixelLeft;
3215       element.style.left = style;
3216       element.runtimeStyle.left = rStyle;
3217 
3218       return value;
3219     }
3220 
3221     if (element && isPercentage) {
3222       context = context || element.parentNode;
3223       var decimal = toDecimal(value);
3224       var whole = null;
3225       var position = element.getStyle('position');
3226 
3227       var isHorizontal = property.include('left') || property.include('right') ||
3228        property.include('width');
3229 
3230       var isVertical =  property.include('top') || property.include('bottom') ||
3231         property.include('height');
3232 
3233       if (context === document.viewport) {
3234         if (isHorizontal) {
3235           whole = document.viewport.getWidth();
3236         } else if (isVertical) {
3237           whole = document.viewport.getHeight();
3238         }
3239       } else {
3240         if (isHorizontal) {
3241           whole = $(context).measure('width');
3242         } else if (isVertical) {
3243           whole = $(context).measure('height');
3244         }
3245       }
3246 
3247       return (whole === null) ? 0 : whole * decimal;
3248     }
3249 
3250     return 0;
3251   }
3252 
3253   function toCSSPixels(number) {
3254     if (Object.isString(number) && number.endsWith('px')) {
3255       return number;
3256     }
3257     return number + 'px';
3258   }
3259 
3260   function isDisplayed(element) {
3261     var originalElement = element;
3262     while (element && element.parentNode) {
3263       var display = element.getStyle('display');
3264       if (display === 'none') {
3265         return false;
3266       }
3267       element = $(element.parentNode);
3268     }
3269     return true;
3270   }
3271 
3272   var hasLayout = Prototype.K;
3273   if ('currentStyle' in document.documentElement) {
3274     hasLayout = function(element) {
3275       if (!element.currentStyle.hasLayout) {
3276         element.style.zoom = 1;
3277       }
3278       return element;
3279     };
3280   }
3281 
3282   function cssNameFor(key) {
3283     if (key.include('border')) key = key + '-width';
3284     return key.camelize();
3285   }
3286 
3287   Element.Layout = Class.create(Hash, {
3288     initialize: function($super, element, preCompute) {
3289       $super();
3290       this.element = $(element);
3291 
3292       Element.Layout.PROPERTIES.each( function(property) {
3293         this._set(property, null);
3294       }, this);
3295 
3296       if (preCompute) {
3297         this._preComputing = true;
3298         this._begin();
3299         Element.Layout.PROPERTIES.each( this._compute, this );
3300         this._end();
3301         this._preComputing = false;
3302       }
3303     },
3304 
3305     _set: function(property, value) {
3306       return Hash.prototype.set.call(this, property, value);
3307     },
3308 
3309     set: function(property, value) {
3310       throw "Properties of Element.Layout are read-only.";
3311     },
3312 
3313     get: function($super, property) {
3314       var value = $super(property);
3315       return value === null ? this._compute(property) : value;
3316     },
3317 
3318     _begin: function() {
3319       if (this._prepared) return;
3320 
3321       var element = this.element;
3322       if (isDisplayed(element)) {
3323         this._prepared = true;
3324         return;
3325       }
3326 
3327       var originalStyles = {
3328         position:   element.style.position   || '',
3329         width:      element.style.width      || '',
3330         visibility: element.style.visibility || '',
3331         display:    element.style.display    || ''
3332       };
3333 
3334       element.store('prototype_original_styles', originalStyles);
3335 
3336       var position = element.getStyle('position'),
3337        width = element.getStyle('width');
3338 
3339       if (width === "0px" || width === null) {
3340         element.style.display = 'block';
3341         width = element.getStyle('width');
3342       }
3343 
3344       var context = (position === 'fixed') ? document.viewport :
3345        element.parentNode;
3346 
3347       element.setStyle({
3348         position:   'absolute',
3349         visibility: 'hidden',
3350         display:    'block'
3351       });
3352 
3353       var positionedWidth = element.getStyle('width');
3354 
3355       var newWidth;
3356       if (width && (positionedWidth === width)) {
3357         newWidth = getPixelValue(element, 'width', context);
3358       } else if (position === 'absolute' || position === 'fixed') {
3359         newWidth = getPixelValue(element, 'width', context);
3360       } else {
3361         var parent = element.parentNode, pLayout = $(parent).getLayout();
3362 
3363         newWidth = pLayout.get('width') -
3364          this.get('margin-left') -
3365          this.get('border-left') -
3366          this.get('padding-left') -
3367          this.get('padding-right') -
3368          this.get('border-right') -
3369          this.get('margin-right');
3370       }
3371 
3372       element.setStyle({ width: newWidth + 'px' });
3373 
3374       this._prepared = true;
3375     },
3376 
3377     _end: function() {
3378       var element = this.element;
3379       var originalStyles = element.retrieve('prototype_original_styles');
3380       element.store('prototype_original_styles', null);
3381       element.setStyle(originalStyles);
3382       this._prepared = false;
3383     },
3384 
3385     _compute: function(property) {
3386       var COMPUTATIONS = Element.Layout.COMPUTATIONS;
3387       if (!(property in COMPUTATIONS)) {
3388         throw "Property not found.";
3389       }
3390 
3391       return this._set(property, COMPUTATIONS[property].call(this, this.element));
3392     },
3393 
3394     toObject: function() {
3395       var args = $A(arguments);
3396       var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3397        args.join(' ').split(' ');
3398       var obj = {};
3399       keys.each( function(key) {
3400         if (!Element.Layout.PROPERTIES.include(key)) return;
3401         var value = this.get(key);
3402         if (value != null) obj[key] = value;
3403       }, this);
3404       return obj;
3405     },
3406 
3407     toHash: function() {
3408       var obj = this.toObject.apply(this, arguments);
3409       return new Hash(obj);
3410     },
3411 
3412     toCSS: function() {
3413       var args = $A(arguments);
3414       var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3415        args.join(' ').split(' ');
3416       var css = {};
3417 
3418       keys.each( function(key) {
3419         if (!Element.Layout.PROPERTIES.include(key)) return;
3420         if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
3421 
3422         var value = this.get(key);
3423         if (value != null) css[cssNameFor(key)] = value + 'px';
3424       }, this);
3425       return css;
3426     },
3427 
3428     inspect: function() {
3429       return "#<Element.Layout>";
3430     }
3431   });
3432 
3433   Object.extend(Element.Layout, {
3434     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'),
3435 
3436     COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3437 
3438     COMPUTATIONS: {
3439       'height': function(element) {
3440         if (!this._preComputing) this._begin();
3441 
3442         var bHeight = this.get('border-box-height');
3443         if (bHeight <= 0) {
3444           if (!this._preComputing) this._end();
3445           return 0;
3446         }
3447 
3448         var bTop = this.get('border-top'),
3449          bBottom = this.get('border-bottom');
3450 
3451         var pTop = this.get('padding-top'),
3452          pBottom = this.get('padding-bottom');
3453 
3454         if (!this._preComputing) this._end();
3455 
3456         return bHeight - bTop - bBottom - pTop - pBottom;
3457       },
3458 
3459       'width': function(element) {
3460         if (!this._preComputing) this._begin();
3461 
3462         var bWidth = this.get('border-box-width');
3463         if (bWidth <= 0) {
3464           if (!this._preComputing) this._end();
3465           return 0;
3466         }
3467 
3468         var bLeft = this.get('border-left'),
3469          bRight = this.get('border-right');
3470 
3471         var pLeft = this.get('padding-left'),
3472          pRight = this.get('padding-right');
3473 
3474         if (!this._preComputing) this._end();
3475 
3476         return bWidth - bLeft - bRight - pLeft - pRight;
3477       },
3478 
3479       'padding-box-height': function(element) {
3480         var height = this.get('height'),
3481          pTop = this.get('padding-top'),
3482          pBottom = this.get('padding-bottom');
3483 
3484         return height + pTop + pBottom;
3485       },
3486 
3487       'padding-box-width': function(element) {
3488         var width = this.get('width'),
3489          pLeft = this.get('padding-left'),
3490          pRight = this.get('padding-right');
3491 
3492         return width + pLeft + pRight;
3493       },
3494 
3495       'border-box-height': function(element) {
3496         if (!this._preComputing) this._begin();
3497         var height = element.offsetHeight;
3498         if (!this._preComputing) this._end();
3499         return height;
3500       },
3501 
3502       'border-box-width': function(element) {
3503         if (!this._preComputing) this._begin();
3504         var width = element.offsetWidth;
3505         if (!this._preComputing) this._end();
3506         return width;
3507       },
3508 
3509       'margin-box-height': function(element) {
3510         var bHeight = this.get('border-box-height'),
3511          mTop = this.get('margin-top'),
3512          mBottom = this.get('margin-bottom');
3513 
3514         if (bHeight <= 0) return 0;
3515 
3516         return bHeight + mTop + mBottom;
3517       },
3518 
3519       'margin-box-width': function(element) {
3520         var bWidth = this.get('border-box-width'),
3521          mLeft = this.get('margin-left'),
3522          mRight = this.get('margin-right');
3523 
3524         if (bWidth <= 0) return 0;
3525 
3526         return bWidth + mLeft + mRight;
3527       },
3528 
3529       'top': function(element) {
3530         var offset = element.positionedOffset();
3531         return offset.top;
3532       },
3533 
3534       'bottom': function(element) {
3535         var offset = element.positionedOffset(),
3536          parent = element.getOffsetParent(),
3537          pHeight = parent.measure('height');
3538 
3539         var mHeight = this.get('border-box-height');
3540 
3541         return pHeight - mHeight - offset.top;
3542       },
3543 
3544       'left': function(element) {
3545         var offset = element.positionedOffset();
3546         return offset.left;
3547       },
3548 
3549       'right': function(element) {
3550         var offset = element.positionedOffset(),
3551          parent = element.getOffsetParent(),
3552          pWidth = parent.measure('width');
3553 
3554         var mWidth = this.get('border-box-width');
3555 
3556         return pWidth - mWidth - offset.left;
3557       },
3558 
3559       'padding-top': function(element) {
3560         return getPixelValue(element, 'paddingTop');
3561       },
3562 
3563       'padding-bottom': function(element) {
3564         return getPixelValue(element, 'paddingBottom');
3565       },
3566 
3567       'padding-left': function(element) {
3568         return getPixelValue(element, 'paddingLeft');
3569       },
3570 
3571       'padding-right': function(element) {
3572         return getPixelValue(element, 'paddingRight');
3573       },
3574 
3575       'border-top': function(element) {
3576         return getPixelValue(element, 'borderTopWidth');
3577       },
3578 
3579       'border-bottom': function(element) {
3580         return getPixelValue(element, 'borderBottomWidth');
3581       },
3582 
3583       'border-left': function(element) {
3584         return getPixelValue(element, 'borderLeftWidth');
3585       },
3586 
3587       'border-right': function(element) {
3588         return getPixelValue(element, 'borderRightWidth');
3589       },
3590 
3591       'margin-top': function(element) {
3592         return getPixelValue(element, 'marginTop');
3593       },
3594 
3595       'margin-bottom': function(element) {
3596         return getPixelValue(element, 'marginBottom');
3597       },
3598 
3599       'margin-left': function(element) {
3600         return getPixelValue(element, 'marginLeft');
3601       },
3602 
3603       'margin-right': function(element) {
3604         return getPixelValue(element, 'marginRight');
3605       }
3606     }
3607   });
3608 
3609   if ('getBoundingClientRect' in document.documentElement) {
3610     Object.extend(Element.Layout.COMPUTATIONS, {
3611       'right': function(element) {
3612         var parent = hasLayout(element.getOffsetParent());
3613         var rect = element.getBoundingClientRect(),
3614          pRect = parent.getBoundingClientRect();
3615 
3616         return (pRect.right - rect.right).round();
3617       },
3618 
3619       'bottom': function(element) {
3620         var parent = hasLayout(element.getOffsetParent());
3621         var rect = element.getBoundingClientRect(),
3622          pRect = parent.getBoundingClientRect();
3623 
3624         return (pRect.bottom - rect.bottom).round();
3625       }
3626     });
3627   }
3628 
3629   Element.Offset = Class.create({
3630     initialize: function(left, top) {
3631       this.left = left.round();
3632       this.top  = top.round();
3633 
3634       this[0] = this.left;
3635       this[1] = this.top;
3636     },
3637 
3638     relativeTo: function(offset) {
3639       return new Element.Offset(
3640         this.left - offset.left,
3641         this.top  - offset.top
3642       );
3643     },
3644 
3645     inspect: function() {
3646       return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3647     },
3648 
3649     toString: function() {
3650       return "[#{left}, #{top}]".interpolate(this);
3651     },
3652 
3653     toArray: function() {
3654       return [this.left, this.top];
3655     }
3656   });
3657 
3658   function getLayout(element, preCompute) {
3659     return new Element.Layout(element, preCompute);
3660   }
3661 
3662   function measure(element, property) {
3663     return $(element).getLayout().get(property);
3664   }
3665 
3666   function getDimensions(element) {
3667     element = $(element);
3668     var display = Element.getStyle(element, 'display');
3669 
3670     if (display && display !== 'none') {
3671       return { width: element.offsetWidth, height: element.offsetHeight };
3672     }
3673 
3674     var style = element.style;
3675     var originalStyles = {
3676       visibility: style.visibility,
3677       position:   style.position,
3678       display:    style.display
3679     };
3680 
3681     var newStyles = {
3682       visibility: 'hidden',
3683       display:    'block'
3684     };
3685 
3686     if (originalStyles.position !== 'fixed')
3687       newStyles.position = 'absolute';
3688 
3689     Element.setStyle(element, newStyles);
3690 
3691     var dimensions = {
3692       width:  element.offsetWidth,
3693       height: element.offsetHeight
3694     };
3695 
3696     Element.setStyle(element, originalStyles);
3697 
3698     return dimensions;
3699   }
3700 
3701   function getOffsetParent(element) {
3702     element = $(element);
3703 
3704     if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
3705       return $(document.body);
3706 
3707     var isInline = (Element.getStyle(element, 'display') === 'inline');
3708     if (!isInline && element.offsetParent) return $(element.offsetParent);
3709 
3710     while ((element = element.parentNode) && element !== document.body) {
3711       if (Element.getStyle(element, 'position') !== 'static') {
3712         return isHtml(element) ? $(document.body) : $(element);
3713       }
3714     }
3715 
3716     return $(document.body);
3717   }
3718 
3719 
3720   function cumulativeOffset(element) {
3721     element = $(element);
3722     var valueT = 0, valueL = 0;
3723     if (element.parentNode) {
3724       do {
3725         valueT += element.offsetTop  || 0;
3726         valueL += element.offsetLeft || 0;
3727         element = element.offsetParent;
3728       } while (element);
3729     }
3730     return new Element.Offset(valueL, valueT);
3731   }
3732 
3733   function positionedOffset(element) {
3734     element = $(element);
3735 
3736     var layout = element.getLayout();
3737 
3738     var valueT = 0, valueL = 0;
3739     do {
3740       valueT += element.offsetTop  || 0;
3741       valueL += element.offsetLeft || 0;
3742       element = element.offsetParent;
3743       if (element) {
3744         if (isBody(element)) break;
3745         var p = Element.getStyle(element, 'position');
3746         if (p !== 'static') break;
3747       }
3748     } while (element);
3749 
3750     valueL -= layout.get('margin-top');
3751     valueT -= layout.get('margin-left');
3752 
3753     return new Element.Offset(valueL, valueT);
3754   }
3755 
3756   function cumulativeScrollOffset(element) {
3757     var valueT = 0, valueL = 0;
3758     do {
3759       valueT += element.scrollTop  || 0;
3760       valueL += element.scrollLeft || 0;
3761       element = element.parentNode;
3762     } while (element);
3763     return new Element.Offset(valueL, valueT);
3764   }
3765 
3766   function viewportOffset(forElement) {
3767     element = $(element);
3768     var valueT = 0, valueL = 0, docBody = document.body;
3769 
3770     var element = forElement;
3771     do {
3772       valueT += element.offsetTop  || 0;
3773       valueL += element.offsetLeft || 0;
3774       if (element.offsetParent == docBody &&
3775         Element.getStyle(element, 'position') == 'absolute') break;
3776     } while (element = element.offsetParent);
3777 
3778     element = forElement;
3779     do {
3780       if (element != docBody) {
3781         valueT -= element.scrollTop  || 0;
3782         valueL -= element.scrollLeft || 0;
3783       }
3784     } while (element = element.parentNode);
3785     return new Element.Offset(valueL, valueT);
3786   }
3787 
3788   function absolutize(element) {
3789     element = $(element);
3790 
3791     if (Element.getStyle(element, 'position') === 'absolute') {
3792       return element;
3793     }
3794 
3795     var offsetParent = getOffsetParent(element);
3796     var eOffset = element.viewportOffset(),
3797      pOffset = offsetParent.viewportOffset();
3798 
3799     var offset = eOffset.relativeTo(pOffset);
3800     var layout = element.getLayout();
3801 
3802     element.store('prototype_absolutize_original_styles', {
3803       left:   element.getStyle('left'),
3804       top:    element.getStyle('top'),
3805       width:  element.getStyle('width'),
3806       height: element.getStyle('height')
3807     });
3808 
3809     element.setStyle({
3810       position: 'absolute',
3811       top:    offset.top + 'px',
3812       left:   offset.left + 'px',
3813       width:  layout.get('width') + 'px',
3814       height: layout.get('height') + 'px'
3815     });
3816 
3817     return element;
3818   }
3819 
3820   function relativize(element) {
3821     element = $(element);
3822     if (Element.getStyle(element, 'position') === 'relative') {
3823       return element;
3824     }
3825 
3826     var originalStyles =
3827      element.retrieve('prototype_absolutize_original_styles');
3828 
3829     if (originalStyles) element.setStyle(originalStyles);
3830     return element;
3831   }
3832 
3833   if (Prototype.Browser.IE) {
3834     getOffsetParent = getOffsetParent.wrap(
3835       function(proceed, element) {
3836         element = $(element);
3837 
3838         if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
3839           return $(document.body);
3840 
3841         var position = element.getStyle('position');
3842         if (position !== 'static') return proceed(element);
3843 
3844         element.setStyle({ position: 'relative' });
3845         var value = proceed(element);
3846         element.setStyle({ position: position });
3847         return value;
3848       }
3849     );
3850 
3851     positionedOffset = positionedOffset.wrap(function(proceed, element) {
3852       element = $(element);
3853       if (!element.parentNode) return new Element.Offset(0, 0);
3854       var position = element.getStyle('position');
3855       if (position !== 'static') return proceed(element);
3856 
3857       var offsetParent = element.getOffsetParent();
3858       if (offsetParent && offsetParent.getStyle('position') === 'fixed')
3859         hasLayout(offsetParent);
3860 
3861       element.setStyle({ position: 'relative' });
3862       var value = proceed(element);
3863       element.setStyle({ position: position });
3864       return value;
3865     });
3866   } else if (Prototype.Browser.Webkit) {
3867     cumulativeOffset = function(element) {
3868       element = $(element);
3869       var valueT = 0, valueL = 0;
3870       do {
3871         valueT += element.offsetTop  || 0;
3872         valueL += element.offsetLeft || 0;
3873         if (element.offsetParent == document.body)
3874           if (Element.getStyle(element, 'position') == 'absolute') break;
3875 
3876         element = element.offsetParent;
3877       } while (element);
3878 
3879       return new Element.Offset(valueL, valueT);
3880     };
3881   }
3882 
3883 
3884   Element.addMethods({
3885     getLayout:              getLayout,
3886     measure:                measure,
3887     getDimensions:          getDimensions,
3888     getOffsetParent:        getOffsetParent,
3889     cumulativeOffset:       cumulativeOffset,
3890     positionedOffset:       positionedOffset,
3891     cumulativeScrollOffset: cumulativeScrollOffset,
3892     viewportOffset:         viewportOffset,
3893     absolutize:             absolutize,
3894     relativize:             relativize
3895   });
3896 
3897   function isBody(element) {
3898     return element.nodeName.toUpperCase() === 'BODY';
3899   }
3900 
3901   function isHtml(element) {
3902     return element.nodeName.toUpperCase() === 'HTML';
3903   }
3904 
3905   function isDocument(element) {
3906     return element.nodeType === Node.DOCUMENT_NODE;
3907   }
3908 
3909   function isDetached(element) {
3910     return element !== document.body &&
3911      !Element.descendantOf(element, document.body);
3912   }
3913 
3914   if ('getBoundingClientRect' in document.documentElement) {
3915     Element.addMethods({
3916       viewportOffset: function(element) {
3917         element = $(element);
3918         if (isDetached(element)) return new Element.Offset(0, 0);
3919 
3920         var rect = element.getBoundingClientRect(),
3921          docEl = document.documentElement;
3922         return new Element.Offset(rect.left - docEl.clientLeft,
3923          rect.top - docEl.clientTop);
3924       }
3925     });
3926   }
3927 })();
3928 window.$$ = function() {
3929   var expression = $A(arguments).join(', ');
3930   return Prototype.Selector.select(expression, document);
3931 };
3932 
3933 Prototype.Selector = (function() {
3934 
3935   function select() {
3936     throw new Error('Method "Prototype.Selector.select" must be defined.');
3937   }
3938 
3939   function match() {
3940     throw new Error('Method "Prototype.Selector.match" must be defined.');
3941   }
3942 
3943   function find(elements, expression, index) {
3944     index = index || 0;
3945     var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
3946 
3947     for (i = 0; i < length; i++) {
3948       if (match(elements[i], expression) && index == matchIndex++) {
3949         return Element.extend(elements[i]);
3950       }
3951     }
3952   }
3953 
3954   function extendElements(elements) {
3955     for (var i = 0, length = elements.length; i < length; i++) {
3956       Element.extend(elements[i]);
3957     }
3958     return elements;
3959   }
3960 
3961 
3962   var K = Prototype.K;
3963 
3964   return {
3965     select: select,
3966     match: match,
3967     find: find,
3968     extendElements: (Element.extend === K) ? K : extendElements,
3969     extendElement: Element.extend
3970   };
3971 })();
3972 Prototype._original_property = window.Sizzle;
3973 /*!
3974  * Sizzle CSS Selector Engine - v1.0
3975  *  Copyright 2009, The Dojo Foundation
3976  *  Released under the MIT, BSD, and GPL Licenses.
3977  *  More information: http://sizzlejs.com/
3978  */
3979 (function(){
3980 
3981 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
3982 	done = 0,
3983 	toString = Object.prototype.toString,
3984 	hasDuplicate = false,
3985 	baseHasDuplicate = true;
3986 
3987 [0, 0].sort(function(){
3988 	baseHasDuplicate = false;
3989 	return 0;
3990 });
3991 
3992 var Sizzle = function(selector, context, results, seed) {
3993 	results = results || [];
3994 	var origContext = context = context || document;
3995 
3996 	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
3997 		return [];
3998 	}
3999 
4000 	if ( !selector || typeof selector !== "string" ) {
4001 		return results;
4002 	}
4003 
4004 	var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context),
4005 		soFar = selector;
4006 
4007 	while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
4008 		soFar = m[3];
4009 
4010 		parts.push( m[1] );
4011 
4012 		if ( m[2] ) {
4013 			extra = m[3];
4014 			break;
4015 		}
4016 	}
4017 
4018 	if ( parts.length > 1 && origPOS.exec( selector ) ) {
4019 		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
4020 			set = posProcess( parts[0] + parts[1], context );
4021 		} else {
4022 			set = Expr.relative[ parts[0] ] ?
4023 				[ context ] :
4024 				Sizzle( parts.shift(), context );
4025 
4026 			while ( parts.length ) {
4027 				selector = parts.shift();
4028 
4029 				if ( Expr.relative[ selector ] )
4030 					selector += parts.shift();
4031 
4032 				set = posProcess( selector, set );
4033 			}
4034 		}
4035 	} else {
4036 		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
4037 				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
4038 			var ret = Sizzle.find( parts.shift(), context, contextXML );
4039 			context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
4040 		}
4041 
4042 		if ( context ) {
4043 			var ret = seed ?
4044 				{ expr: parts.pop(), set: makeArray(seed) } :
4045 				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
4046 			set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
4047 
4048 			if ( parts.length > 0 ) {
4049 				checkSet = makeArray(set);
4050 			} else {
4051 				prune = false;
4052 			}
4053 
4054 			while ( parts.length ) {
4055 				var cur = parts.pop(), pop = cur;
4056 
4057 				if ( !Expr.relative[ cur ] ) {
4058 					cur = "";
4059 				} else {
4060 					pop = parts.pop();
4061 				}
4062 
4063 				if ( pop == null ) {
4064 					pop = context;
4065 				}
4066 
4067 				Expr.relative[ cur ]( checkSet, pop, contextXML );
4068 			}
4069 		} else {
4070 			checkSet = parts = [];
4071 		}
4072 	}
4073 
4074 	if ( !checkSet ) {
4075 		checkSet = set;
4076 	}
4077 
4078 	if ( !checkSet ) {
4079 		throw "Syntax error, unrecognized expression: " + (cur || selector);
4080 	}
4081 
4082 	if ( toString.call(checkSet) === "[object Array]" ) {
4083 		if ( !prune ) {
4084 			results.push.apply( results, checkSet );
4085 		} else if ( context && context.nodeType === 1 ) {
4086 			for ( var i = 0; checkSet[i] != null; i++ ) {
4087 				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
4088 					results.push( set[i] );
4089 				}
4090 			}
4091 		} else {
4092 			for ( var i = 0; checkSet[i] != null; i++ ) {
4093 				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
4094 					results.push( set[i] );
4095 				}
4096 			}
4097 		}
4098 	} else {
4099 		makeArray( checkSet, results );
4100 	}
4101 
4102 	if ( extra ) {
4103 		Sizzle( extra, origContext, results, seed );
4104 		Sizzle.uniqueSort( results );
4105 	}
4106 
4107 	return results;
4108 };
4109 
4110 Sizzle.uniqueSort = function(results){
4111 	if ( sortOrder ) {
4112 		hasDuplicate = baseHasDuplicate;
4113 		results.sort(sortOrder);
4114 
4115 		if ( hasDuplicate ) {
4116 			for ( var i = 1; i < results.length; i++ ) {
4117 				if ( results[i] === results[i-1] ) {
4118 					results.splice(i--, 1);
4119 				}
4120 			}
4121 		}
4122 	}
4123 
4124 	return results;
4125 };
4126 
4127 Sizzle.matches = function(expr, set){
4128 	return Sizzle(expr, null, null, set);
4129 };
4130 
4131 Sizzle.find = function(expr, context, isXML){
4132 	var set, match;
4133 
4134 	if ( !expr ) {
4135 		return [];
4136 	}
4137 
4138 	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
4139 		var type = Expr.order[i], match;
4140 
4141 		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
4142 			var left = match[1];
4143 			match.splice(1,1);
4144 
4145 			if ( left.substr( left.length - 1 ) !== "\\" ) {
4146 				match[1] = (match[1] || "").replace(/\\/g, "");
4147 				set = Expr.find[ type ]( match, context, isXML );
4148 				if ( set != null ) {
4149 					expr = expr.replace( Expr.match[ type ], "" );
4150 					break;
4151 				}
4152 			}
4153 		}
4154 	}
4155 
4156 	if ( !set ) {
4157 		set = context.getElementsByTagName("*");
4158 	}
4159 
4160 	return {set: set, expr: expr};
4161 };
4162 
4163 Sizzle.filter = function(expr, set, inplace, not){
4164 	var old = expr, result = [], curLoop = set, match, anyFound,
4165 		isXMLFilter = set && set[0] && isXML(set[0]);
4166 
4167 	while ( expr && set.length ) {
4168 		for ( var type in Expr.filter ) {
4169 			if ( (match = Expr.match[ type ].exec( expr )) != null ) {
4170 				var filter = Expr.filter[ type ], found, item;
4171 				anyFound = false;
4172 
4173 				if ( curLoop == result ) {
4174 					result = [];
4175 				}
4176 
4177 				if ( Expr.preFilter[ type ] ) {
4178 					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
4179 
4180 					if ( !match ) {
4181 						anyFound = found = true;
4182 					} else if ( match === true ) {
4183 						continue;
4184 					}
4185 				}
4186 
4187 				if ( match ) {
4188 					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
4189 						if ( item ) {
4190 							found = filter( item, match, i, curLoop );
4191 							var pass = not ^ !!found;
4192 
4193 							if ( inplace && found != null ) {
4194 								if ( pass ) {
4195 									anyFound = true;
4196 								} else {
4197 									curLoop[i] = false;
4198 								}
4199 							} else if ( pass ) {
4200 								result.push( item );
4201 								anyFound = true;
4202 							}
4203 						}
4204 					}
4205 				}
4206 
4207 				if ( found !== undefined ) {
4208 					if ( !inplace ) {
4209 						curLoop = result;
4210 					}
4211 
4212 					expr = expr.replace( Expr.match[ type ], "" );
4213 
4214 					if ( !anyFound ) {
4215 						return [];
4216 					}
4217 
4218 					break;
4219 				}
4220 			}
4221 		}
4222 
4223 		if ( expr == old ) {
4224 			if ( anyFound == null ) {
4225 				throw "Syntax error, unrecognized expression: " + expr;
4226 			} else {
4227 				break;
4228 			}
4229 		}
4230 
4231 		old = expr;
4232 	}
4233 
4234 	return curLoop;
4235 };
4236 
4237 var Expr = Sizzle.selectors = {
4238 	order: [ "ID", "NAME", "TAG" ],
4239 	match: {
4240 		ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
4241 		CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
4242 		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
4243 		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
4244 		TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
4245 		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
4246 		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
4247 		PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
4248 	},
4249 	leftMatch: {},
4250 	attrMap: {
4251 		"class": "className",
4252 		"for": "htmlFor"
4253 	},
4254 	attrHandle: {
4255 		href: function(elem){
4256 			return elem.getAttribute("href");
4257 		}
4258 	},
4259 	relative: {
4260 		"+": function(checkSet, part, isXML){
4261 			var isPartStr = typeof part === "string",
4262 				isTag = isPartStr && !/\W/.test(part),
4263 				isPartStrNotTag = isPartStr && !isTag;
4264 
4265 			if ( isTag && !isXML ) {
4266 				part = part.toUpperCase();
4267 			}
4268 
4269 			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
4270 				if ( (elem = checkSet[i]) ) {
4271 					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
4272 
4273 					checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
4274 						elem || false :
4275 						elem === part;
4276 				}
4277 			}
4278 
4279 			if ( isPartStrNotTag ) {
4280 				Sizzle.filter( part, checkSet, true );
4281 			}
4282 		},
4283 		">": function(checkSet, part, isXML){
4284 			var isPartStr = typeof part === "string";
4285 
4286 			if ( isPartStr && !/\W/.test(part) ) {
4287 				part = isXML ? part : part.toUpperCase();
4288 
4289 				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4290 					var elem = checkSet[i];
4291 					if ( elem ) {
4292 						var parent = elem.parentNode;
4293 						checkSet[i] = parent.nodeName === part ? parent : false;
4294 					}
4295 				}
4296 			} else {
4297 				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4298 					var elem = checkSet[i];
4299 					if ( elem ) {
4300 						checkSet[i] = isPartStr ?
4301 							elem.parentNode :
4302 							elem.parentNode === part;
4303 					}
4304 				}
4305 
4306 				if ( isPartStr ) {
4307 					Sizzle.filter( part, checkSet, true );
4308 				}
4309 			}
4310 		},
4311 		"": function(checkSet, part, isXML){
4312 			var doneName = done++, checkFn = dirCheck;
4313 
4314 			if ( !/\W/.test(part) ) {
4315 				var nodeCheck = part = isXML ? part : part.toUpperCase();
4316 				checkFn = dirNodeCheck;
4317 			}
4318 
4319 			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
4320 		},
4321 		"~": function(checkSet, part, isXML){
4322 			var doneName = done++, checkFn = dirCheck;
4323 
4324 			if ( typeof part === "string" && !/\W/.test(part) ) {
4325 				var nodeCheck = part = isXML ? part : part.toUpperCase();
4326 				checkFn = dirNodeCheck;
4327 			}
4328 
4329 			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
4330 		}
4331 	},
4332 	find: {
4333 		ID: function(match, context, isXML){
4334 			if ( typeof context.getElementById !== "undefined" && !isXML ) {
4335 				var m = context.getElementById(match[1]);
4336 				return m ? [m] : [];
4337 			}
4338 		},
4339 		NAME: function(match, context, isXML){
4340 			if ( typeof context.getElementsByName !== "undefined" ) {
4341 				var ret = [], results = context.getElementsByName(match[1]);
4342 
4343 				for ( var i = 0, l = results.length; i < l; i++ ) {
4344 					if ( results[i].getAttribute("name") === match[1] ) {
4345 						ret.push( results[i] );
4346 					}
4347 				}
4348 
4349 				return ret.length === 0 ? null : ret;
4350 			}
4351 		},
4352 		TAG: function(match, context){
4353 			return context.getElementsByTagName(match[1]);
4354 		}
4355 	},
4356 	preFilter: {
4357 		CLASS: function(match, curLoop, inplace, result, not, isXML){
4358 			match = " " + match[1].replace(/\\/g, "") + " ";
4359 
4360 			if ( isXML ) {
4361 				return match;
4362 			}
4363 
4364 			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
4365 				if ( elem ) {
4366 					if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
4367 						if ( !inplace )
4368 							result.push( elem );
4369 					} else if ( inplace ) {
4370 						curLoop[i] = false;
4371 					}
4372 				}
4373 			}
4374 
4375 			return false;
4376 		},
4377 		ID: function(match){
4378 			return match[1].replace(/\\/g, "");
4379 		},
4380 		TAG: function(match, curLoop){
4381 			for ( var i = 0; curLoop[i] === false; i++ ){}
4382 			return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
4383 		},
4384 		CHILD: function(match){
4385 			if ( match[1] == "nth" ) {
4386 				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
4387 					match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
4388 					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
4389 
4390 				match[2] = (test[1] + (test[2] || 1)) - 0;
4391 				match[3] = test[3] - 0;
4392 			}
4393 
4394 			match[0] = done++;
4395 
4396 			return match;
4397 		},
4398 		ATTR: function(match, curLoop, inplace, result, not, isXML){
4399 			var name = match[1].replace(/\\/g, "");
4400 
4401 			if ( !isXML && Expr.attrMap[name] ) {
4402 				match[1] = Expr.attrMap[name];
4403 			}
4404 
4405 			if ( match[2] === "~=" ) {
4406 				match[4] = " " + match[4] + " ";
4407 			}
4408 
4409 			return match;
4410 		},
4411 		PSEUDO: function(match, curLoop, inplace, result, not){
4412 			if ( match[1] === "not" ) {
4413 				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
4414 					match[3] = Sizzle(match[3], null, null, curLoop);
4415 				} else {
4416 					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
4417 					if ( !inplace ) {
4418 						result.push.apply( result, ret );
4419 					}
4420 					return false;
4421 				}
4422 			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
4423 				return true;
4424 			}
4425 
4426 			return match;
4427 		},
4428 		POS: function(match){
4429 			match.unshift( true );
4430 			return match;
4431 		}
4432 	},
4433 	filters: {
4434 		enabled: function(elem){
4435 			return elem.disabled === false && elem.type !== "hidden";
4436 		},
4437 		disabled: function(elem){
4438 			return elem.disabled === true;
4439 		},
4440 		checked: function(elem){
4441 			return elem.checked === true;
4442 		},
4443 		selected: function(elem){
4444 			elem.parentNode.selectedIndex;
4445 			return elem.selected === true;
4446 		},
4447 		parent: function(elem){
4448 			return !!elem.firstChild;
4449 		},
4450 		empty: function(elem){
4451 			return !elem.firstChild;
4452 		},
4453 		has: function(elem, i, match){
4454 			return !!Sizzle( match[3], elem ).length;
4455 		},
4456 		header: function(elem){
4457 			return /h\d/i.test( elem.nodeName );
4458 		},
4459 		text: function(elem){
4460 			return "text" === elem.type;
4461 		},
4462 		radio: function(elem){
4463 			return "radio" === elem.type;
4464 		},
4465 		checkbox: function(elem){
4466 			return "checkbox" === elem.type;
4467 		},
4468 		file: function(elem){
4469 			return "file" === elem.type;
4470 		},
4471 		password: function(elem){
4472 			return "password" === elem.type;
4473 		},
4474 		submit: function(elem){
4475 			return "submit" === elem.type;
4476 		},
4477 		image: function(elem){
4478 			return "image" === elem.type;
4479 		},
4480 		reset: function(elem){
4481 			return "reset" === elem.type;
4482 		},
4483 		button: function(elem){
4484 			return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
4485 		},
4486 		input: function(elem){
4487 			return /input|select|textarea|button/i.test(elem.nodeName);
4488 		}
4489 	},
4490 	setFilters: {
4491 		first: function(elem, i){
4492 			return i === 0;
4493 		},
4494 		last: function(elem, i, match, array){
4495 			return i === array.length - 1;
4496 		},
4497 		even: function(elem, i){
4498 			return i % 2 === 0;
4499 		},
4500 		odd: function(elem, i){
4501 			return i % 2 === 1;
4502 		},
4503 		lt: function(elem, i, match){
4504 			return i < match[3] - 0;
4505 		},
4506 		gt: function(elem, i, match){
4507 			return i > match[3] - 0;
4508 		},
4509 		nth: function(elem, i, match){
4510 			return match[3] - 0 == i;
4511 		},
4512 		eq: function(elem, i, match){
4513 			return match[3] - 0 == i;
4514 		}
4515 	},
4516 	filter: {
4517 		PSEUDO: function(elem, match, i, array){
4518 			var name = match[1], filter = Expr.filters[ name ];
4519 
4520 			if ( filter ) {
4521 				return filter( elem, i, match, array );
4522 			} else if ( name === "contains" ) {
4523 				return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
4524 			} else if ( name === "not" ) {
4525 				var not = match[3];
4526 
4527 				for ( var i = 0, l = not.length; i < l; i++ ) {
4528 					if ( not[i] === elem ) {
4529 						return false;
4530 					}
4531 				}
4532 
4533 				return true;
4534 			}
4535 		},
4536 		CHILD: function(elem, match){
4537 			var type = match[1], node = elem;
4538 			switch (type) {
4539 				case 'only':
4540 				case 'first':
4541 					while ( (node = node.previousSibling) )  {
4542 						if ( node.nodeType === 1 ) return false;
4543 					}
4544 					if ( type == 'first') return true;
4545 					node = elem;
4546 				case 'last':
4547 					while ( (node = node.nextSibling) )  {
4548 						if ( node.nodeType === 1 ) return false;
4549 					}
4550 					return true;
4551 				case 'nth':
4552 					var first = match[2], last = match[3];
4553 
4554 					if ( first == 1 && last == 0 ) {
4555 						return true;
4556 					}
4557 
4558 					var doneName = match[0],
4559 						parent = elem.parentNode;
4560 
4561 					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
4562 						var count = 0;
4563 						for ( node = parent.firstChild; node; node = node.nextSibling ) {
4564 							if ( node.nodeType === 1 ) {
4565 								node.nodeIndex = ++count;
4566 							}
4567 						}
4568 						parent.sizcache = doneName;
4569 					}
4570 
4571 					var diff = elem.nodeIndex - last;
4572 					if ( first == 0 ) {
4573 						return diff == 0;
4574 					} else {
4575 						return ( diff % first == 0 && diff / first >= 0 );
4576 					}
4577 			}
4578 		},
4579 		ID: function(elem, match){
4580 			return elem.nodeType === 1 && elem.getAttribute("id") === match;
4581 		},
4582 		TAG: function(elem, match){
4583 			return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
4584 		},
4585 		CLASS: function(elem, match){
4586 			return (" " + (elem.className || elem.getAttribute("class")) + " ")
4587 				.indexOf( match ) > -1;
4588 		},
4589 		ATTR: function(elem, match){
4590 			var name = match[1],
4591 				result = Expr.attrHandle[ name ] ?
4592 					Expr.attrHandle[ name ]( elem ) :
4593 					elem[ name ] != null ?
4594 						elem[ name ] :
4595 						elem.getAttribute( name ),
4596 				value = result + "",
4597 				type = match[2],
4598 				check = match[4];
4599 
4600 			return result == null ?
4601 				type === "!=" :
4602 				type === "=" ?
4603 				value === check :
4604 				type === "*=" ?
4605 				value.indexOf(check) >= 0 :
4606 				type === "~=" ?
4607 				(" " + value + " ").indexOf(check) >= 0 :
4608 				!check ?
4609 				value && result !== false :
4610 				type === "!=" ?
4611 				value != check :
4612 				type === "^=" ?
4613 				value.indexOf(check) === 0 :
4614 				type === "$=" ?
4615 				value.substr(value.length - check.length) === check :
4616 				type === "|=" ?
4617 				value === check || value.substr(0, check.length + 1) === check + "-" :
4618 				false;
4619 		},
4620 		POS: function(elem, match, i, array){
4621 			var name = match[2], filter = Expr.setFilters[ name ];
4622 
4623 			if ( filter ) {
4624 				return filter( elem, i, match, array );
4625 			}
4626 		}
4627 	}
4628 };
4629 
4630 var origPOS = Expr.match.POS;
4631 
4632 for ( var type in Expr.match ) {
4633 	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
4634 	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
4635 }
4636 
4637 var makeArray = function(array, results) {
4638 	array = Array.prototype.slice.call( array, 0 );
4639 
4640 	if ( results ) {
4641 		results.push.apply( results, array );
4642 		return results;
4643 	}
4644 
4645 	return array;
4646 };
4647 
4648 try {
4649 	Array.prototype.slice.call( document.documentElement.childNodes, 0 );
4650 
4651 } catch(e){
4652 	makeArray = function(array, results) {
4653 		var ret = results || [];
4654 
4655 		if ( toString.call(array) === "[object Array]" ) {
4656 			Array.prototype.push.apply( ret, array );
4657 		} else {
4658 			if ( typeof array.length === "number" ) {
4659 				for ( var i = 0, l = array.length; i < l; i++ ) {
4660 					ret.push( array[i] );
4661 				}
4662 			} else {
4663 				for ( var i = 0; array[i]; i++ ) {
4664 					ret.push( array[i] );
4665 				}
4666 			}
4667 		}
4668 
4669 		return ret;
4670 	};
4671 }
4672 
4673 var sortOrder;
4674 
4675 if ( document.documentElement.compareDocumentPosition ) {
4676 	sortOrder = function( a, b ) {
4677 		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
4678 			if ( a == b ) {
4679 				hasDuplicate = true;
4680 			}
4681 			return 0;
4682 		}
4683 
4684 		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
4685 		if ( ret === 0 ) {
4686 			hasDuplicate = true;
4687 		}
4688 		return ret;
4689 	};
4690 } else if ( "sourceIndex" in document.documentElement ) {
4691 	sortOrder = function( a, b ) {
4692 		if ( !a.sourceIndex || !b.sourceIndex ) {
4693 			if ( a == b ) {
4694 				hasDuplicate = true;
4695 			}
4696 			return 0;
4697 		}
4698 
4699 		var ret = a.sourceIndex - b.sourceIndex;
4700 		if ( ret === 0 ) {
4701 			hasDuplicate = true;
4702 		}
4703 		return ret;
4704 	};
4705 } else if ( document.createRange ) {
4706 	sortOrder = function( a, b ) {
4707 		if ( !a.ownerDocument || !b.ownerDocument ) {
4708 			if ( a == b ) {
4709 				hasDuplicate = true;
4710 			}
4711 			return 0;
4712 		}
4713 
4714 		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
4715 		aRange.setStart(a, 0);
4716 		aRange.setEnd(a, 0);
4717 		bRange.setStart(b, 0);
4718 		bRange.setEnd(b, 0);
4719 		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
4720 		if ( ret === 0 ) {
4721 			hasDuplicate = true;
4722 		}
4723 		return ret;
4724 	};
4725 }
4726 
4727 (function(){
4728 	var form = document.createElement("div"),
4729 		id = "script" + (new Date).getTime();
4730 	form.innerHTML = "<a name='" + id + "'/>";
4731 
4732 	var root = document.documentElement;
4733 	root.insertBefore( form, root.firstChild );
4734 
4735 	if ( !!document.getElementById( id ) ) {
4736 		Expr.find.ID = function(match, context, isXML){
4737 			if ( typeof context.getElementById !== "undefined" && !isXML ) {
4738 				var m = context.getElementById(match[1]);
4739 				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
4740 			}
4741 		};
4742 
4743 		Expr.filter.ID = function(elem, match){
4744 			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
4745 			return elem.nodeType === 1 && node && node.nodeValue === match;
4746 		};
4747 	}
4748 
4749 	root.removeChild( form );
4750 	root = form = null; // release memory in IE
4751 })();
4752 
4753 (function(){
4754 
4755 	var div = document.createElement("div");
4756 	div.appendChild( document.createComment("") );
4757 
4758 	if ( div.getElementsByTagName("*").length > 0 ) {
4759 		Expr.find.TAG = function(match, context){
4760 			var results = context.getElementsByTagName(match[1]);
4761 
4762 			if ( match[1] === "*" ) {
4763 				var tmp = [];
4764 
4765 				for ( var i = 0; results[i]; i++ ) {
4766 					if ( results[i].nodeType === 1 ) {
4767 						tmp.push( results[i] );
4768 					}
4769 				}
4770 
4771 				results = tmp;
4772 			}
4773 
4774 			return results;
4775 		};
4776 	}
4777 
4778 	div.innerHTML = "<a href='#'></a>";
4779 	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
4780 			div.firstChild.getAttribute("href") !== "#" ) {
4781 		Expr.attrHandle.href = function(elem){
4782 			return elem.getAttribute("href", 2);
4783 		};
4784 	}
4785 
4786 	div = null; // release memory in IE
4787 })();
4788 
4789 if ( document.querySelectorAll ) (function(){
4790 	var oldSizzle = Sizzle, div = document.createElement("div");
4791 	div.innerHTML = "<p class='TEST'></p>";
4792 
4793 	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
4794 		return;
4795 	}
4796 
4797 	Sizzle = function(query, context, extra, seed){
4798 		context = context || document;
4799 
4800 		if ( !seed && context.nodeType === 9 && !isXML(context) ) {
4801 			try {
4802 				return makeArray( context.querySelectorAll(query), extra );
4803 			} catch(e){}
4804 		}
4805 
4806 		return oldSizzle(query, context, extra, seed);
4807 	};
4808 
4809 	for ( var prop in oldSizzle ) {
4810 		Sizzle[ prop ] = oldSizzle[ prop ];
4811 	}
4812 
4813 	div = null; // release memory in IE
4814 })();
4815 
4816 if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
4817 	var div = document.createElement("div");
4818 	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
4819 
4820 	if ( div.getElementsByClassName("e").length === 0 )
4821 		return;
4822 
4823 	div.lastChild.className = "e";
4824 
4825 	if ( div.getElementsByClassName("e").length === 1 )
4826 		return;
4827 
4828 	Expr.order.splice(1, 0, "CLASS");
4829 	Expr.find.CLASS = function(match, context, isXML) {
4830 		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
4831 			return context.getElementsByClassName(match[1]);
4832 		}
4833 	};
4834 
4835 	div = null; // release memory in IE
4836 })();
4837 
4838 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4839 	var sibDir = dir == "previousSibling" && !isXML;
4840 	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4841 		var elem = checkSet[i];
4842 		if ( elem ) {
4843 			if ( sibDir && elem.nodeType === 1 ){
4844 				elem.sizcache = doneName;
4845 				elem.sizset = i;
4846 			}
4847 			elem = elem[dir];
4848 			var match = false;
4849 
4850 			while ( elem ) {
4851 				if ( elem.sizcache === doneName ) {
4852 					match = checkSet[elem.sizset];
4853 					break;
4854 				}
4855 
4856 				if ( elem.nodeType === 1 && !isXML ){
4857 					elem.sizcache = doneName;
4858 					elem.sizset = i;
4859 				}
4860 
4861 				if ( elem.nodeName === cur ) {
4862 					match = elem;
4863 					break;
4864 				}
4865 
4866 				elem = elem[dir];
4867 			}
4868 
4869 			checkSet[i] = match;
4870 		}
4871 	}
4872 }
4873 
4874 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4875 	var sibDir = dir == "previousSibling" && !isXML;
4876 	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4877 		var elem = checkSet[i];
4878 		if ( elem ) {
4879 			if ( sibDir && elem.nodeType === 1 ) {
4880 				elem.sizcache = doneName;
4881 				elem.sizset = i;
4882 			}
4883 			elem = elem[dir];
4884 			var match = false;
4885 
4886 			while ( elem ) {
4887 				if ( elem.sizcache === doneName ) {
4888 					match = checkSet[elem.sizset];
4889 					break;
4890 				}
4891 
4892 				if ( elem.nodeType === 1 ) {
4893 					if ( !isXML ) {
4894 						elem.sizcache = doneName;
4895 						elem.sizset = i;
4896 					}
4897 					if ( typeof cur !== "string" ) {
4898 						if ( elem === cur ) {
4899 							match = true;
4900 							break;
4901 						}
4902 
4903 					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
4904 						match = elem;
4905 						break;
4906 					}
4907 				}
4908 
4909 				elem = elem[dir];
4910 			}
4911 
4912 			checkSet[i] = match;
4913 		}
4914 	}
4915 }
4916 
4917 var contains = document.compareDocumentPosition ?  function(a, b){
4918 	return a.compareDocumentPosition(b) & 16;
4919 } : function(a, b){
4920 	return a !== b && (a.contains ? a.contains(b) : true);
4921 };
4922 
4923 var isXML = function(elem){
4924 	return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
4925 		!!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
4926 };
4927 
4928 var posProcess = function(selector, context){
4929 	var tmpSet = [], later = "", match,
4930 		root = context.nodeType ? [context] : context;
4931 
4932 	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
4933 		later += match[0];
4934 		selector = selector.replace( Expr.match.PSEUDO, "" );
4935 	}
4936 
4937 	selector = Expr.relative[selector] ? selector + "*" : selector;
4938 
4939 	for ( var i = 0, l = root.length; i < l; i++ ) {
4940 		Sizzle( selector, root[i], tmpSet );
4941 	}
4942 
4943 	return Sizzle.filter( later, tmpSet );
4944 };
4945 
4946 
4947 window.Sizzle = Sizzle;
4948 
4949 })();
4950 
4951 ;(function(engine) {
4952   var extendElements = Prototype.Selector.extendElements;
4953 
4954   function select(selector, scope) {
4955     return extendElements(engine(selector, scope || document));
4956   }
4957 
4958   function match(element, selector) {
4959     return engine.matches(selector, [element]).length == 1;
4960   }
4961 
4962   Prototype.Selector.engine = engine;
4963   Prototype.Selector.select = select;
4964   Prototype.Selector.match = match;
4965 })(Sizzle);
4966 
4967 window.Sizzle = Prototype._original_property;
4968 delete Prototype._original_property;
4969 
4970 var Form = {
4971   reset: function(form) {
4972     form = $(form);
4973     form.reset();
4974     return form;
4975   },
4976 
4977   serializeElements: function(elements, options) {
4978     if (typeof options != 'object') options = { hash: !!options };
4979     else if (Object.isUndefined(options.hash)) options.hash = true;
4980     var key, value, submitted = false, submit = options.submit, accumulator, initial;
4981 
4982     if (options.hash) {
4983       initial = {};
4984       accumulator = function(result, key, value) {
4985         if (key in result) {
4986           if (!Object.isArray(result[key])) result[key] = [result[key]];
4987           result[key].push(value);
4988         } else result[key] = value;
4989         return result;
4990       };
4991     } else {
4992       initial = '';
4993       accumulator = function(result, key, value) {
4994         return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
4995       }
4996     }
4997 
4998     return elements.inject(initial, function(result, element) {
4999       if (!element.disabled && element.name) {
5000         key = element.name; value = $(element).getValue();
5001         if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
5002             submit !== false && (!submit || key == submit) && (submitted = true)))) {
5003           result = accumulator(result, key, value);
5004         }
5005       }
5006       return result;
5007     });
5008   }
5009 };
5010 
5011 Form.Methods = {
5012   serialize: function(form, options) {
5013     return Form.serializeElements(Form.getElements(form), options);
5014   },
5015 
5016   getElements: function(form) {
5017     var elements = $(form).getElementsByTagName('*'),
5018         element,
5019         arr = [ ],
5020         serializers = Form.Element.Serializers;
5021     for (var i = 0; element = elements[i]; i++) {
5022       arr.push(element);
5023     }
5024     return arr.inject([], function(elements, child) {
5025       if (serializers[child.tagName.toLowerCase()])
5026         elements.push(Element.extend(child));
5027       return elements;
5028     })
5029   },
5030 
5031   getInputs: function(form, typeName, name) {
5032     form = $(form);
5033     var inputs = form.getElementsByTagName('input');
5034 
5035     if (!typeName && !name) return $A(inputs).map(Element.extend);
5036 
5037     for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
5038       var input = inputs[i];
5039       if ((typeName && input.type != typeName) || (name && input.name != name))
5040         continue;
5041       matchingInputs.push(Element.extend(input));
5042     }
5043 
5044     return matchingInputs;
5045   },
5046 
5047   disable: function(form) {
5048     form = $(form);
5049     Form.getElements(form).invoke('disable');
5050     return form;
5051   },
5052 
5053   enable: function(form) {
5054     form = $(form);
5055     Form.getElements(form).invoke('enable');
5056     return form;
5057   },
5058 
5059   findFirstElement: function(form) {
5060     var elements = $(form).getElements().findAll(function(element) {
5061       return 'hidden' != element.type && !element.disabled;
5062     });
5063     var firstByIndex = elements.findAll(function(element) {
5064       return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
5065     }).sortBy(function(element) { return element.tabIndex }).first();
5066 
5067     return firstByIndex ? firstByIndex : elements.find(function(element) {
5068       return /^(?:input|select|textarea)$/i.test(element.tagName);
5069     });
5070   },
5071 
5072   focusFirstElement: function(form) {
5073     form = $(form);
5074     var element = form.findFirstElement();
5075     if (element) element.activate();
5076     return form;
5077   },
5078 
5079   request: function(form, options) {
5080     form = $(form), options = Object.clone(options || { });
5081 
5082     var params = options.parameters, action = form.readAttribute('action') || '';
5083     if (action.blank()) action = window.location.href;
5084     options.parameters = form.serialize(true);
5085 
5086     if (params) {
5087       if (Object.isString(params)) params = params.toQueryParams();
5088       Object.extend(options.parameters, params);
5089     }
5090 
5091     if (form.hasAttribute('method') && !options.method)
5092       options.method = form.method;
5093 
5094     return new Ajax.Request(action, options);
5095   }
5096 };
5097 
5098 /*--------------------------------------------------------------------------*/
5099 
5100 
5101 Form.Element = {
5102   focus: function(element) {
5103     $(element).focus();
5104     return element;
5105   },
5106 
5107   select: function(element) {
5108     $(element).select();
5109     return element;
5110   }
5111 };
5112 
5113 Form.Element.Methods = {
5114 
5115   serialize: function(element) {
5116     element = $(element);
5117     if (!element.disabled && element.name) {
5118       var value = element.getValue();
5119       if (value != undefined) {
5120         var pair = { };
5121         pair[element.name] = value;
5122         return Object.toQueryString(pair);
5123       }
5124     }
5125     return '';
5126   },
5127 
5128   getValue: function(element) {
5129     element = $(element);
5130     var method = element.tagName.toLowerCase();
5131     return Form.Element.Serializers[method](element);
5132   },
5133 
5134   setValue: function(element, value) {
5135     element = $(element);
5136     var method = element.tagName.toLowerCase();
5137     Form.Element.Serializers[method](element, value);
5138     return element;
5139   },
5140 
5141   clear: function(element) {
5142     $(element).value = '';
5143     return element;
5144   },
5145 
5146   present: function(element) {
5147     return $(element).value != '';
5148   },
5149 
5150   activate: function(element) {
5151     element = $(element);
5152     try {
5153       element.focus();
5154       if (element.select && (element.tagName.toLowerCase() != 'input' ||
5155           !(/^(?:button|reset|submit)$/i.test(element.type))))
5156         element.select();
5157     } catch (e) { }
5158     return element;
5159   },
5160 
5161   disable: function(element) {
5162     element = $(element);
5163     element.disabled = true;
5164     return element;
5165   },
5166 
5167   enable: function(element) {
5168     element = $(element);
5169     element.disabled = false;
5170     return element;
5171   }
5172 };
5173 
5174 /*--------------------------------------------------------------------------*/
5175 
5176 var Field = Form.Element;
5177 
5178 var $F = Form.Element.Methods.getValue;
5179 
5180 /*--------------------------------------------------------------------------*/
5181 
5182 Form.Element.Serializers = (function() {
5183   function input(element, value) {
5184     switch (element.type.toLowerCase()) {
5185       case 'checkbox':
5186       case 'radio':
5187         return inputSelector(element, value);
5188       default:
5189         return valueSelector(element, value);
5190     }
5191   }
5192 
5193   function inputSelector(element, value) {
5194     if (Object.isUndefined(value))
5195       return element.checked ? element.value : null;
5196     else element.checked = !!value;
5197   }
5198 
5199   function valueSelector(element, value) {
5200     if (Object.isUndefined(value)) return element.value;
5201     else element.value = value;
5202   }
5203 
5204   function select(element, value) {
5205     if (Object.isUndefined(value))
5206       return (element.type === 'select-one' ? selectOne : selectMany)(element);
5207 
5208     var opt, currentValue, single = !Object.isArray(value);
5209     for (var i = 0, length = element.length; i < length; i++) {
5210       opt = element.options[i];
5211       currentValue = this.optionValue(opt);
5212       if (single) {
5213         if (currentValue == value) {
5214           opt.selected = true;
5215           return;
5216         }
5217       }
5218       else opt.selected = value.include(currentValue);
5219     }
5220   }
5221 
5222   function selectOne(element) {
5223     var index = element.selectedIndex;
5224     return index >= 0 ? optionValue(element.options[index]) : null;
5225   }
5226 
5227   function selectMany(element) {
5228     var values, length = element.length;
5229     if (!length) return null;
5230 
5231     for (var i = 0, values = []; i < length; i++) {
5232       var opt = element.options[i];
5233       if (opt.selected) values.push(optionValue(opt));
5234     }
5235     return values;
5236   }
5237 
5238   function optionValue(opt) {
5239     return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
5240   }
5241 
5242   return {
5243     input:         input,
5244     inputSelector: inputSelector,
5245     textarea:      valueSelector,
5246     select:        select,
5247     selectOne:     selectOne,
5248     selectMany:    selectMany,
5249     optionValue:   optionValue,
5250     button:        valueSelector
5251   };
5252 })();
5253 
5254 /*--------------------------------------------------------------------------*/
5255 
5256 
5257 Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
5258   initialize: function($super, element, frequency, callback) {
5259     $super(callback, frequency);
5260     this.element   = $(element);
5261     this.lastValue = this.getValue();
5262   },
5263 
5264   execute: function() {
5265     var value = this.getValue();
5266     if (Object.isString(this.lastValue) && Object.isString(value) ?
5267         this.lastValue != value : String(this.lastValue) != String(value)) {
5268       this.callback(this.element, value);
5269       this.lastValue = value;
5270     }
5271   }
5272 });
5273 
5274 Form.Element.Observer = Class.create(Abstract.TimedObserver, {
5275   getValue: function() {
5276     return Form.Element.getValue(this.element);
5277   }
5278 });
5279 
5280 Form.Observer = Class.create(Abstract.TimedObserver, {
5281   getValue: function() {
5282     return Form.serialize(this.element);
5283   }
5284 });
5285 
5286 /*--------------------------------------------------------------------------*/
5287 
5288 Abstract.EventObserver = Class.create({
5289   initialize: function(element, callback) {
5290     this.element  = $(element);
5291     this.callback = callback;
5292 
5293     this.lastValue = this.getValue();
5294     if (this.element.tagName.toLowerCase() == 'form')
5295       this.registerFormCallbacks();
5296     else
5297       this.registerCallback(this.element);
5298   },
5299 
5300   onElementEvent: function() {
5301     var value = this.getValue();
5302     if (this.lastValue != value) {
5303       this.callback(this.element, value);
5304       this.lastValue = value;
5305     }
5306   },
5307 
5308   registerFormCallbacks: function() {
5309     Form.getElements(this.element).each(this.registerCallback, this);
5310   },
5311 
5312   registerCallback: function(element) {
5313     if (element.type) {
5314       switch (element.type.toLowerCase()) {
5315         case 'checkbox':
5316         case 'radio':
5317           Event.observe(element, 'click', this.onElementEvent.bind(this));
5318           break;
5319         default:
5320           Event.observe(element, 'change', this.onElementEvent.bind(this));
5321           break;
5322       }
5323     }
5324   }
5325 });
5326 
5327 Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
5328   getValue: function() {
5329     return Form.Element.getValue(this.element);
5330   }
5331 });
5332 
5333 Form.EventObserver = Class.create(Abstract.EventObserver, {
5334   getValue: function() {
5335     return Form.serialize(this.element);
5336   }
5337 });
5338 (function() {
5339 
5340   var Event = {
5341     KEY_BACKSPACE: 8,
5342     KEY_TAB:       9,
5343     KEY_RETURN:   13,
5344     KEY_ESC:      27,
5345     KEY_LEFT:     37,
5346     KEY_UP:       38,
5347     KEY_RIGHT:    39,
5348     KEY_DOWN:     40,
5349     KEY_DELETE:   46,
5350     KEY_HOME:     36,
5351     KEY_END:      35,
5352     KEY_PAGEUP:   33,
5353     KEY_PAGEDOWN: 34,
5354     KEY_INSERT:   45,
5355 
5356     cache: {}
5357   };
5358 
5359   var docEl = document.documentElement;
5360   var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
5361     && 'onmouseleave' in docEl;
5362 
5363 
5364 
5365   var isIELegacyEvent = function(event) { return false; };
5366 
5367   if (window.attachEvent) {
5368     if (window.addEventListener) {
5369       isIELegacyEvent = function(event) {
5370         return !(event instanceof window.Event);
5371       };
5372     } else {
5373       isIELegacyEvent = function(event) { return true; };
5374     }
5375   }
5376 
5377   var _isButton;
5378 
5379   function _isButtonForDOMEvents(event, code) {
5380     return event.which ? (event.which === code + 1) : (event.button === code);
5381   }
5382 
5383   var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
5384   function _isButtonForLegacyEvents(event, code) {
5385     return event.button === legacyButtonMap[code];
5386   }
5387 
5388   function _isButtonForWebKit(event, code) {
5389     switch (code) {
5390       case 0: return event.which == 1 && !event.metaKey;
5391       case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
5392       case 2: return event.which == 3;
5393       default: return false;
5394     }
5395   }
5396 
5397   if (window.attachEvent) {
5398     if (!window.addEventListener) {
5399       _isButton = _isButtonForLegacyEvents;
5400     } else {
5401       _isButton = function(event, code) {
5402         return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
5403          _isButtonForDOMEvents(event, code);
5404       }
5405     }
5406   } else if (Prototype.Browser.WebKit) {
5407     _isButton = _isButtonForWebKit;
5408   } else {
5409     _isButton = _isButtonForDOMEvents;
5410   }
5411 
5412   function isLeftClick(event)   { return _isButton(event, 0) }
5413 
5414   function isMiddleClick(event) { return _isButton(event, 1) }
5415 
5416   function isRightClick(event)  { return _isButton(event, 2) }
5417 
5418   function element(event) {
5419     event = Event.extend(event);
5420 
5421     var node = event.target, type = event.type,
5422      currentTarget = event.currentTarget;
5423 
5424     if (currentTarget && currentTarget.tagName) {
5425       if (type === 'load' || type === 'error' ||
5426         (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
5427           && currentTarget.type === 'radio'))
5428             node = currentTarget;
5429     }
5430 
5431     if (node.nodeType == Node.TEXT_NODE)
5432       node = node.parentNode;
5433 
5434     return Element.extend(node);
5435   }
5436 
5437   function findElement(event, expression) {
5438     var element = Event.element(event);
5439 
5440     if (!expression) return element;
5441     while (element) {
5442       if (Object.isElement(element) && Prototype.Selector.match(element, expression)) {
5443         return Element.extend(element);
5444       }
5445       element = element.parentNode;
5446     }
5447   }
5448 
5449   function pointer(event) {
5450     return { x: pointerX(event), y: pointerY(event) };
5451   }
5452 
5453   function pointerX(event) {
5454     var docElement = document.documentElement,
5455      body = document.body || { scrollLeft: 0 };
5456 
5457     return event.pageX || (event.clientX +
5458       (docElement.scrollLeft || body.scrollLeft) -
5459       (docElement.clientLeft || 0));
5460   }
5461 
5462   function pointerY(event) {
5463     var docElement = document.documentElement,
5464      body = document.body || { scrollTop: 0 };
5465 
5466     return  event.pageY || (event.clientY +
5467        (docElement.scrollTop || body.scrollTop) -
5468        (docElement.clientTop || 0));
5469   }
5470 
5471 
5472   function stop(event) {
5473     Event.extend(event);
5474     event.preventDefault();
5475     event.stopPropagation();
5476 
5477     event.stopped = true;
5478   }
5479 
5480 
5481   Event.Methods = {
5482     isLeftClick:   isLeftClick,
5483     isMiddleClick: isMiddleClick,
5484     isRightClick:  isRightClick,
5485 
5486     element:     element,
5487     findElement: findElement,
5488 
5489     pointer:  pointer,
5490     pointerX: pointerX,
5491     pointerY: pointerY,
5492 
5493     stop: stop
5494   };
5495 
5496   var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
5497     m[name] = Event.Methods[name].methodize();
5498     return m;
5499   });
5500 
5501   if (window.attachEvent) {
5502     function _relatedTarget(event) {
5503       var element;
5504       switch (event.type) {
5505         case 'mouseover':
5506         case 'mouseenter':
5507           element = event.fromElement;
5508           break;
5509         case 'mouseout':
5510         case 'mouseleave':
5511           element = event.toElement;
5512           break;
5513         default:
5514           return null;
5515       }
5516       return Element.extend(element);
5517     }
5518 
5519     var additionalMethods = {
5520       stopPropagation: function() { this.cancelBubble = true },
5521       preventDefault:  function() { this.returnValue = false },
5522       inspect: function() { return '[object Event]' }
5523     };
5524 
5525     Event.extend = function(event, element) {
5526       if (!event) return false;
5527 
5528       if (!isIELegacyEvent(event)) return event;
5529 
5530       if (event._extendedByPrototype) return event;
5531       event._extendedByPrototype = Prototype.emptyFunction;
5532 
5533       var pointer = Event.pointer(event);
5534 
5535       Object.extend(event, {
5536         target: event.srcElement || element,
5537         relatedTarget: _relatedTarget(event),
5538         pageX:  pointer.x,
5539         pageY:  pointer.y
5540       });
5541 
5542       Object.extend(event, methods);
5543       Object.extend(event, additionalMethods);
5544 
5545       return event;
5546     };
5547   } else {
5548     Event.extend = Prototype.K;
5549   }
5550 
5551   if (window.addEventListener) {
5552     Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
5553     Object.extend(Event.prototype, methods);
5554   }
5555 
5556   function _createResponder(element, eventName, handler) {
5557     var registry = Element.retrieve(element, 'prototype_event_registry');
5558 
5559     if (Object.isUndefined(registry)) {
5560       CACHE.push(element);
5561       registry = Element.retrieve(element, 'prototype_event_registry', $H());
5562     }
5563 
5564     var respondersForEvent = registry.get(eventName);
5565     if (Object.isUndefined(respondersForEvent)) {
5566       respondersForEvent = [];
5567       registry.set(eventName, respondersForEvent);
5568     }
5569 
5570     if (respondersForEvent.pluck('handler').include(handler)) return false;
5571 
5572     var responder;
5573     if (eventName.include(":")) {
5574       responder = function(event) {
5575         if (Object.isUndefined(event.eventName))
5576           return false;
5577 
5578         if (event.eventName !== eventName)
5579           return false;
5580 
5581         Event.extend(event, element);
5582         handler.call(element, event);
5583       };
5584     } else {
5585       if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
5586        (eventName === "mouseenter" || eventName === "mouseleave")) {
5587         if (eventName === "mouseenter" || eventName === "mouseleave") {
5588           responder = function(event) {
5589             Event.extend(event, element);
5590 
5591             var parent = event.relatedTarget;
5592             while (parent && parent !== element) {
5593               try { parent = parent.parentNode; }
5594               catch(e) { parent = element; }
5595             }
5596 
5597             if (parent === element) return;
5598 
5599             handler.call(element, event);
5600           };
5601         }
5602       } else {
5603         responder = function(event) {
5604           Event.extend(event, element);
5605           handler.call(element, event);
5606         };
5607       }
5608     }
5609 
5610     responder.handler = handler;
5611     respondersForEvent.push(responder);
5612     return responder;
5613   }
5614 
5615   function _destroyCache() {
5616     for (var i = 0, length = CACHE.length; i < length; i++) {
5617       Event.stopObserving(CACHE[i]);
5618       CACHE[i] = null;
5619     }
5620   }
5621 
5622   var CACHE = [];
5623 
5624   if (Prototype.Browser.IE)
5625     window.attachEvent('onunload', _destroyCache);
5626 
5627   if (Prototype.Browser.WebKit)
5628     window.addEventListener('unload', Prototype.emptyFunction, false);
5629 
5630 
5631   var _getDOMEventName = Prototype.K,
5632       translations = { mouseenter: "mouseover", mouseleave: "mouseout" };
5633 
5634   if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
5635     _getDOMEventName = function(eventName) {
5636       return (translations[eventName] || eventName);
5637     };
5638   }
5639 
5640   function observe(element, eventName, handler) {
5641     element = $(element);
5642 
5643     var responder = _createResponder(element, eventName, handler);
5644 
5645     if (!responder) return element;
5646 
5647     if (eventName.include(':')) {
5648       if (element.addEventListener)
5649         element.addEventListener("dataavailable", responder, false);
5650       else {
5651         element.attachEvent("ondataavailable", responder);
5652         element.attachEvent("onlosecapture", responder);
5653       }
5654     } else {
5655       var actualEventName = _getDOMEventName(eventName);
5656 
5657       if (element.addEventListener)
5658         element.addEventListener(actualEventName, responder, false);
5659       else
5660         element.attachEvent("on" + actualEventName, responder);
5661     }
5662 
5663     return element;
5664   }
5665 
5666   function stopObserving(element, eventName, handler) {
5667     element = $(element);
5668 
5669     var registry = Element.retrieve(element, 'prototype_event_registry');
5670     if (!registry) return element;
5671 
5672     if (!eventName) {
5673       registry.each( function(pair) {
5674         var eventName = pair.key;
5675         stopObserving(element, eventName);
5676       });
5677       return element;
5678     }
5679 
5680     var responders = registry.get(eventName);
5681     if (!responders) return element;
5682 
5683     if (!handler) {
5684       responders.each(function(r) {
5685         stopObserving(element, eventName, r.handler);
5686       });
5687       return element;
5688     }
5689 
5690     var i = responders.length, responder;
5691     while (i--) {
5692       if (responders[i].handler === handler) {
5693         responder = responders[i];
5694         break;
5695       }
5696     }
5697     if (!responder) return element;
5698 
5699     if (eventName.include(':')) {
5700       if (element.removeEventListener)
5701         element.removeEventListener("dataavailable", responder, false);
5702       else {
5703         element.detachEvent("ondataavailable", responder);
5704         element.detachEvent("onlosecapture", responder);
5705       }
5706     } else {
5707       var actualEventName = _getDOMEventName(eventName);
5708       if (element.removeEventListener)
5709         element.removeEventListener(actualEventName, responder, false);
5710       else
5711         element.detachEvent('on' + actualEventName, responder);
5712     }
5713 
5714     registry.set(eventName, responders.without(responder));
5715 
5716     return element;
5717   }
5718 
5719   function fire(element, eventName, memo, bubble) {
5720     element = $(element);
5721 
5722     if (Object.isUndefined(bubble))
5723       bubble = true;
5724 
5725     if (element == document && document.createEvent && !element.dispatchEvent)
5726       element = document.documentElement;
5727 
5728     var event;
5729     if (document.createEvent) {
5730       event = document.createEvent('HTMLEvents');
5731       event.initEvent('dataavailable', bubble, true);
5732     } else {
5733       event = document.createEventObject();
5734       event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
5735     }
5736 
5737     event.eventName = eventName;
5738     event.memo = memo || { };
5739 
5740     if (document.createEvent)
5741       element.dispatchEvent(event);
5742     else
5743       element.fireEvent(event.eventType, event);
5744 
5745     return Event.extend(event);
5746   }
5747 
5748   Event.Handler = Class.create({
5749     initialize: function(element, eventName, selector, callback) {
5750       this.element   = $(element);
5751       this.eventName = eventName;
5752       this.selector  = selector;
5753       this.callback  = callback;
5754       this.handler   = this.handleEvent.bind(this);
5755     },
5756 
5757     start: function() {
5758       Event.observe(this.element, this.eventName, this.handler);
5759       return this;
5760     },
5761 
5762     stop: function() {
5763       Event.stopObserving(this.element, this.eventName, this.handler);
5764       return this;
5765     },
5766 
5767     handleEvent: function(event) {
5768       var element = Event.findElement(event, this.selector);
5769       if (element) this.callback.call(this.element, event, element);
5770     }
5771   });
5772 
5773   function on(element, eventName, selector, callback) {
5774     element = $(element);
5775     if (Object.isFunction(selector) && Object.isUndefined(callback)) {
5776       callback = selector, selector = null;
5777     }
5778 
5779     return new Event.Handler(element, eventName, selector, callback).start();
5780   }
5781 
5782   Object.extend(Event, Event.Methods);
5783 
5784   Object.extend(Event, {
5785     fire:          fire,
5786     observe:       observe,
5787     stopObserving: stopObserving,
5788     on:            on
5789   });
5790 
5791   Element.addMethods({
5792     fire:          fire,
5793 
5794     observe:       observe,
5795 
5796     stopObserving: stopObserving,
5797 
5798     on:            on
5799   });
5800 
5801   Object.extend(document, {
5802     fire:          fire.methodize(),
5803 
5804     observe:       observe.methodize(),
5805 
5806     stopObserving: stopObserving.methodize(),
5807 
5808     on:            on.methodize(),
5809 
5810     loaded:        false
5811   });
5812 
5813   if (window.Event) Object.extend(window.Event, Event);
5814   else window.Event = Event;
5815 })();
5816 
5817 (function() {
5818   /* Support for the DOMContentLoaded event is based on work by Dan Webb,
5819      Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
5820 
5821   var timer;
5822 
5823   function fireContentLoadedEvent() {
5824     if (document.loaded) return;
5825     if (timer) window.clearTimeout(timer);
5826     document.loaded = true;
5827     document.fire('dom:loaded');
5828   }
5829 
5830   function checkReadyState() {
5831     if (document.readyState === 'complete') {
5832       document.stopObserving('readystatechange', checkReadyState);
5833       fireContentLoadedEvent();
5834     }
5835   }
5836 
5837   function pollDoScroll() {
5838     try { document.documentElement.doScroll('left'); }
5839     catch(e) {
5840       timer = pollDoScroll.defer();
5841       return;
5842     }
5843     fireContentLoadedEvent();
5844   }
5845 
5846   if (document.addEventListener) {
5847     document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
5848   } else {
5849     document.observe('readystatechange', checkReadyState);
5850     if (window == top)
5851       timer = pollDoScroll.defer();
5852   }
5853 
5854   Event.observe(window, 'load', fireContentLoadedEvent);
5855 })();
5856 
5857 Element.addMethods();
5858 
5859 /*------------------------------- DEPRECATED -------------------------------*/
5860 
5861 Hash.toQueryString = Object.toQueryString;
5862 
5863 var Toggle = { display: Element.toggle };
5864 
5865 Element.Methods.childOf = Element.Methods.descendantOf;
5866 
5867 var Insertion = {
5868   Before: function(element, content) {
5869     return Element.insert(element, {before:content});
5870   },
5871 
5872   Top: function(element, content) {
5873     return Element.insert(element, {top:content});
5874   },
5875 
5876   Bottom: function(element, content) {
5877     return Element.insert(element, {bottom:content});
5878   },
5879 
5880   After: function(element, content) {
5881     return Element.insert(element, {after:content});
5882   }
5883 };
5884 
5885 var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
5886 
5887 var Position = {
5888   includeScrollOffsets: false,
5889 
5890   prepare: function() {
5891     this.deltaX =  window.pageXOffset
5892                 || document.documentElement.scrollLeft
5893                 || document.body.scrollLeft
5894                 || 0;
5895     this.deltaY =  window.pageYOffset
5896                 || document.documentElement.scrollTop
5897                 || document.body.scrollTop
5898                 || 0;
5899   },
5900 
5901   within: function(element, x, y) {
5902     if (this.includeScrollOffsets)
5903       return this.withinIncludingScrolloffsets(element, x, y);
5904     this.xcomp = x;
5905     this.ycomp = y;
5906     this.offset = Element.cumulativeOffset(element);
5907 
5908     return (y >= this.offset[1] &&
5909             y <  this.offset[1] + element.offsetHeight &&
5910             x >= this.offset[0] &&
5911             x <  this.offset[0] + element.offsetWidth);
5912   },
5913 
5914   withinIncludingScrolloffsets: function(element, x, y) {
5915     var offsetcache = Element.cumulativeScrollOffset(element);
5916 
5917     this.xcomp = x + offsetcache[0] - this.deltaX;
5918     this.ycomp = y + offsetcache[1] - this.deltaY;
5919     this.offset = Element.cumulativeOffset(element);
5920 
5921     return (this.ycomp >= this.offset[1] &&
5922             this.ycomp <  this.offset[1] + element.offsetHeight &&
5923             this.xcomp >= this.offset[0] &&
5924             this.xcomp <  this.offset[0] + element.offsetWidth);
5925   },
5926 
5927   overlap: function(mode, element) {
5928     if (!mode) return 0;
5929     if (mode == 'vertical')
5930       return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
5931         element.offsetHeight;
5932     if (mode == 'horizontal')
5933       return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
5934         element.offsetWidth;
5935   },
5936 
5937 
5938   cumulativeOffset: Element.Methods.cumulativeOffset,
5939 
5940   positionedOffset: Element.Methods.positionedOffset,
5941 
5942   absolutize: function(element) {
5943     Position.prepare();
5944     return Element.absolutize(element);
5945   },
5946 
5947   relativize: function(element) {
5948     Position.prepare();
5949     return Element.relativize(element);
5950   },
5951 
5952   realOffset: Element.Methods.cumulativeScrollOffset,
5953 
5954   offsetParent: Element.Methods.getOffsetParent,
5955 
5956   page: Element.Methods.viewportOffset,
5957 
5958   clone: function(source, target, options) {
5959     options = options || { };
5960     return Element.clonePosition(target, source, options);
5961   }
5962 };
5963 
5964 /*--------------------------------------------------------------------------*/
5965 
5966 if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
5967   function iter(name) {
5968     return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
5969   }
5970 
5971   instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
5972   function(element, className) {
5973     className = className.toString().strip();
5974     var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
5975     return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
5976   } : function(element, className) {
5977     className = className.toString().strip();
5978     var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
5979     if (!classNames && !className) return elements;
5980 
5981     var nodes = $(element).getElementsByTagName('*');
5982     className = ' ' + className + ' ';
5983 
5984     for (var i = 0, child, cn; child = nodes[i]; i++) {
5985       if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
5986           (classNames && classNames.all(function(name) {
5987             return !name.toString().blank() && cn.include(' ' + name + ' ');
5988           }))))
5989         elements.push(Element.extend(child));
5990     }
5991     return elements;
5992   };
5993 
5994   return function(className, parentElement) {
5995     return $(parentElement || document.body).getElementsByClassName(className);
5996   };
5997 }(Element.Methods);
5998 
5999 /*--------------------------------------------------------------------------*/
6000 
6001 Element.ClassNames = Class.create();
6002 Element.ClassNames.prototype = {
6003   initialize: function(element) {
6004     this.element = $(element);
6005   },
6006 
6007   _each: function(iterator) {
6008     this.element.className.split(/\s+/).select(function(name) {
6009       return name.length > 0;
6010     })._each(iterator);
6011   },
6012 
6013   set: function(className) {
6014     this.element.className = className;
6015   },
6016 
6017   add: function(classNameToAdd) {
6018     if (this.include(classNameToAdd)) return;
6019     this.set($A(this).concat(classNameToAdd).join(' '));
6020   },
6021 
6022   remove: function(classNameToRemove) {
6023     if (!this.include(classNameToRemove)) return;
6024     this.set($A(this).without(classNameToRemove).join(' '));
6025   },
6026 
6027   toString: function() {
6028     return $A(this).join(' ');
6029   }
6030 };
6031 
6032 Object.extend(Element.ClassNames.prototype, Enumerable);
6033 
6034 /*--------------------------------------------------------------------------*/
6035 
6036 (function() {
6037   window.Selector = Class.create({
6038     initialize: function(expression) {
6039       this.expression = expression.strip();
6040     },
6041 
6042     findElements: function(rootElement) {
6043       return Prototype.Selector.select(this.expression, rootElement);
6044     },
6045 
6046     match: function(element) {
6047       return Prototype.Selector.match(element, this.expression);
6048     },
6049 
6050     toString: function() {
6051       return this.expression;
6052     },
6053 
6054     inspect: function() {
6055       return "#<Selector: " + this.expression + ">";
6056     }
6057   });
6058 
6059   Object.extend(Selector, {
6060     matchElements: function(elements, expression) {
6061       var match = Prototype.Selector.match,
6062           results = [];
6063 
6064       for (var i = 0, length = elements.length; i < length; i++) {
6065         var element = elements[i];
6066         if (match(element, expression)) {
6067           results.push(Element.extend(element));
6068         }
6069       }
6070       return results;
6071     },
6072 
6073     findElement: function(elements, expression, index) {
6074       index = index || 0;
6075       var matchIndex = 0, element;
6076       for (var i = 0, length = elements.length; i < length; i++) {
6077         element = elements[i];
6078         if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
6079           return Element.extend(element);
6080         }
6081       }
6082     },
6083 
6084     findChildElements: function(element, expressions) {
6085       var selector = expressions.toArray().join(', ');
6086       return Prototype.Selector.select(selector, element || document);
6087     }
6088   });
6089 })();
6090