refactoring brapi json responses
[sgn.git] / js / Prototype.js
blobcc89dafcd6ae69cf81adfea016a0f1a8d8341c58
1 /*  Prototype JavaScript framework, version 1.7.3
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  *--------------------------------------------------------------------------*/
9 var Prototype = {
11   Version: '1.7.3',
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   })(),
25   BrowserFeatures: {
26     XPath: !!document.evaluate,
28     SelectorsAPI: !!document.querySelector,
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;
38       var div = document.createElement('div'),
39           form = document.createElement('form'),
40           isSupported = false;
42       if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
43         isSupported = true;
44       }
46       div = form = null;
48       return isSupported;
49     })()
50   },
52   ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script\\s*>',
53   JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
55   emptyFunction: function() { },
57   K: function(x) { return x }
60 if (Prototype.Browser.MobileSafari)
61   Prototype.BrowserFeatures.SpecificElementExtensions = false;
62 /* Based on Alex Arnell's inheritance implementation. */
64 var Class = (function() {
66   var IS_DONTENUM_BUGGY = (function(){
67     for (var p in { toString: 1 }) {
68       if (p === 'toString') return false;
69     }
70     return true;
71   })();
73   function subclass() {};
74   function create() {
75     var parent = null, properties = $A(arguments);
76     if (Object.isFunction(properties[0]))
77       parent = properties.shift();
79     function klass() {
80       this.initialize.apply(this, arguments);
81     }
83     Object.extend(klass, Class.Methods);
84     klass.superclass = parent;
85     klass.subclasses = [];
87     if (parent) {
88       subclass.prototype = parent.prototype;
89       klass.prototype = new subclass;
90       parent.subclasses.push(klass);
91     }
93     for (var i = 0, length = properties.length; i < length; i++)
94       klass.addMethods(properties[i]);
96     if (!klass.prototype.initialize)
97       klass.prototype.initialize = Prototype.emptyFunction;
99     klass.prototype.constructor = klass;
100     return klass;
101   }
103   function addMethods(source) {
104     var ancestor   = this.superclass && this.superclass.prototype,
105         properties = Object.keys(source);
107     if (IS_DONTENUM_BUGGY) {
108       if (source.toString != Object.prototype.toString)
109         properties.push("toString");
110       if (source.valueOf != Object.prototype.valueOf)
111         properties.push("valueOf");
112     }
114     for (var i = 0, length = properties.length; i < length; i++) {
115       var property = properties[i], value = source[property];
116       if (ancestor && Object.isFunction(value) &&
117           value.argumentNames()[0] == "$super") {
118         var method = value;
119         value = (function(m) {
120           return function() { return ancestor[m].apply(this, arguments); };
121         })(property).wrap(method);
123         value.valueOf = (function(method) {
124           return function() { return method.valueOf.call(method); };
125         })(method);
127         value.toString = (function(method) {
128           return function() { return method.toString.call(method); };
129         })(method);
130       }
131       this.prototype[property] = value;
132     }
134     return this;
135   }
137   return {
138     create: create,
139     Methods: {
140       addMethods: addMethods
141     }
142   };
143 })();
144 (function() {
146   var _toString = Object.prototype.toString,
147       _hasOwnProperty = Object.prototype.hasOwnProperty,
148       NULL_TYPE = 'Null',
149       UNDEFINED_TYPE = 'Undefined',
150       BOOLEAN_TYPE = 'Boolean',
151       NUMBER_TYPE = 'Number',
152       STRING_TYPE = 'String',
153       OBJECT_TYPE = 'Object',
154       FUNCTION_CLASS = '[object Function]',
155       BOOLEAN_CLASS = '[object Boolean]',
156       NUMBER_CLASS = '[object Number]',
157       STRING_CLASS = '[object String]',
158       ARRAY_CLASS = '[object Array]',
159       DATE_CLASS = '[object Date]',
160       NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
161         typeof JSON.stringify === 'function' &&
162         JSON.stringify(0) === '0' &&
163         typeof JSON.stringify(Prototype.K) === 'undefined';
167   var DONT_ENUMS = ['toString', 'toLocaleString', 'valueOf',
168    'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
170   var IS_DONTENUM_BUGGY = (function(){
171     for (var p in { toString: 1 }) {
172       if (p === 'toString') return false;
173     }
174     return true;
175   })();
177   function Type(o) {
178     switch(o) {
179       case null: return NULL_TYPE;
180       case (void 0): return UNDEFINED_TYPE;
181     }
182     var type = typeof o;
183     switch(type) {
184       case 'boolean': return BOOLEAN_TYPE;
185       case 'number':  return NUMBER_TYPE;
186       case 'string':  return STRING_TYPE;
187     }
188     return OBJECT_TYPE;
189   }
191   function extend(destination, source) {
192     for (var property in source)
193       destination[property] = source[property];
194     return destination;
195   }
197   function inspect(object) {
198     try {
199       if (isUndefined(object)) return 'undefined';
200       if (object === null) return 'null';
201       return object.inspect ? object.inspect() : String(object);
202     } catch (e) {
203       if (e instanceof RangeError) return '...';
204       throw e;
205     }
206   }
208   function toJSON(value) {
209     return Str('', { '': value }, []);
210   }
212   function Str(key, holder, stack) {
213     var value = holder[key];
214     if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
215       value = value.toJSON(key);
216     }
218     var _class = _toString.call(value);
220     switch (_class) {
221       case NUMBER_CLASS:
222       case BOOLEAN_CLASS:
223       case STRING_CLASS:
224         value = value.valueOf();
225     }
227     switch (value) {
228       case null: return 'null';
229       case true: return 'true';
230       case false: return 'false';
231     }
233     var type = typeof value;
234     switch (type) {
235       case 'string':
236         return value.inspect(true);
237       case 'number':
238         return isFinite(value) ? String(value) : 'null';
239       case 'object':
241         for (var i = 0, length = stack.length; i < length; i++) {
242           if (stack[i] === value) {
243             throw new TypeError("Cyclic reference to '" + value + "' in object");
244           }
245         }
246         stack.push(value);
248         var partial = [];
249         if (_class === ARRAY_CLASS) {
250           for (var i = 0, length = value.length; i < length; i++) {
251             var str = Str(i, value, stack);
252             partial.push(typeof str === 'undefined' ? 'null' : str);
253           }
254           partial = '[' + partial.join(',') + ']';
255         } else {
256           var keys = Object.keys(value);
257           for (var i = 0, length = keys.length; i < length; i++) {
258             var key = keys[i], str = Str(key, value, stack);
259             if (typeof str !== "undefined") {
260                partial.push(key.inspect(true)+ ':' + str);
261              }
262           }
263           partial = '{' + partial.join(',') + '}';
264         }
265         stack.pop();
266         return partial;
267     }
268   }
270   function stringify(object) {
271     return JSON.stringify(object);
272   }
274   function toQueryString(object) {
275     return $H(object).toQueryString();
276   }
278   function toHTML(object) {
279     return object && object.toHTML ? object.toHTML() : String.interpret(object);
280   }
282   function keys(object) {
283     if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
284     var results = [];
285     for (var property in object) {
286       if (_hasOwnProperty.call(object, property))
287         results.push(property);
288     }
290     if (IS_DONTENUM_BUGGY) {
291       for (var i = 0; property = DONT_ENUMS[i]; i++) {
292         if (_hasOwnProperty.call(object, property))
293           results.push(property);
294       }
295     }
297     return results;
298   }
300   function values(object) {
301     var results = [];
302     for (var property in object)
303       results.push(object[property]);
304     return results;
305   }
307   function clone(object) {
308     return extend({ }, object);
309   }
311   function isElement(object) {
312     return !!(object && object.nodeType == 1);
313   }
315   function isArray(object) {
316     return _toString.call(object) === ARRAY_CLASS;
317   }
319   var hasNativeIsArray = (typeof Array.isArray == 'function')
320     && Array.isArray([]) && !Array.isArray({});
322   if (hasNativeIsArray) {
323     isArray = Array.isArray;
324   }
326   function isHash(object) {
327     return object instanceof Hash;
328   }
330   function isFunction(object) {
331     return _toString.call(object) === FUNCTION_CLASS;
332   }
334   function isString(object) {
335     return _toString.call(object) === STRING_CLASS;
336   }
338   function isNumber(object) {
339     return _toString.call(object) === NUMBER_CLASS;
340   }
342   function isDate(object) {
343     return _toString.call(object) === DATE_CLASS;
344   }
346   function isUndefined(object) {
347     return typeof object === "undefined";
348   }
350   extend(Object, {
351     extend:        extend,
352     inspect:       inspect,
353     toJSON:        NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
354     toQueryString: toQueryString,
355     toHTML:        toHTML,
356     keys:          Object.keys || keys,
357     values:        values,
358     clone:         clone,
359     isElement:     isElement,
360     isArray:       isArray,
361     isHash:        isHash,
362     isFunction:    isFunction,
363     isString:      isString,
364     isNumber:      isNumber,
365     isDate:        isDate,
366     isUndefined:   isUndefined
367   });
368 })();
369 Object.extend(Function.prototype, (function() {
370   var slice = Array.prototype.slice;
372   function update(array, args) {
373     var arrayLength = array.length, length = args.length;
374     while (length--) array[arrayLength + length] = args[length];
375     return array;
376   }
378   function merge(array, args) {
379     array = slice.call(array, 0);
380     return update(array, args);
381   }
383   function argumentNames() {
384     var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
385       .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
386       .replace(/\s+/g, '').split(',');
387     return names.length == 1 && !names[0] ? [] : names;
388   }
391   function bind(context) {
392     if (arguments.length < 2 && Object.isUndefined(arguments[0]))
393       return this;
395     if (!Object.isFunction(this))
396       throw new TypeError("The object is not callable.");
398     var nop = function() {};
399     var __method = this, args = slice.call(arguments, 1);
401     var bound = function() {
402       var a = merge(args, arguments);
403       var c = this instanceof bound ? this : context;
404       return __method.apply(c, a);
405     };
407     nop.prototype   = this.prototype;
408     bound.prototype = new nop();
410     return bound;
411   }
413   function bindAsEventListener(context) {
414     var __method = this, args = slice.call(arguments, 1);
415     return function(event) {
416       var a = update([event || window.event], args);
417       return __method.apply(context, a);
418     }
419   }
421   function curry() {
422     if (!arguments.length) return this;
423     var __method = this, args = slice.call(arguments, 0);
424     return function() {
425       var a = merge(args, arguments);
426       return __method.apply(this, a);
427     }
428   }
430   function delay(timeout) {
431     var __method = this, args = slice.call(arguments, 1);
432     timeout = timeout * 1000;
433     return window.setTimeout(function() {
434       return __method.apply(__method, args);
435     }, timeout);
436   }
438   function defer() {
439     var args = update([0.01], arguments);
440     return this.delay.apply(this, args);
441   }
443   function wrap(wrapper) {
444     var __method = this;
445     return function() {
446       var a = update([__method.bind(this)], arguments);
447       return wrapper.apply(this, a);
448     }
449   }
451   function methodize() {
452     if (this._methodized) return this._methodized;
453     var __method = this;
454     return this._methodized = function() {
455       var a = update([this], arguments);
456       return __method.apply(null, a);
457     };
458   }
460   var extensions = {
461     argumentNames:       argumentNames,
462     bindAsEventListener: bindAsEventListener,
463     curry:               curry,
464     delay:               delay,
465     defer:               defer,
466     wrap:                wrap,
467     methodize:           methodize
468   };
470   if (!Function.prototype.bind)
471     extensions.bind = bind;
473   return extensions;
474 })());
478 (function(proto) {
481   function toISOString() {
482     return this.getUTCFullYear() + '-' +
483       (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
484       this.getUTCDate().toPaddedString(2) + 'T' +
485       this.getUTCHours().toPaddedString(2) + ':' +
486       this.getUTCMinutes().toPaddedString(2) + ':' +
487       this.getUTCSeconds().toPaddedString(2) + 'Z';
488   }
491   function toJSON() {
492     return this.toISOString();
493   }
495   if (!proto.toISOString) proto.toISOString = toISOString;
496   if (!proto.toJSON) proto.toJSON = toJSON;
498 })(Date.prototype);
501 RegExp.prototype.match = RegExp.prototype.test;
503 RegExp.escape = function(str) {
504   return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
506 var PeriodicalExecuter = Class.create({
507   initialize: function(callback, frequency) {
508     this.callback = callback;
509     this.frequency = frequency;
510     this.currentlyExecuting = false;
512     this.registerCallback();
513   },
515   registerCallback: function() {
516     this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
517   },
519   execute: function() {
520     this.callback(this);
521   },
523   stop: function() {
524     if (!this.timer) return;
525     clearInterval(this.timer);
526     this.timer = null;
527   },
529   onTimerEvent: function() {
530     if (!this.currentlyExecuting) {
531       try {
532         this.currentlyExecuting = true;
533         this.execute();
534         this.currentlyExecuting = false;
535       } catch(e) {
536         this.currentlyExecuting = false;
537         throw e;
538       }
539     }
540   }
542 Object.extend(String, {
543   interpret: function(value) {
544     return value == null ? '' : String(value);
545   },
546   specialChar: {
547     '\b': '\\b',
548     '\t': '\\t',
549     '\n': '\\n',
550     '\f': '\\f',
551     '\r': '\\r',
552     '\\': '\\\\'
553   }
556 Object.extend(String.prototype, (function() {
557   var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
558     typeof JSON.parse === 'function' &&
559     JSON.parse('{"test": true}').test;
561   function prepareReplacement(replacement) {
562     if (Object.isFunction(replacement)) return replacement;
563     var template = new Template(replacement);
564     return function(match) { return template.evaluate(match) };
565   }
567   function isNonEmptyRegExp(regexp) {
568     return regexp.source && regexp.source !== '(?:)';
569   }
572   function gsub(pattern, replacement) {
573     var result = '', source = this, match;
574     replacement = prepareReplacement(replacement);
576     if (Object.isString(pattern))
577       pattern = RegExp.escape(pattern);
579     if (!(pattern.length || isNonEmptyRegExp(pattern))) {
580       replacement = replacement('');
581       return replacement + source.split('').join(replacement) + replacement;
582     }
584     while (source.length > 0) {
585       match = source.match(pattern)
586       if (match && match[0].length > 0) {
587         result += source.slice(0, match.index);
588         result += String.interpret(replacement(match));
589         source  = source.slice(match.index + match[0].length);
590       } else {
591         result += source, source = '';
592       }
593     }
594     return result;
595   }
597   function sub(pattern, replacement, count) {
598     replacement = prepareReplacement(replacement);
599     count = Object.isUndefined(count) ? 1 : count;
601     return this.gsub(pattern, function(match) {
602       if (--count < 0) return match[0];
603       return replacement(match);
604     });
605   }
607   function scan(pattern, iterator) {
608     this.gsub(pattern, iterator);
609     return String(this);
610   }
612   function truncate(length, truncation) {
613     length = length || 30;
614     truncation = Object.isUndefined(truncation) ? '...' : truncation;
615     return this.length > length ?
616       this.slice(0, length - truncation.length) + truncation : String(this);
617   }
619   function strip() {
620     return this.replace(/^\s+/, '').replace(/\s+$/, '');
621   }
623   function stripTags() {
624     return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?(\/)?>|<\/\w+>/gi, '');
625   }
627   function stripScripts() {
628     return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
629   }
631   function extractScripts() {
632     var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
633         matchOne = new RegExp(Prototype.ScriptFragment, 'im');
634     return (this.match(matchAll) || []).map(function(scriptTag) {
635       return (scriptTag.match(matchOne) || ['', ''])[1];
636     });
637   }
639   function evalScripts() {
640     return this.extractScripts().map(function(script) { return eval(script); });
641   }
643   function escapeHTML() {
644     return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
645   }
647   function unescapeHTML() {
648     return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
649   }
652   function toQueryParams(separator) {
653     var match = this.strip().match(/([^?#]*)(#.*)?$/);
654     if (!match) return { };
656     return match[1].split(separator || '&').inject({ }, function(hash, pair) {
657       if ((pair = pair.split('='))[0]) {
658         var key = decodeURIComponent(pair.shift()),
659             value = pair.length > 1 ? pair.join('=') : pair[0];
661         if (value != undefined) {
662           value = value.gsub('+', ' ');
663           value = decodeURIComponent(value);
664         }
666         if (key in hash) {
667           if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
668           hash[key].push(value);
669         }
670         else hash[key] = value;
671       }
672       return hash;
673     });
674   }
676   function toArray() {
677     return this.split('');
678   }
680   function succ() {
681     return this.slice(0, this.length - 1) +
682       String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
683   }
685   function times(count) {
686     return count < 1 ? '' : new Array(count + 1).join(this);
687   }
689   function camelize() {
690     return this.replace(/-+(.)?/g, function(match, chr) {
691       return chr ? chr.toUpperCase() : '';
692     });
693   }
695   function capitalize() {
696     return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
697   }
699   function underscore() {
700     return this.replace(/::/g, '/')
701                .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
702                .replace(/([a-z\d])([A-Z])/g, '$1_$2')
703                .replace(/-/g, '_')
704                .toLowerCase();
705   }
707   function dasherize() {
708     return this.replace(/_/g, '-');
709   }
711   function inspect(useDoubleQuotes) {
712     var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
713       if (character in String.specialChar) {
714         return String.specialChar[character];
715       }
716       return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
717     });
718     if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
719     return "'" + escapedString.replace(/'/g, '\\\'') + "'";
720   }
722   function unfilterJSON(filter) {
723     return this.replace(filter || Prototype.JSONFilter, '$1');
724   }
726   function isJSON() {
727     var str = this;
728     if (str.blank()) return false;
729     str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
730     str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
731     str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
732     return (/^[\],:{}\s]*$/).test(str);
733   }
735   function evalJSON(sanitize) {
736     var json = this.unfilterJSON(),
737         cx = /[\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff\u0000]/g;
738     if (cx.test(json)) {
739       json = json.replace(cx, function (a) {
740         return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
741       });
742     }
743     try {
744       if (!sanitize || json.isJSON()) return eval('(' + json + ')');
745     } catch (e) { }
746     throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
747   }
749   function parseJSON() {
750     var json = this.unfilterJSON();
751     return JSON.parse(json);
752   }
754   function include(pattern) {
755     return this.indexOf(pattern) > -1;
756   }
758   function startsWith(pattern, position) {
759     position = Object.isNumber(position) ? position : 0;
760     return this.lastIndexOf(pattern, position) === position;
761   }
763   function endsWith(pattern, position) {
764     pattern = String(pattern);
765     position = Object.isNumber(position) ? position : this.length;
766     if (position < 0) position = 0;
767     if (position > this.length) position = this.length;
768     var d = position - pattern.length;
769     return d >= 0 && this.indexOf(pattern, d) === d;
770   }
772   function empty() {
773     return this == '';
774   }
776   function blank() {
777     return /^\s*$/.test(this);
778   }
780   function interpolate(object, pattern) {
781     return new Template(this, pattern).evaluate(object);
782   }
784   return {
785     gsub:           gsub,
786     sub:            sub,
787     scan:           scan,
788     truncate:       truncate,
789     strip:          String.prototype.trim || strip,
790     stripTags:      stripTags,
791     stripScripts:   stripScripts,
792     extractScripts: extractScripts,
793     evalScripts:    evalScripts,
794     escapeHTML:     escapeHTML,
795     unescapeHTML:   unescapeHTML,
796     toQueryParams:  toQueryParams,
797     parseQuery:     toQueryParams,
798     toArray:        toArray,
799     succ:           succ,
800     times:          times,
801     camelize:       camelize,
802     capitalize:     capitalize,
803     underscore:     underscore,
804     dasherize:      dasherize,
805     inspect:        inspect,
806     unfilterJSON:   unfilterJSON,
807     isJSON:         isJSON,
808     evalJSON:       NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
809     include:        include,
810     startsWith:     String.prototype.startsWith || startsWith,
811     endsWith:       String.prototype.endsWith || endsWith,
812     empty:          empty,
813     blank:          blank,
814     interpolate:    interpolate
815   };
816 })());
818 var Template = Class.create({
819   initialize: function(template, pattern) {
820     this.template = template.toString();
821     this.pattern = pattern || Template.Pattern;
822   },
824   evaluate: function(object) {
825     if (object && Object.isFunction(object.toTemplateReplacements))
826       object = object.toTemplateReplacements();
828     return this.template.gsub(this.pattern, function(match) {
829       if (object == null) return (match[1] + '');
831       var before = match[1] || '';
832       if (before == '\\') return match[2];
834       var ctx = object, expr = match[3],
835           pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
837       match = pattern.exec(expr);
838       if (match == null) return before;
840       while (match != null) {
841         var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
842         ctx = ctx[comp];
843         if (null == ctx || '' == match[3]) break;
844         expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
845         match = pattern.exec(expr);
846       }
848       return before + String.interpret(ctx);
849     });
850   }
852 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
854 var $break = { };
856 var Enumerable = (function() {
857   function each(iterator, context) {
858     try {
859       this._each(iterator, context);
860     } catch (e) {
861       if (e != $break) throw e;
862     }
863     return this;
864   }
866   function eachSlice(number, iterator, context) {
867     var index = -number, slices = [], array = this.toArray();
868     if (number < 1) return array;
869     while ((index += number) < array.length)
870       slices.push(array.slice(index, index+number));
871     return slices.collect(iterator, context);
872   }
874   function all(iterator, context) {
875     iterator = iterator || Prototype.K;
876     var result = true;
877     this.each(function(value, index) {
878       result = result && !!iterator.call(context, value, index, this);
879       if (!result) throw $break;
880     }, this);
881     return result;
882   }
884   function any(iterator, context) {
885     iterator = iterator || Prototype.K;
886     var result = false;
887     this.each(function(value, index) {
888       if (result = !!iterator.call(context, value, index, this))
889         throw $break;
890     }, this);
891     return result;
892   }
894   function collect(iterator, context) {
895     iterator = iterator || Prototype.K;
896     var results = [];
897     this.each(function(value, index) {
898       results.push(iterator.call(context, value, index, this));
899     }, this);
900     return results;
901   }
903   function detect(iterator, context) {
904     var result;
905     this.each(function(value, index) {
906       if (iterator.call(context, value, index, this)) {
907         result = value;
908         throw $break;
909       }
910     }, this);
911     return result;
912   }
914   function findAll(iterator, context) {
915     var results = [];
916     this.each(function(value, index) {
917       if (iterator.call(context, value, index, this))
918         results.push(value);
919     }, this);
920     return results;
921   }
923   function grep(filter, iterator, context) {
924     iterator = iterator || Prototype.K;
925     var results = [];
927     if (Object.isString(filter))
928       filter = new RegExp(RegExp.escape(filter));
930     this.each(function(value, index) {
931       if (filter.match(value))
932         results.push(iterator.call(context, value, index, this));
933     }, this);
934     return results;
935   }
937   function include(object) {
938     if (Object.isFunction(this.indexOf) && this.indexOf(object) != -1)
939       return true;
941     var found = false;
942     this.each(function(value) {
943       if (value == object) {
944         found = true;
945         throw $break;
946       }
947     });
948     return found;
949   }
951   function inGroupsOf(number, fillWith) {
952     fillWith = Object.isUndefined(fillWith) ? null : fillWith;
953     return this.eachSlice(number, function(slice) {
954       while(slice.length < number) slice.push(fillWith);
955       return slice;
956     });
957   }
959   function inject(memo, iterator, context) {
960     this.each(function(value, index) {
961       memo = iterator.call(context, memo, value, index, this);
962     }, this);
963     return memo;
964   }
966   function invoke(method) {
967     var args = $A(arguments).slice(1);
968     return this.map(function(value) {
969       return value[method].apply(value, args);
970     });
971   }
973   function max(iterator, context) {
974     iterator = iterator || Prototype.K;
975     var result;
976     this.each(function(value, index) {
977       value = iterator.call(context, value, index, this);
978       if (result == null || value >= result)
979         result = value;
980     }, this);
981     return result;
982   }
984   function min(iterator, context) {
985     iterator = iterator || Prototype.K;
986     var result;
987     this.each(function(value, index) {
988       value = iterator.call(context, value, index, this);
989       if (result == null || value < result)
990         result = value;
991     }, this);
992     return result;
993   }
995   function partition(iterator, context) {
996     iterator = iterator || Prototype.K;
997     var trues = [], falses = [];
998     this.each(function(value, index) {
999       (iterator.call(context, value, index, this) ?
1000         trues : falses).push(value);
1001     }, this);
1002     return [trues, falses];
1003   }
1005   function pluck(property) {
1006     var results = [];
1007     this.each(function(value) {
1008       results.push(value[property]);
1009     });
1010     return results;
1011   }
1013   function reject(iterator, context) {
1014     var results = [];
1015     this.each(function(value, index) {
1016       if (!iterator.call(context, value, index, this))
1017         results.push(value);
1018     }, this);
1019     return results;
1020   }
1022   function sortBy(iterator, context) {
1023     return this.map(function(value, index) {
1024       return {
1025         value: value,
1026         criteria: iterator.call(context, value, index, this)
1027       };
1028     }, this).sort(function(left, right) {
1029       var a = left.criteria, b = right.criteria;
1030       return a < b ? -1 : a > b ? 1 : 0;
1031     }).pluck('value');
1032   }
1034   function toArray() {
1035     return this.map();
1036   }
1038   function zip() {
1039     var iterator = Prototype.K, args = $A(arguments);
1040     if (Object.isFunction(args.last()))
1041       iterator = args.pop();
1043     var collections = [this].concat(args).map($A);
1044     return this.map(function(value, index) {
1045       return iterator(collections.pluck(index));
1046     });
1047   }
1049   function size() {
1050     return this.toArray().length;
1051   }
1053   function inspect() {
1054     return '#<Enumerable:' + this.toArray().inspect() + '>';
1055   }
1065   return {
1066     each:       each,
1067     eachSlice:  eachSlice,
1068     all:        all,
1069     every:      all,
1070     any:        any,
1071     some:       any,
1072     collect:    collect,
1073     map:        collect,
1074     detect:     detect,
1075     findAll:    findAll,
1076     select:     findAll,
1077     filter:     findAll,
1078     grep:       grep,
1079     include:    include,
1080     member:     include,
1081     inGroupsOf: inGroupsOf,
1082     inject:     inject,
1083     invoke:     invoke,
1084     max:        max,
1085     min:        min,
1086     partition:  partition,
1087     pluck:      pluck,
1088     reject:     reject,
1089     sortBy:     sortBy,
1090     toArray:    toArray,
1091     entries:    toArray,
1092     zip:        zip,
1093     size:       size,
1094     inspect:    inspect,
1095     find:       detect
1096   };
1097 })();
1099 function $A(iterable) {
1100   if (!iterable) return [];
1101   if ('toArray' in Object(iterable)) return iterable.toArray();
1102   var length = iterable.length || 0, results = new Array(length);
1103   while (length--) results[length] = iterable[length];
1104   return results;
1108 function $w(string) {
1109   if (!Object.isString(string)) return [];
1110   string = string.strip();
1111   return string ? string.split(/\s+/) : [];
1114 Array.from = $A;
1117 (function() {
1118   var arrayProto = Array.prototype,
1119       slice = arrayProto.slice,
1120       _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
1122   function each(iterator, context) {
1123     for (var i = 0, length = this.length >>> 0; i < length; i++) {
1124       if (i in this) iterator.call(context, this[i], i, this);
1125     }
1126   }
1127   if (!_each) _each = each;
1129   function clear() {
1130     this.length = 0;
1131     return this;
1132   }
1134   function first() {
1135     return this[0];
1136   }
1138   function last() {
1139     return this[this.length - 1];
1140   }
1142   function compact() {
1143     return this.select(function(value) {
1144       return value != null;
1145     });
1146   }
1148   function flatten() {
1149     return this.inject([], function(array, value) {
1150       if (Object.isArray(value))
1151         return array.concat(value.flatten());
1152       array.push(value);
1153       return array;
1154     });
1155   }
1157   function without() {
1158     var values = slice.call(arguments, 0);
1159     return this.select(function(value) {
1160       return !values.include(value);
1161     });
1162   }
1164   function reverse(inline) {
1165     return (inline === false ? this.toArray() : this)._reverse();
1166   }
1168   function uniq(sorted) {
1169     return this.inject([], function(array, value, index) {
1170       if (0 == index || (sorted ? array.last() != value : !array.include(value)))
1171         array.push(value);
1172       return array;
1173     });
1174   }
1176   function intersect(array) {
1177     return this.uniq().findAll(function(item) {
1178       return array.indexOf(item) !== -1;
1179     });
1180   }
1183   function clone() {
1184     return slice.call(this, 0);
1185   }
1187   function size() {
1188     return this.length;
1189   }
1191   function inspect() {
1192     return '[' + this.map(Object.inspect).join(', ') + ']';
1193   }
1195   function indexOf(item, i) {
1196     if (this == null) throw new TypeError();
1198     var array = Object(this), length = array.length >>> 0;
1199     if (length === 0) return -1;
1201     i = Number(i);
1202     if (isNaN(i)) {
1203       i = 0;
1204     } else if (i !== 0 && isFinite(i)) {
1205       i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
1206     }
1208     if (i > length) return -1;
1210     var k = i >= 0 ? i : Math.max(length - Math.abs(i), 0);
1211     for (; k < length; k++)
1212       if (k in array && array[k] === item) return k;
1213     return -1;
1214   }
1217   function lastIndexOf(item, i) {
1218     if (this == null) throw new TypeError();
1220     var array = Object(this), length = array.length >>> 0;
1221     if (length === 0) return -1;
1223     if (!Object.isUndefined(i)) {
1224       i = Number(i);
1225       if (isNaN(i)) {
1226         i = 0;
1227       } else if (i !== 0 && isFinite(i)) {
1228         i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
1229       }
1230     } else {
1231       i = length;
1232     }
1234     var k = i >= 0 ? Math.min(i, length - 1) :
1235      length - Math.abs(i);
1237     for (; k >= 0; k--)
1238       if (k in array && array[k] === item) return k;
1239     return -1;
1240   }
1242   function concat(_) {
1243     var array = [], items = slice.call(arguments, 0), item, n = 0;
1244     items.unshift(this);
1245     for (var i = 0, length = items.length; i < length; i++) {
1246       item = items[i];
1247       if (Object.isArray(item) && !('callee' in item)) {
1248         for (var j = 0, arrayLength = item.length; j < arrayLength; j++) {
1249           if (j in item) array[n] = item[j];
1250           n++;
1251         }
1252       } else {
1253         array[n++] = item;
1254       }
1255     }
1256     array.length = n;
1257     return array;
1258   }
1261   function wrapNative(method) {
1262     return function() {
1263       if (arguments.length === 0) {
1264         return method.call(this, Prototype.K);
1265       } else if (arguments[0] === undefined) {
1266         var args = slice.call(arguments, 1);
1267         args.unshift(Prototype.K);
1268         return method.apply(this, args);
1269       } else {
1270         return method.apply(this, arguments);
1271       }
1272     };
1273   }
1276   function map(iterator) {
1277     if (this == null) throw new TypeError();
1278     iterator = iterator || Prototype.K;
1280     var object = Object(this);
1281     var results = [], context = arguments[1], n = 0;
1283     for (var i = 0, length = object.length >>> 0; i < length; i++) {
1284       if (i in object) {
1285         results[n] = iterator.call(context, object[i], i, object);
1286       }
1287       n++;
1288     }
1289     results.length = n;
1290     return results;
1291   }
1293   if (arrayProto.map) {
1294     map = wrapNative(Array.prototype.map);
1295   }
1297   function filter(iterator) {
1298     if (this == null || !Object.isFunction(iterator))
1299       throw new TypeError();
1301     var object = Object(this);
1302     var results = [], context = arguments[1], value;
1304     for (var i = 0, length = object.length >>> 0; i < length; i++) {
1305       if (i in object) {
1306         value = object[i];
1307         if (iterator.call(context, value, i, object)) {
1308           results.push(value);
1309         }
1310       }
1311     }
1312     return results;
1313   }
1315   if (arrayProto.filter) {
1316     filter = Array.prototype.filter;
1317   }
1319   function some(iterator) {
1320     if (this == null) throw new TypeError();
1321     iterator = iterator || Prototype.K;
1322     var context = arguments[1];
1324     var object = Object(this);
1325     for (var i = 0, length = object.length >>> 0; i < length; i++) {
1326       if (i in object && iterator.call(context, object[i], i, object)) {
1327         return true;
1328       }
1329     }
1331     return false;
1332   }
1334   if (arrayProto.some) {
1335     some = wrapNative(Array.prototype.some);
1336   }
1338   function every(iterator) {
1339     if (this == null) throw new TypeError();
1340     iterator = iterator || Prototype.K;
1341     var context = arguments[1];
1343     var object = Object(this);
1344     for (var i = 0, length = object.length >>> 0; i < length; i++) {
1345       if (i in object && !iterator.call(context, object[i], i, object)) {
1346         return false;
1347       }
1348     }
1350     return true;
1351   }
1353   if (arrayProto.every) {
1354     every = wrapNative(Array.prototype.every);
1355   }
1358   Object.extend(arrayProto, Enumerable);
1360   if (arrayProto.entries === Enumerable.entries) {
1361     delete arrayProto.entries;
1362   }
1364   if (!arrayProto._reverse)
1365     arrayProto._reverse = arrayProto.reverse;
1367   Object.extend(arrayProto, {
1368     _each:     _each,
1370     map:       map,
1371     collect:   map,
1372     select:    filter,
1373     filter:    filter,
1374     findAll:   filter,
1375     some:      some,
1376     any:       some,
1377     every:     every,
1378     all:       every,
1380     clear:     clear,
1381     first:     first,
1382     last:      last,
1383     compact:   compact,
1384     flatten:   flatten,
1385     without:   without,
1386     reverse:   reverse,
1387     uniq:      uniq,
1388     intersect: intersect,
1389     clone:     clone,
1390     toArray:   clone,
1391     size:      size,
1392     inspect:   inspect
1393   });
1395   var CONCAT_ARGUMENTS_BUGGY = (function() {
1396     return [].concat(arguments)[0][0] !== 1;
1397   })(1,2);
1399   if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
1401   if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
1402   if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
1403 })();
1404 function $H(object) {
1405   return new Hash(object);
1408 var Hash = Class.create(Enumerable, (function() {
1409   function initialize(object) {
1410     this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1411   }
1414   function _each(iterator, context) {
1415     var i = 0;
1416     for (var key in this._object) {
1417       var value = this._object[key], pair = [key, value];
1418       pair.key = key;
1419       pair.value = value;
1420       iterator.call(context, pair, i);
1421       i++;
1422     }
1423   }
1425   function set(key, value) {
1426     return this._object[key] = value;
1427   }
1429   function get(key) {
1430     if (this._object[key] !== Object.prototype[key])
1431       return this._object[key];
1432   }
1434   function unset(key) {
1435     var value = this._object[key];
1436     delete this._object[key];
1437     return value;
1438   }
1440   function toObject() {
1441     return Object.clone(this._object);
1442   }
1446   function keys() {
1447     return this.pluck('key');
1448   }
1450   function values() {
1451     return this.pluck('value');
1452   }
1454   function index(value) {
1455     var match = this.detect(function(pair) {
1456       return pair.value === value;
1457     });
1458     return match && match.key;
1459   }
1461   function merge(object) {
1462     return this.clone().update(object);
1463   }
1465   function update(object) {
1466     return new Hash(object).inject(this, function(result, pair) {
1467       result.set(pair.key, pair.value);
1468       return result;
1469     });
1470   }
1472   function toQueryPair(key, value) {
1473     if (Object.isUndefined(value)) return key;
1475     value = String.interpret(value);
1477     value = value.gsub(/(\r)?\n/, '\r\n');
1478     value = encodeURIComponent(value);
1479     value = value.gsub(/%20/, '+');
1480     return key + '=' + value;
1481   }
1483   function toQueryString() {
1484     return this.inject([], function(results, pair) {
1485       var key = encodeURIComponent(pair.key), values = pair.value;
1487       if (values && typeof values == 'object') {
1488         if (Object.isArray(values)) {
1489           var queryValues = [];
1490           for (var i = 0, len = values.length, value; i < len; i++) {
1491             value = values[i];
1492             queryValues.push(toQueryPair(key, value));
1493           }
1494           return results.concat(queryValues);
1495         }
1496       } else results.push(toQueryPair(key, values));
1497       return results;
1498     }).join('&');
1499   }
1501   function inspect() {
1502     return '#<Hash:{' + this.map(function(pair) {
1503       return pair.map(Object.inspect).join(': ');
1504     }).join(', ') + '}>';
1505   }
1507   function clone() {
1508     return new Hash(this);
1509   }
1511   return {
1512     initialize:             initialize,
1513     _each:                  _each,
1514     set:                    set,
1515     get:                    get,
1516     unset:                  unset,
1517     toObject:               toObject,
1518     toTemplateReplacements: toObject,
1519     keys:                   keys,
1520     values:                 values,
1521     index:                  index,
1522     merge:                  merge,
1523     update:                 update,
1524     toQueryString:          toQueryString,
1525     inspect:                inspect,
1526     toJSON:                 toObject,
1527     clone:                  clone
1528   };
1529 })());
1531 Hash.from = $H;
1532 Object.extend(Number.prototype, (function() {
1533   function toColorPart() {
1534     return this.toPaddedString(2, 16);
1535   }
1537   function succ() {
1538     return this + 1;
1539   }
1541   function times(iterator, context) {
1542     $R(0, this, true).each(iterator, context);
1543     return this;
1544   }
1546   function toPaddedString(length, radix) {
1547     var string = this.toString(radix || 10);
1548     return '0'.times(length - string.length) + string;
1549   }
1551   function abs() {
1552     return Math.abs(this);
1553   }
1555   function round() {
1556     return Math.round(this);
1557   }
1559   function ceil() {
1560     return Math.ceil(this);
1561   }
1563   function floor() {
1564     return Math.floor(this);
1565   }
1567   return {
1568     toColorPart:    toColorPart,
1569     succ:           succ,
1570     times:          times,
1571     toPaddedString: toPaddedString,
1572     abs:            abs,
1573     round:          round,
1574     ceil:           ceil,
1575     floor:          floor
1576   };
1577 })());
1579 function $R(start, end, exclusive) {
1580   return new ObjectRange(start, end, exclusive);
1583 var ObjectRange = Class.create(Enumerable, (function() {
1584   function initialize(start, end, exclusive) {
1585     this.start = start;
1586     this.end = end;
1587     this.exclusive = exclusive;
1588   }
1590   function _each(iterator, context) {
1591     var value = this.start, i;
1592     for (i = 0; this.include(value); i++) {
1593       iterator.call(context, value, i);
1594       value = value.succ();
1595     }
1596   }
1598   function include(value) {
1599     if (value < this.start)
1600       return false;
1601     if (this.exclusive)
1602       return value < this.end;
1603     return value <= this.end;
1604   }
1606   return {
1607     initialize: initialize,
1608     _each:      _each,
1609     include:    include
1610   };
1611 })());
1615 var Abstract = { };
1618 var Try = {
1619   these: function() {
1620     var returnValue;
1622     for (var i = 0, length = arguments.length; i < length; i++) {
1623       var lambda = arguments[i];
1624       try {
1625         returnValue = lambda();
1626         break;
1627       } catch (e) { }
1628     }
1630     return returnValue;
1631   }
1634 var Ajax = {
1635   getTransport: function() {
1636     return Try.these(
1637       function() {return new XMLHttpRequest()},
1638       function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1639       function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1640     ) || false;
1641   },
1643   activeRequestCount: 0
1646 Ajax.Responders = {
1647   responders: [],
1649   _each: function(iterator, context) {
1650     this.responders._each(iterator, context);
1651   },
1653   register: function(responder) {
1654     if (!this.include(responder))
1655       this.responders.push(responder);
1656   },
1658   unregister: function(responder) {
1659     this.responders = this.responders.without(responder);
1660   },
1662   dispatch: function(callback, request, transport, json) {
1663     this.each(function(responder) {
1664       if (Object.isFunction(responder[callback])) {
1665         try {
1666           responder[callback].apply(responder, [request, transport, json]);
1667         } catch (e) { }
1668       }
1669     });
1670   }
1673 Object.extend(Ajax.Responders, Enumerable);
1675 Ajax.Responders.register({
1676   onCreate:   function() { Ajax.activeRequestCount++ },
1677   onComplete: function() { Ajax.activeRequestCount-- }
1679 Ajax.Base = Class.create({
1680   initialize: function(options) {
1681     this.options = {
1682       method:       'post',
1683       asynchronous: true,
1684       contentType:  'application/x-www-form-urlencoded',
1685       encoding:     'UTF-8',
1686       parameters:   '',
1687       evalJSON:     true,
1688       evalJS:       true
1689     };
1690     Object.extend(this.options, options || { });
1692     this.options.method = this.options.method.toLowerCase();
1694     if (Object.isHash(this.options.parameters))
1695       this.options.parameters = this.options.parameters.toObject();
1696   }
1698 Ajax.Request = Class.create(Ajax.Base, {
1699   _complete: false,
1701   initialize: function($super, url, options) {
1702     $super(options);
1703     this.transport = Ajax.getTransport();
1704     this.request(url);
1705   },
1707   request: function(url) {
1708     this.url = url;
1709     this.method = this.options.method;
1710     var params = Object.isString(this.options.parameters) ?
1711           this.options.parameters :
1712           Object.toQueryString(this.options.parameters);
1714     if (!['get', 'post'].include(this.method)) {
1715       params += (params ? '&' : '') + "_method=" + this.method;
1716       this.method = 'post';
1717     }
1719     if (params && this.method === 'get') {
1720       this.url += (this.url.include('?') ? '&' : '?') + params;
1721     }
1723     this.parameters = params.toQueryParams();
1725     try {
1726       var response = new Ajax.Response(this);
1727       if (this.options.onCreate) this.options.onCreate(response);
1728       Ajax.Responders.dispatch('onCreate', this, response);
1730       this.transport.open(this.method.toUpperCase(), this.url,
1731         this.options.asynchronous);
1733       if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1735       this.transport.onreadystatechange = this.onStateChange.bind(this);
1736       this.setRequestHeaders();
1738       this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1739       this.transport.send(this.body);
1741       /* Force Firefox to handle ready state 4 for synchronous requests */
1742       if (!this.options.asynchronous && this.transport.overrideMimeType)
1743         this.onStateChange();
1745     }
1746     catch (e) {
1747       this.dispatchException(e);
1748     }
1749   },
1751   onStateChange: function() {
1752     var readyState = this.transport.readyState;
1753     if (readyState > 1 && !((readyState == 4) && this._complete))
1754       this.respondToReadyState(this.transport.readyState);
1755   },
1757   setRequestHeaders: function() {
1758     var headers = {
1759       'X-Requested-With': 'XMLHttpRequest',
1760       'X-Prototype-Version': Prototype.Version,
1761       'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1762     };
1764     if (this.method == 'post') {
1765       headers['Content-type'] = this.options.contentType +
1766         (this.options.encoding ? '; charset=' + this.options.encoding : '');
1768       /* Force "Connection: close" for older Mozilla browsers to work
1769        * around a bug where XMLHttpRequest sends an incorrect
1770        * Content-length header. See Mozilla Bugzilla #246651.
1771        */
1772       if (this.transport.overrideMimeType &&
1773           (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1774             headers['Connection'] = 'close';
1775     }
1777     if (typeof this.options.requestHeaders == 'object') {
1778       var extras = this.options.requestHeaders;
1780       if (Object.isFunction(extras.push))
1781         for (var i = 0, length = extras.length; i < length; i += 2)
1782           headers[extras[i]] = extras[i+1];
1783       else
1784         $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1785     }
1787     for (var name in headers)
1788       if (headers[name] != null)
1789         this.transport.setRequestHeader(name, headers[name]);
1790   },
1792   success: function() {
1793     var status = this.getStatus();
1794     return !status || (status >= 200 && status < 300) || status == 304;
1795   },
1797   getStatus: function() {
1798     try {
1799       if (this.transport.status === 1223) return 204;
1800       return this.transport.status || 0;
1801     } catch (e) { return 0 }
1802   },
1804   respondToReadyState: function(readyState) {
1805     var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
1807     if (state == 'Complete') {
1808       try {
1809         this._complete = true;
1810         (this.options['on' + response.status]
1811          || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1812          || Prototype.emptyFunction)(response, response.headerJSON);
1813       } catch (e) {
1814         this.dispatchException(e);
1815       }
1817       var contentType = response.getHeader('Content-type');
1818       if (this.options.evalJS == 'force'
1819           || (this.options.evalJS && this.isSameOrigin() && contentType
1820           && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1821         this.evalResponse();
1822     }
1824     try {
1825       (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1826       Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
1827     } catch (e) {
1828       this.dispatchException(e);
1829     }
1831     if (state == 'Complete') {
1832       this.transport.onreadystatechange = Prototype.emptyFunction;
1833     }
1834   },
1836   isSameOrigin: function() {
1837     var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1838     return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1839       protocol: location.protocol,
1840       domain: document.domain,
1841       port: location.port ? ':' + location.port : ''
1842     }));
1843   },
1845   getHeader: function(name) {
1846     try {
1847       return this.transport.getResponseHeader(name) || null;
1848     } catch (e) { return null; }
1849   },
1851   evalResponse: function() {
1852     try {
1853       return eval((this.transport.responseText || '').unfilterJSON());
1854     } catch (e) {
1855       this.dispatchException(e);
1856     }
1857   },
1859   dispatchException: function(exception) {
1860     (this.options.onException || Prototype.emptyFunction)(this, exception);
1861     Ajax.Responders.dispatch('onException', this, exception);
1862   }
1865 Ajax.Request.Events =
1866   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1875 Ajax.Response = Class.create({
1876   initialize: function(request){
1877     this.request = request;
1878     var transport  = this.transport  = request.transport,
1879         readyState = this.readyState = transport.readyState;
1881     if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1882       this.status       = this.getStatus();
1883       this.statusText   = this.getStatusText();
1884       this.responseText = String.interpret(transport.responseText);
1885       this.headerJSON   = this._getHeaderJSON();
1886     }
1888     if (readyState == 4) {
1889       var xml = transport.responseXML;
1890       this.responseXML  = Object.isUndefined(xml) ? null : xml;
1891       this.responseJSON = this._getResponseJSON();
1892     }
1893   },
1895   status:      0,
1897   statusText: '',
1899   getStatus: Ajax.Request.prototype.getStatus,
1901   getStatusText: function() {
1902     try {
1903       return this.transport.statusText || '';
1904     } catch (e) { return '' }
1905   },
1907   getHeader: Ajax.Request.prototype.getHeader,
1909   getAllHeaders: function() {
1910     try {
1911       return this.getAllResponseHeaders();
1912     } catch (e) { return null }
1913   },
1915   getResponseHeader: function(name) {
1916     return this.transport.getResponseHeader(name);
1917   },
1919   getAllResponseHeaders: function() {
1920     return this.transport.getAllResponseHeaders();
1921   },
1923   _getHeaderJSON: function() {
1924     var json = this.getHeader('X-JSON');
1925     if (!json) return null;
1927     try {
1928       json = decodeURIComponent(escape(json));
1929     } catch(e) {
1930     }
1932     try {
1933       return json.evalJSON(this.request.options.sanitizeJSON ||
1934         !this.request.isSameOrigin());
1935     } catch (e) {
1936       this.request.dispatchException(e);
1937     }
1938   },
1940   _getResponseJSON: function() {
1941     var options = this.request.options;
1942     if (!options.evalJSON || (options.evalJSON != 'force' &&
1943       !(this.getHeader('Content-type') || '').include('application/json')) ||
1944         this.responseText.blank())
1945           return null;
1946     try {
1947       return this.responseText.evalJSON(options.sanitizeJSON ||
1948         !this.request.isSameOrigin());
1949     } catch (e) {
1950       this.request.dispatchException(e);
1951     }
1952   }
1955 Ajax.Updater = Class.create(Ajax.Request, {
1956   initialize: function($super, container, url, options) {
1957     this.container = {
1958       success: (container.success || container),
1959       failure: (container.failure || (container.success ? null : container))
1960     };
1962     options = Object.clone(options);
1963     var onComplete = options.onComplete;
1964     options.onComplete = (function(response, json) {
1965       this.updateContent(response.responseText);
1966       if (Object.isFunction(onComplete)) onComplete(response, json);
1967     }).bind(this);
1969     $super(url, options);
1970   },
1972   updateContent: function(responseText) {
1973     var receiver = this.container[this.success() ? 'success' : 'failure'],
1974         options = this.options;
1976     if (!options.evalScripts) responseText = responseText.stripScripts();
1978     if (receiver = $(receiver)) {
1979       if (options.insertion) {
1980         if (Object.isString(options.insertion)) {
1981           var insertion = { }; insertion[options.insertion] = responseText;
1982           receiver.insert(insertion);
1983         }
1984         else options.insertion(receiver, responseText);
1985       }
1986       else receiver.update(responseText);
1987     }
1988   }
1991 Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1992   initialize: function($super, container, url, options) {
1993     $super(options);
1994     this.onComplete = this.options.onComplete;
1996     this.frequency = (this.options.frequency || 2);
1997     this.decay = (this.options.decay || 1);
1999     this.updater = { };
2000     this.container = container;
2001     this.url = url;
2003     this.start();
2004   },
2006   start: function() {
2007     this.options.onComplete = this.updateComplete.bind(this);
2008     this.onTimerEvent();
2009   },
2011   stop: function() {
2012     this.updater.options.onComplete = undefined;
2013     clearTimeout(this.timer);
2014     (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
2015   },
2017   updateComplete: function(response) {
2018     if (this.options.decay) {
2019       this.decay = (response.responseText == this.lastText ?
2020         this.decay * this.options.decay : 1);
2022       this.lastText = response.responseText;
2023     }
2024     this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
2025   },
2027   onTimerEvent: function() {
2028     this.updater = new Ajax.Updater(this.container, this.url, this.options);
2029   }
2032 (function(GLOBAL) {
2034   var UNDEFINED;
2035   var SLICE = Array.prototype.slice;
2037   var DIV = document.createElement('div');
2040   function $(element) {
2041     if (arguments.length > 1) {
2042       for (var i = 0, elements = [], length = arguments.length; i < length; i++)
2043         elements.push($(arguments[i]));
2044       return elements;
2045     }
2047     if (Object.isString(element))
2048       element = document.getElementById(element);
2049     return Element.extend(element);
2050   }
2052   GLOBAL.$ = $;
2055   if (!GLOBAL.Node) GLOBAL.Node = {};
2057   if (!GLOBAL.Node.ELEMENT_NODE) {
2058     Object.extend(GLOBAL.Node, {
2059       ELEMENT_NODE:                1,
2060       ATTRIBUTE_NODE:              2,
2061       TEXT_NODE:                   3,
2062       CDATA_SECTION_NODE:          4,
2063       ENTITY_REFERENCE_NODE:       5,
2064       ENTITY_NODE:                 6,
2065       PROCESSING_INSTRUCTION_NODE: 7,
2066       COMMENT_NODE:                8,
2067       DOCUMENT_NODE:               9,
2068       DOCUMENT_TYPE_NODE:         10,
2069       DOCUMENT_FRAGMENT_NODE:     11,
2070       NOTATION_NODE:              12
2071     });
2072   }
2074   var ELEMENT_CACHE = {};
2076   function shouldUseCreationCache(tagName, attributes) {
2077     if (tagName === 'select') return false;
2078     if ('type' in attributes) return false;
2079     return true;
2080   }
2082   var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
2083     try {
2084       var el = document.createElement('<input name="x">');
2085       return el.tagName.toLowerCase() === 'input' && el.name === 'x';
2086     }
2087     catch(err) {
2088       return false;
2089     }
2090   })();
2093   var oldElement = GLOBAL.Element;
2094   function Element(tagName, attributes) {
2095     attributes = attributes || {};
2096     tagName = tagName.toLowerCase();
2098     if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
2099       tagName = '<' + tagName + ' name="' + attributes.name + '">';
2100       delete attributes.name;
2101       return Element.writeAttribute(document.createElement(tagName), attributes);
2102     }
2104     if (!ELEMENT_CACHE[tagName])
2105       ELEMENT_CACHE[tagName] = Element.extend(document.createElement(tagName));
2107     var node = shouldUseCreationCache(tagName, attributes) ?
2108      ELEMENT_CACHE[tagName].cloneNode(false) : document.createElement(tagName);
2110     return Element.writeAttribute(node, attributes);
2111   }
2113   GLOBAL.Element = Element;
2115   Object.extend(GLOBAL.Element, oldElement || {});
2116   if (oldElement) GLOBAL.Element.prototype = oldElement.prototype;
2118   Element.Methods = { ByTag: {}, Simulated: {} };
2120   var methods = {};
2122   var INSPECT_ATTRIBUTES = { id: 'id', className: 'class' };
2123   function inspect(element) {
2124     element = $(element);
2125     var result = '<' + element.tagName.toLowerCase();
2127     var attribute, value;
2128     for (var property in INSPECT_ATTRIBUTES) {
2129       attribute = INSPECT_ATTRIBUTES[property];
2130       value = (element[property] || '').toString();
2131       if (value) result += ' ' + attribute + '=' + value.inspect(true);
2132     }
2134     return result + '>';
2135   }
2137   methods.inspect = inspect;
2140   function visible(element) {
2141     return $(element).getStyle('display') !== 'none';
2142   }
2144   function toggle(element, bool) {
2145     element = $(element);
2146     if (typeof bool !== 'boolean')
2147       bool = !Element.visible(element);
2148     Element[bool ? 'show' : 'hide'](element);
2150     return element;
2151   }
2153   function hide(element) {
2154     element = $(element);
2155     element.style.display = 'none';
2156     return element;
2157   }
2159   function show(element) {
2160     element = $(element);
2161     element.style.display = '';
2162     return element;
2163   }
2166   Object.extend(methods, {
2167     visible: visible,
2168     toggle:  toggle,
2169     hide:    hide,
2170     show:    show
2171   });
2174   function remove(element) {
2175     element = $(element);
2176     element.parentNode.removeChild(element);
2177     return element;
2178   }
2180   var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
2181     var el = document.createElement("select"),
2182         isBuggy = true;
2183     el.innerHTML = "<option value=\"test\">test</option>";
2184     if (el.options && el.options[0]) {
2185       isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
2186     }
2187     el = null;
2188     return isBuggy;
2189   })();
2191   var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
2192     try {
2193       var el = document.createElement("table");
2194       if (el && el.tBodies) {
2195         el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
2196         var isBuggy = typeof el.tBodies[0] == "undefined";
2197         el = null;
2198         return isBuggy;
2199       }
2200     } catch (e) {
2201       return true;
2202     }
2203   })();
2205   var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
2206     try {
2207       var el = document.createElement('div');
2208       el.innerHTML = "<link />";
2209       var isBuggy = (el.childNodes.length === 0);
2210       el = null;
2211       return isBuggy;
2212     } catch(e) {
2213       return true;
2214     }
2215   })();
2217   var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
2218    TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
2220   var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
2221     var s = document.createElement("script"),
2222         isBuggy = false;
2223     try {
2224       s.appendChild(document.createTextNode(""));
2225       isBuggy = !s.firstChild ||
2226         s.firstChild && s.firstChild.nodeType !== 3;
2227     } catch (e) {
2228       isBuggy = true;
2229     }
2230     s = null;
2231     return isBuggy;
2232   })();
2234   function update(element, content) {
2235     element = $(element);
2237     var descendants = element.getElementsByTagName('*'),
2238      i = descendants.length;
2239     while (i--) purgeElement(descendants[i]);
2241     if (content && content.toElement)
2242       content = content.toElement();
2244     if (Object.isElement(content))
2245       return element.update().insert(content);
2248     content = Object.toHTML(content);
2249     var tagName = element.tagName.toUpperCase();
2251     if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
2252       element.text = content;
2253       return element;
2254     }
2256     if (ANY_INNERHTML_BUGGY) {
2257       if (tagName in INSERTION_TRANSLATIONS.tags) {
2258         while (element.firstChild)
2259           element.removeChild(element.firstChild);
2261         var nodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2262         for (var i = 0, node; node = nodes[i]; i++)
2263           element.appendChild(node);
2265       } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
2266         while (element.firstChild)
2267           element.removeChild(element.firstChild);
2269         var nodes = getContentFromAnonymousElement(tagName,
2270          content.stripScripts(), true);
2272         for (var i = 0, node; node = nodes[i]; i++)
2273           element.appendChild(node);
2274       } else {
2275         element.innerHTML = content.stripScripts();
2276       }
2277     } else {
2278       element.innerHTML = content.stripScripts();
2279     }
2281     content.evalScripts.bind(content).defer();
2282     return element;
2283   }
2285   function replace(element, content) {
2286     element = $(element);
2288     if (content && content.toElement) {
2289       content = content.toElement();
2290     } else if (!Object.isElement(content)) {
2291       content = Object.toHTML(content);
2292       var range = element.ownerDocument.createRange();
2293       range.selectNode(element);
2294       content.evalScripts.bind(content).defer();
2295       content = range.createContextualFragment(content.stripScripts());
2296     }
2298     element.parentNode.replaceChild(content, element);
2299     return element;
2300   }
2302   var INSERTION_TRANSLATIONS = {
2303     before: function(element, node) {
2304       element.parentNode.insertBefore(node, element);
2305     },
2306     top: function(element, node) {
2307       element.insertBefore(node, element.firstChild);
2308     },
2309     bottom: function(element, node) {
2310       element.appendChild(node);
2311     },
2312     after: function(element, node) {
2313       element.parentNode.insertBefore(node, element.nextSibling);
2314     },
2316     tags: {
2317       TABLE:  ['<table>',                '</table>',                   1],
2318       TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
2319       TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
2320       TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2321       SELECT: ['<select>',               '</select>',                  1]
2322     }
2323   };
2325   var tags = INSERTION_TRANSLATIONS.tags;
2327   Object.extend(tags, {
2328     THEAD: tags.TBODY,
2329     TFOOT: tags.TBODY,
2330     TH:    tags.TD
2331   });
2333   function replace_IE(element, content) {
2334     element = $(element);
2335     if (content && content.toElement)
2336       content = content.toElement();
2337     if (Object.isElement(content)) {
2338       element.parentNode.replaceChild(content, element);
2339       return element;
2340     }
2342     content = Object.toHTML(content);
2343     var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2345     if (tagName in INSERTION_TRANSLATIONS.tags) {
2346       var nextSibling = Element.next(element);
2347       var fragments = getContentFromAnonymousElement(
2348        tagName, content.stripScripts());
2350       parent.removeChild(element);
2352       var iterator;
2353       if (nextSibling)
2354         iterator = function(node) { parent.insertBefore(node, nextSibling) };
2355       else
2356         iterator = function(node) { parent.appendChild(node); }
2358       fragments.each(iterator);
2359     } else {
2360       element.outerHTML = content.stripScripts();
2361     }
2363     content.evalScripts.bind(content).defer();
2364     return element;
2365   }
2367   if ('outerHTML' in document.documentElement)
2368     replace = replace_IE;
2370   function isContent(content) {
2371     if (Object.isUndefined(content) || content === null) return false;
2373     if (Object.isString(content) || Object.isNumber(content)) return true;
2374     if (Object.isElement(content)) return true;
2375     if (content.toElement || content.toHTML) return true;
2377     return false;
2378   }
2380   function insertContentAt(element, content, position) {
2381     position   = position.toLowerCase();
2382     var method = INSERTION_TRANSLATIONS[position];
2384     if (content && content.toElement) content = content.toElement();
2385     if (Object.isElement(content)) {
2386       method(element, content);
2387       return element;
2388     }
2390     content = Object.toHTML(content);
2391     var tagName = ((position === 'before' || position === 'after') ?
2392      element.parentNode : element).tagName.toUpperCase();
2394     var childNodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2396     if (position === 'top' || position === 'after') childNodes.reverse();
2398     for (var i = 0, node; node = childNodes[i]; i++)
2399       method(element, node);
2401     content.evalScripts.bind(content).defer();
2402   }
2404   function insert(element, insertions) {
2405     element = $(element);
2407     if (isContent(insertions))
2408       insertions = { bottom: insertions };
2410     for (var position in insertions)
2411       insertContentAt(element, insertions[position], position);
2413     return element;
2414   }
2416   function wrap(element, wrapper, attributes) {
2417     element = $(element);
2419     if (Object.isElement(wrapper)) {
2420       $(wrapper).writeAttribute(attributes || {});
2421     } else if (Object.isString(wrapper)) {
2422       wrapper = new Element(wrapper, attributes);
2423     } else {
2424       wrapper = new Element('div', wrapper);
2425     }
2427     if (element.parentNode)
2428       element.parentNode.replaceChild(wrapper, element);
2430     wrapper.appendChild(element);
2432     return wrapper;
2433   }
2435   function cleanWhitespace(element) {
2436     element = $(element);
2437     var node = element.firstChild;
2439     while (node) {
2440       var nextNode = node.nextSibling;
2441       if (node.nodeType === Node.TEXT_NODE && !/\S/.test(node.nodeValue))
2442         element.removeChild(node);
2443       node = nextNode;
2444     }
2445     return element;
2446   }
2448   function empty(element) {
2449     return $(element).innerHTML.blank();
2450   }
2452   function getContentFromAnonymousElement(tagName, html, force) {
2453     var t = INSERTION_TRANSLATIONS.tags[tagName], div = DIV;
2455     var workaround = !!t;
2456     if (!workaround && force) {
2457       workaround = true;
2458       t = ['', '', 0];
2459     }
2461     if (workaround) {
2462       div.innerHTML = '&#160;' + t[0] + html + t[1];
2463       div.removeChild(div.firstChild);
2464       for (var i = t[2]; i--; )
2465         div = div.firstChild;
2466     } else {
2467       div.innerHTML = html;
2468     }
2470     return $A(div.childNodes);
2471   }
2473   function clone(element, deep) {
2474     if (!(element = $(element))) return;
2475     var clone = element.cloneNode(deep);
2476     if (!HAS_UNIQUE_ID_PROPERTY) {
2477       clone._prototypeUID = UNDEFINED;
2478       if (deep) {
2479         var descendants = Element.select(clone, '*'),
2480          i = descendants.length;
2481         while (i--)
2482           descendants[i]._prototypeUID = UNDEFINED;
2483       }
2484     }
2485     return Element.extend(clone);
2486   }
2488   function purgeElement(element) {
2489     var uid = getUniqueElementID(element);
2490     if (uid) {
2491       Element.stopObserving(element);
2492       if (!HAS_UNIQUE_ID_PROPERTY)
2493         element._prototypeUID = UNDEFINED;
2494       delete Element.Storage[uid];
2495     }
2496   }
2498   function purgeCollection(elements) {
2499     var i = elements.length;
2500     while (i--)
2501       purgeElement(elements[i]);
2502   }
2504   function purgeCollection_IE(elements) {
2505     var i = elements.length, element, uid;
2506     while (i--) {
2507       element = elements[i];
2508       uid = getUniqueElementID(element);
2509       delete Element.Storage[uid];
2510       delete Event.cache[uid];
2511     }
2512   }
2514   if (HAS_UNIQUE_ID_PROPERTY) {
2515     purgeCollection = purgeCollection_IE;
2516   }
2519   function purge(element) {
2520     if (!(element = $(element))) return;
2521     purgeElement(element);
2523     var descendants = element.getElementsByTagName('*'),
2524      i = descendants.length;
2526     while (i--) purgeElement(descendants[i]);
2528     return null;
2529   }
2531   Object.extend(methods, {
2532     remove:  remove,
2533     update:  update,
2534     replace: replace,
2535     insert:  insert,
2536     wrap:    wrap,
2537     cleanWhitespace: cleanWhitespace,
2538     empty:   empty,
2539     clone:   clone,
2540     purge:   purge
2541   });
2545   function recursivelyCollect(element, property, maximumLength) {
2546     element = $(element);
2547     maximumLength = maximumLength || -1;
2548     var elements = [];
2550     while (element = element[property]) {
2551       if (element.nodeType === Node.ELEMENT_NODE)
2552         elements.push(Element.extend(element));
2554       if (elements.length === maximumLength) break;
2555     }
2557     return elements;
2558   }
2561   function ancestors(element) {
2562     return recursivelyCollect(element, 'parentNode');
2563   }
2565   function descendants(element) {
2566     return Element.select(element, '*');
2567   }
2569   function firstDescendant(element) {
2570     element = $(element).firstChild;
2571     while (element && element.nodeType !== Node.ELEMENT_NODE)
2572       element = element.nextSibling;
2574     return $(element);
2575   }
2577   function immediateDescendants(element) {
2578     var results = [], child = $(element).firstChild;
2580     while (child) {
2581       if (child.nodeType === Node.ELEMENT_NODE)
2582         results.push(Element.extend(child));
2584       child = child.nextSibling;
2585     }
2587     return results;
2588   }
2590   function previousSiblings(element) {
2591     return recursivelyCollect(element, 'previousSibling');
2592   }
2594   function nextSiblings(element) {
2595     return recursivelyCollect(element, 'nextSibling');
2596   }
2598   function siblings(element) {
2599     element = $(element);
2600     var previous = previousSiblings(element),
2601      next = nextSiblings(element);
2602     return previous.reverse().concat(next);
2603   }
2605   function match(element, selector) {
2606     element = $(element);
2608     if (Object.isString(selector))
2609       return Prototype.Selector.match(element, selector);
2611     return selector.match(element);
2612   }
2615   function _recursivelyFind(element, property, expression, index) {
2616     element = $(element), expression = expression || 0, index = index || 0;
2617     if (Object.isNumber(expression)) {
2618       index = expression, expression = null;
2619     }
2621     while (element = element[property]) {
2622       if (element.nodeType !== 1) continue;
2623       if (expression && !Prototype.Selector.match(element, expression))
2624         continue;
2625       if (--index >= 0) continue;
2627       return Element.extend(element);
2628     }
2629   }
2632   function up(element, expression, index) {
2633     element = $(element);
2635     if (arguments.length === 1) return $(element.parentNode);
2636     return _recursivelyFind(element, 'parentNode', expression, index);
2637   }
2639   function down(element, expression, index) {
2640     if (arguments.length === 1) return firstDescendant(element);
2641     element = $(element), expression = expression || 0, index = index || 0;
2643     if (Object.isNumber(expression))
2644       index = expression, expression = '*';
2646     var node = Prototype.Selector.select(expression, element)[index];
2647     return Element.extend(node);
2648   }
2650   function previous(element, expression, index) {
2651     return _recursivelyFind(element, 'previousSibling', expression, index);
2652   }
2654   function next(element, expression, index) {
2655     return _recursivelyFind(element, 'nextSibling', expression, index);
2656   }
2658   function select(element) {
2659     element = $(element);
2660     var expressions = SLICE.call(arguments, 1).join(', ');
2661     return Prototype.Selector.select(expressions, element);
2662   }
2664   function adjacent(element) {
2665     element = $(element);
2666     var expressions = SLICE.call(arguments, 1).join(', ');
2667     var siblings = Element.siblings(element), results = [];
2668     for (var i = 0, sibling; sibling = siblings[i]; i++) {
2669       if (Prototype.Selector.match(sibling, expressions))
2670         results.push(sibling);
2671     }
2673     return results;
2674   }
2676   function descendantOf_DOM(element, ancestor) {
2677     element = $(element), ancestor = $(ancestor);
2678     if (!element || !ancestor) return false;
2679     while (element = element.parentNode)
2680       if (element === ancestor) return true;
2681     return false;
2682   }
2684   function descendantOf_contains(element, ancestor) {
2685     element = $(element), ancestor = $(ancestor);
2686     if (!element || !ancestor) return false;
2687     if (!ancestor.contains) return descendantOf_DOM(element, ancestor);
2688     return ancestor.contains(element) && ancestor !== element;
2689   }
2691   function descendantOf_compareDocumentPosition(element, ancestor) {
2692     element = $(element), ancestor = $(ancestor);
2693     if (!element || !ancestor) return false;
2694     return (element.compareDocumentPosition(ancestor) & 8) === 8;
2695   }
2697   var descendantOf;
2698   if (DIV.compareDocumentPosition) {
2699     descendantOf = descendantOf_compareDocumentPosition;
2700   } else if (DIV.contains) {
2701     descendantOf = descendantOf_contains;
2702   } else {
2703     descendantOf = descendantOf_DOM;
2704   }
2707   Object.extend(methods, {
2708     recursivelyCollect:   recursivelyCollect,
2709     ancestors:            ancestors,
2710     descendants:          descendants,
2711     firstDescendant:      firstDescendant,
2712     immediateDescendants: immediateDescendants,
2713     previousSiblings:     previousSiblings,
2714     nextSiblings:         nextSiblings,
2715     siblings:             siblings,
2716     match:                match,
2717     up:                   up,
2718     down:                 down,
2719     previous:             previous,
2720     next:                 next,
2721     select:               select,
2722     adjacent:             adjacent,
2723     descendantOf:         descendantOf,
2725     getElementsBySelector: select,
2727     childElements:         immediateDescendants
2728   });
2731   var idCounter = 1;
2732   function identify(element) {
2733     element = $(element);
2734     var id = Element.readAttribute(element, 'id');
2735     if (id) return id;
2737     do { id = 'anonymous_element_' + idCounter++ } while ($(id));
2739     Element.writeAttribute(element, 'id', id);
2740     return id;
2741   }
2744   function readAttribute(element, name) {
2745     return $(element).getAttribute(name);
2746   }
2748   function readAttribute_IE(element, name) {
2749     element = $(element);
2751     var table = ATTRIBUTE_TRANSLATIONS.read;
2752     if (table.values[name])
2753       return table.values[name](element, name);
2755     if (table.names[name]) name = table.names[name];
2757     if (name.include(':')) {
2758       if (!element.attributes || !element.attributes[name]) return null;
2759       return element.attributes[name].value;
2760     }
2762     return element.getAttribute(name);
2763   }
2765   function readAttribute_Opera(element, name) {
2766     if (name === 'title') return element.title;
2767     return element.getAttribute(name);
2768   }
2770   var PROBLEMATIC_ATTRIBUTE_READING = (function() {
2771     DIV.setAttribute('onclick', []);
2772     var value = DIV.getAttribute('onclick');
2773     var isFunction = Object.isArray(value);
2774     DIV.removeAttribute('onclick');
2775     return isFunction;
2776   })();
2778   if (PROBLEMATIC_ATTRIBUTE_READING) {
2779     readAttribute = readAttribute_IE;
2780   } else if (Prototype.Browser.Opera) {
2781     readAttribute = readAttribute_Opera;
2782   }
2785   function writeAttribute(element, name, value) {
2786     element = $(element);
2787     var attributes = {}, table = ATTRIBUTE_TRANSLATIONS.write;
2789     if (typeof name === 'object') {
2790       attributes = name;
2791     } else {
2792       attributes[name] = Object.isUndefined(value) ? true : value;
2793     }
2795     for (var attr in attributes) {
2796       name = table.names[attr] || attr;
2797       value = attributes[attr];
2798       if (table.values[attr]) {
2799         value = table.values[attr](element, value);
2800         if (Object.isUndefined(value)) continue;
2801       }
2802       if (value === false || value === null)
2803         element.removeAttribute(name);
2804       else if (value === true)
2805         element.setAttribute(name, name);
2806       else element.setAttribute(name, value);
2807     }
2809     return element;
2810   }
2812   var PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES = (function () {
2813     if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) {
2814       return false;
2815     }
2816     var checkbox = document.createElement('<input type="checkbox">');
2817     checkbox.checked = true;
2818     var node = checkbox.getAttributeNode('checked');
2819     return !node || !node.specified;
2820   })();
2822   function hasAttribute(element, attribute) {
2823     attribute = ATTRIBUTE_TRANSLATIONS.has[attribute] || attribute;
2824     var node = $(element).getAttributeNode(attribute);
2825     return !!(node && node.specified);
2826   }
2828   function hasAttribute_IE(element, attribute) {
2829     if (attribute === 'checked') {
2830       return element.checked;
2831     }
2832     return hasAttribute(element, attribute);
2833   }
2835   GLOBAL.Element.Methods.Simulated.hasAttribute =
2836    PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES ?
2837    hasAttribute_IE : hasAttribute;
2839   function classNames(element) {
2840     return new Element.ClassNames(element);
2841   }
2843   var regExpCache = {};
2844   function getRegExpForClassName(className) {
2845     if (regExpCache[className]) return regExpCache[className];
2847     var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
2848     regExpCache[className] = re;
2849     return re;
2850   }
2852   function hasClassName(element, className) {
2853     if (!(element = $(element))) return;
2855     var elementClassName = element.className;
2857     if (elementClassName.length === 0) return false;
2858     if (elementClassName === className) return true;
2860     return getRegExpForClassName(className).test(elementClassName);
2861   }
2863   function addClassName(element, className) {
2864     if (!(element = $(element))) return;
2866     if (!hasClassName(element, className))
2867       element.className += (element.className ? ' ' : '') + className;
2869     return element;
2870   }
2872   function removeClassName(element, className) {
2873     if (!(element = $(element))) return;
2875     element.className = element.className.replace(
2876      getRegExpForClassName(className), ' ').strip();
2878     return element;
2879   }
2881   function toggleClassName(element, className, bool) {
2882     if (!(element = $(element))) return;
2884     if (Object.isUndefined(bool))
2885       bool = !hasClassName(element, className);
2887     var method = Element[bool ? 'addClassName' : 'removeClassName'];
2888     return method(element, className);
2889   }
2891   var ATTRIBUTE_TRANSLATIONS = {};
2893   var classProp = 'className', forProp = 'for';
2895   DIV.setAttribute(classProp, 'x');
2896   if (DIV.className !== 'x') {
2897     DIV.setAttribute('class', 'x');
2898     if (DIV.className === 'x')
2899       classProp = 'class';
2900   }
2902   var LABEL = document.createElement('label');
2903   LABEL.setAttribute(forProp, 'x');
2904   if (LABEL.htmlFor !== 'x') {
2905     LABEL.setAttribute('htmlFor', 'x');
2906     if (LABEL.htmlFor === 'x')
2907       forProp = 'htmlFor';
2908   }
2909   LABEL = null;
2911   function _getAttr(element, attribute) {
2912     return element.getAttribute(attribute);
2913   }
2915   function _getAttr2(element, attribute) {
2916     return element.getAttribute(attribute, 2);
2917   }
2919   function _getAttrNode(element, attribute) {
2920     var node = element.getAttributeNode(attribute);
2921     return node ? node.value : '';
2922   }
2924   function _getFlag(element, attribute) {
2925     return $(element).hasAttribute(attribute) ? attribute : null;
2926   }
2928   DIV.onclick = Prototype.emptyFunction;
2929   var onclickValue = DIV.getAttribute('onclick');
2931   var _getEv;
2933   if (String(onclickValue).indexOf('{') > -1) {
2934     _getEv = function(element, attribute) {
2935       var value = element.getAttribute(attribute);
2936       if (!value) return null;
2937       value = value.toString();
2938       value = value.split('{')[1];
2939       value = value.split('}')[0];
2940       return value.strip();
2941     };
2942   }
2943   else if (onclickValue === '') {
2944     _getEv = function(element, attribute) {
2945       var value = element.getAttribute(attribute);
2946       if (!value) return null;
2947       return value.strip();
2948     };
2949   }
2951   ATTRIBUTE_TRANSLATIONS.read = {
2952     names: {
2953       'class':     classProp,
2954       'className': classProp,
2955       'for':       forProp,
2956       'htmlFor':   forProp
2957     },
2959     values: {
2960       style: function(element) {
2961         return element.style.cssText.toLowerCase();
2962       },
2963       title: function(element) {
2964         return element.title;
2965       }
2966     }
2967   };
2969   ATTRIBUTE_TRANSLATIONS.write = {
2970     names: {
2971       className:   'class',
2972       htmlFor:     'for',
2973       cellpadding: 'cellPadding',
2974       cellspacing: 'cellSpacing'
2975     },
2977     values: {
2978       checked: function(element, value) {
2979         value = !!value;
2980         element.checked = value;
2981         return value ? 'checked' : null;
2982       },
2984       style: function(element, value) {
2985         element.style.cssText = value ? value : '';
2986       }
2987     }
2988   };
2990   ATTRIBUTE_TRANSLATIONS.has = { names: {} };
2992   Object.extend(ATTRIBUTE_TRANSLATIONS.write.names,
2993    ATTRIBUTE_TRANSLATIONS.read.names);
2995   var CAMEL_CASED_ATTRIBUTE_NAMES = $w('colSpan rowSpan vAlign dateTime ' +
2996    'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
2998   for (var i = 0, attr; attr = CAMEL_CASED_ATTRIBUTE_NAMES[i]; i++) {
2999     ATTRIBUTE_TRANSLATIONS.write.names[attr.toLowerCase()] = attr;
3000     ATTRIBUTE_TRANSLATIONS.has.names[attr.toLowerCase()]   = attr;
3001   }
3003   Object.extend(ATTRIBUTE_TRANSLATIONS.read.values, {
3004     href:        _getAttr2,
3005     src:         _getAttr2,
3006     type:        _getAttr,
3007     action:      _getAttrNode,
3008     disabled:    _getFlag,
3009     checked:     _getFlag,
3010     readonly:    _getFlag,
3011     multiple:    _getFlag,
3012     onload:      _getEv,
3013     onunload:    _getEv,
3014     onclick:     _getEv,
3015     ondblclick:  _getEv,
3016     onmousedown: _getEv,
3017     onmouseup:   _getEv,
3018     onmouseover: _getEv,
3019     onmousemove: _getEv,
3020     onmouseout:  _getEv,
3021     onfocus:     _getEv,
3022     onblur:      _getEv,
3023     onkeypress:  _getEv,
3024     onkeydown:   _getEv,
3025     onkeyup:     _getEv,
3026     onsubmit:    _getEv,
3027     onreset:     _getEv,
3028     onselect:    _getEv,
3029     onchange:    _getEv
3030   });
3033   Object.extend(methods, {
3034     identify:        identify,
3035     readAttribute:   readAttribute,
3036     writeAttribute:  writeAttribute,
3037     classNames:      classNames,
3038     hasClassName:    hasClassName,
3039     addClassName:    addClassName,
3040     removeClassName: removeClassName,
3041     toggleClassName: toggleClassName
3042   });
3045   function normalizeStyleName(style) {
3046     if (style === 'float' || style === 'styleFloat')
3047       return 'cssFloat';
3048     return style.camelize();
3049   }
3051   function normalizeStyleName_IE(style) {
3052     if (style === 'float' || style === 'cssFloat')
3053       return 'styleFloat';
3054     return style.camelize();
3055   }
3057   function setStyle(element, styles) {
3058     element = $(element);
3059     var elementStyle = element.style, match;
3061     if (Object.isString(styles)) {
3062       elementStyle.cssText += ';' + styles;
3063       if (styles.include('opacity')) {
3064         var opacity = styles.match(/opacity:\s*(\d?\.?\d*)/)[1];
3065         Element.setOpacity(element, opacity);
3066       }
3067       return element;
3068     }
3070     for (var property in styles) {
3071       if (property === 'opacity') {
3072         Element.setOpacity(element, styles[property]);
3073       } else {
3074         var value = styles[property];
3075         if (property === 'float' || property === 'cssFloat') {
3076           property = Object.isUndefined(elementStyle.styleFloat) ?
3077            'cssFloat' : 'styleFloat';
3078         }
3079         elementStyle[property] = value;
3080       }
3081     }
3083     return element;
3084   }
3087   function getStyle(element, style) {
3088     element = $(element);
3089     style = normalizeStyleName(style);
3091     var value = element.style[style];
3092     if (!value || value === 'auto') {
3093       var css = document.defaultView.getComputedStyle(element, null);
3094       value = css ? css[style] : null;
3095     }
3097     if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3098     return value === 'auto' ? null : value;
3099   }
3101   function getStyle_Opera(element, style) {
3102     switch (style) {
3103       case 'height': case 'width':
3104         if (!Element.visible(element)) return null;
3106         var dim = parseInt(getStyle(element, style), 10);
3108         if (dim !== element['offset' + style.capitalize()])
3109           return dim + 'px';
3111         return Element.measure(element, style);
3113       default: return getStyle(element, style);
3114     }
3115   }
3117   function getStyle_IE(element, style) {
3118     element = $(element);
3119     style = normalizeStyleName_IE(style);
3121     var value = element.style[style];
3122     if (!value && element.currentStyle) {
3123       value = element.currentStyle[style];
3124     }
3126     if (style === 'opacity') {
3127       if (!STANDARD_CSS_OPACITY_SUPPORTED)
3128         return getOpacity_IE(element);
3129       else return value ? parseFloat(value) : 1.0;
3130     }
3132     if (value === 'auto') {
3133       if ((style === 'width' || style === 'height') && Element.visible(element))
3134         return Element.measure(element, style) + 'px';
3135       return null;
3136     }
3138     return value;
3139   }
3141   function stripAlphaFromFilter_IE(filter) {
3142     return (filter || '').replace(/alpha\([^\)]*\)/gi, '');
3143   }
3145   function hasLayout_IE(element) {
3146     if (!element.currentStyle || !element.currentStyle.hasLayout)
3147       element.style.zoom = 1;
3148     return element;
3149   }
3151   var STANDARD_CSS_OPACITY_SUPPORTED = (function() {
3152     DIV.style.cssText = "opacity:.55";
3153     return /^0.55/.test(DIV.style.opacity);
3154   })();
3156   function setOpacity(element, value) {
3157     element = $(element);
3158     if (value == 1 || value === '') value = '';
3159     else if (value < 0.00001) value = 0;
3160     element.style.opacity = value;
3161     return element;
3162   }
3164   function setOpacity_IE(element, value) {
3165     if (STANDARD_CSS_OPACITY_SUPPORTED)
3166       return setOpacity(element, value);
3168     element = hasLayout_IE($(element));
3169     var filter = Element.getStyle(element, 'filter'),
3170      style = element.style;
3172     if (value == 1 || value === '') {
3173       filter = stripAlphaFromFilter_IE(filter);
3174       if (filter) style.filter = filter;
3175       else style.removeAttribute('filter');
3176       return element;
3177     }
3179     if (value < 0.00001) value = 0;
3181     style.filter = stripAlphaFromFilter_IE(filter) +
3182      ' alpha(opacity=' + (value * 100) + ')';
3184     return element;
3185   }
3188   function getOpacity(element) {
3189     return Element.getStyle(element, 'opacity');
3190   }
3192   function getOpacity_IE(element) {
3193     if (STANDARD_CSS_OPACITY_SUPPORTED)
3194       return getOpacity(element);
3196     var filter = Element.getStyle(element, 'filter');
3197     if (filter.length === 0) return 1.0;
3198     var match = (filter || '').match(/alpha\(opacity=(.*)\)/i);
3199     if (match && match[1]) return parseFloat(match[1]) / 100;
3200     return 1.0;
3201   }
3204   Object.extend(methods, {
3205     setStyle:   setStyle,
3206     getStyle:   getStyle,
3207     setOpacity: setOpacity,
3208     getOpacity: getOpacity
3209   });
3211   if ('styleFloat' in DIV.style) {
3212     methods.getStyle = getStyle_IE;
3213     methods.setOpacity = setOpacity_IE;
3214     methods.getOpacity = getOpacity_IE;
3215   }
3217   var UID = 0;
3219   GLOBAL.Element.Storage = { UID: 1 };
3221   function getUniqueElementID(element) {
3222     if (element === window) return 0;
3224     if (typeof element._prototypeUID === 'undefined')
3225       element._prototypeUID = Element.Storage.UID++;
3226     return element._prototypeUID;
3227   }
3229   function getUniqueElementID_IE(element) {
3230     if (element === window) return 0;
3231     if (element == document) return 1;
3232     return element.uniqueID;
3233   }
3235   var HAS_UNIQUE_ID_PROPERTY = ('uniqueID' in DIV);
3236   if (HAS_UNIQUE_ID_PROPERTY)
3237     getUniqueElementID = getUniqueElementID_IE;
3239   function getStorage(element) {
3240     if (!(element = $(element))) return;
3242     var uid = getUniqueElementID(element);
3244     if (!Element.Storage[uid])
3245       Element.Storage[uid] = $H();
3247     return Element.Storage[uid];
3248   }
3250   function store(element, key, value) {
3251     if (!(element = $(element))) return;
3252     var storage = getStorage(element);
3253     if (arguments.length === 2) {
3254       storage.update(key);
3255     } else {
3256       storage.set(key, value);
3257     }
3258     return element;
3259   }
3261   function retrieve(element, key, defaultValue) {
3262     if (!(element = $(element))) return;
3263     var storage = getStorage(element), value = storage.get(key);
3265     if (Object.isUndefined(value)) {
3266       storage.set(key, defaultValue);
3267       value = defaultValue;
3268     }
3270     return value;
3271   }
3274   Object.extend(methods, {
3275     getStorage: getStorage,
3276     store:      store,
3277     retrieve:   retrieve
3278   });
3281   var Methods = {}, ByTag = Element.Methods.ByTag,
3282    F = Prototype.BrowserFeatures;
3284   if (!F.ElementExtensions && ('__proto__' in DIV)) {
3285     GLOBAL.HTMLElement = {};
3286     GLOBAL.HTMLElement.prototype = DIV['__proto__'];
3287     F.ElementExtensions = true;
3288   }
3290   function checkElementPrototypeDeficiency(tagName) {
3291     if (typeof window.Element === 'undefined') return false;
3292     if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) return false;
3293     var proto = window.Element.prototype;
3294     if (proto) {
3295       var id = '_' + (Math.random() + '').slice(2),
3296        el = document.createElement(tagName);
3297       proto[id] = 'x';
3298       var isBuggy = (el[id] !== 'x');
3299       delete proto[id];
3300       el = null;
3301       return isBuggy;
3302     }
3304     return false;
3305   }
3307   var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY =
3308    checkElementPrototypeDeficiency('object');
3310   function extendElementWith(element, methods) {
3311     for (var property in methods) {
3312       var value = methods[property];
3313       if (Object.isFunction(value) && !(property in element))
3314         element[property] = value.methodize();
3315     }
3316   }
3318   var EXTENDED = {};
3319   function elementIsExtended(element) {
3320     var uid = getUniqueElementID(element);
3321     return (uid in EXTENDED);
3322   }
3324   function extend(element) {
3325     if (!element || elementIsExtended(element)) return element;
3326     if (element.nodeType !== Node.ELEMENT_NODE || element == window)
3327       return element;
3329     var methods = Object.clone(Methods),
3330      tagName = element.tagName.toUpperCase();
3332     if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
3334     extendElementWith(element, methods);
3335     EXTENDED[getUniqueElementID(element)] = true;
3336     return element;
3337   }
3339   function extend_IE8(element) {
3340     if (!element || elementIsExtended(element)) return element;
3342     var t = element.tagName;
3343     if (t && (/^(?:object|applet|embed)$/i.test(t))) {
3344       extendElementWith(element, Element.Methods);
3345       extendElementWith(element, Element.Methods.Simulated);
3346       extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
3347     }
3349     return element;
3350   }
3352   if (F.SpecificElementExtensions) {
3353     extend = HTMLOBJECTELEMENT_PROTOTYPE_BUGGY ? extend_IE8 : Prototype.K;
3354   }
3356   function addMethodsToTagName(tagName, methods) {
3357     tagName = tagName.toUpperCase();
3358     if (!ByTag[tagName]) ByTag[tagName] = {};
3359     Object.extend(ByTag[tagName], methods);
3360   }
3362   function mergeMethods(destination, methods, onlyIfAbsent) {
3363     if (Object.isUndefined(onlyIfAbsent)) onlyIfAbsent = false;
3364     for (var property in methods) {
3365       var value = methods[property];
3366       if (!Object.isFunction(value)) continue;
3367       if (!onlyIfAbsent || !(property in destination))
3368         destination[property] = value.methodize();
3369     }
3370   }
3372   function findDOMClass(tagName) {
3373     var klass;
3374     var trans = {
3375       "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3376       "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3377       "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3378       "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3379       "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3380       "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3381       "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3382       "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3383       "FrameSet", "IFRAME": "IFrame"
3384     };
3385     if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
3386     if (window[klass]) return window[klass];
3387     klass = 'HTML' + tagName + 'Element';
3388     if (window[klass]) return window[klass];
3389     klass = 'HTML' + tagName.capitalize() + 'Element';
3390     if (window[klass]) return window[klass];
3392     var element = document.createElement(tagName),
3393      proto = element['__proto__'] || element.constructor.prototype;
3395     element = null;
3396     return proto;
3397   }
3399   function addMethods(methods) {
3400     if (arguments.length === 0) addFormMethods();
3402     if (arguments.length === 2) {
3403       var tagName = methods;
3404       methods = arguments[1];
3405     }
3407     if (!tagName) {
3408       Object.extend(Element.Methods, methods || {});
3409     } else {
3410       if (Object.isArray(tagName)) {
3411         for (var i = 0, tag; tag = tagName[i]; i++)
3412           addMethodsToTagName(tag, methods);
3413       } else {
3414         addMethodsToTagName(tagName, methods);
3415       }
3416     }
3418     var ELEMENT_PROTOTYPE = window.HTMLElement ? HTMLElement.prototype :
3419      Element.prototype;
3421     if (F.ElementExtensions) {
3422       mergeMethods(ELEMENT_PROTOTYPE, Element.Methods);
3423       mergeMethods(ELEMENT_PROTOTYPE, Element.Methods.Simulated, true);
3424     }
3426     if (F.SpecificElementExtensions) {
3427       for (var tag in Element.Methods.ByTag) {
3428         var klass = findDOMClass(tag);
3429         if (Object.isUndefined(klass)) continue;
3430         mergeMethods(klass.prototype, ByTag[tag]);
3431       }
3432     }
3434     Object.extend(Element, Element.Methods);
3435     Object.extend(Element, Element.Methods.Simulated);
3436     delete Element.ByTag;
3437     delete Element.Simulated;
3439     Element.extend.refresh();
3441     ELEMENT_CACHE = {};
3442   }
3444   Object.extend(GLOBAL.Element, {
3445     extend:     extend,
3446     addMethods: addMethods
3447   });
3449   if (extend === Prototype.K) {
3450     GLOBAL.Element.extend.refresh = Prototype.emptyFunction;
3451   } else {
3452     GLOBAL.Element.extend.refresh = function() {
3453       if (Prototype.BrowserFeatures.ElementExtensions) return;
3454       Object.extend(Methods, Element.Methods);
3455       Object.extend(Methods, Element.Methods.Simulated);
3457       EXTENDED = {};
3458     };
3459   }
3461   function addFormMethods() {
3462     Object.extend(Form, Form.Methods);
3463     Object.extend(Form.Element, Form.Element.Methods);
3464     Object.extend(Element.Methods.ByTag, {
3465       "FORM":     Object.clone(Form.Methods),
3466       "INPUT":    Object.clone(Form.Element.Methods),
3467       "SELECT":   Object.clone(Form.Element.Methods),
3468       "TEXTAREA": Object.clone(Form.Element.Methods),
3469       "BUTTON":   Object.clone(Form.Element.Methods)
3470     });
3471   }
3473   Element.addMethods(methods);
3475   function destroyCache_IE() {
3476     DIV = null;
3477     ELEMENT_CACHE = null;
3478   }
3480   if (window.attachEvent)
3481     window.attachEvent('onunload', destroyCache_IE);
3483 })(this);
3484 (function() {
3486   function toDecimal(pctString) {
3487     var match = pctString.match(/^(\d+)%?$/i);
3488     if (!match) return null;
3489     return (Number(match[1]) / 100);
3490   }
3492   function getRawStyle(element, style) {
3493     element = $(element);
3495     var value = element.style[style];
3496     if (!value || value === 'auto') {
3497       var css = document.defaultView.getComputedStyle(element, null);
3498       value = css ? css[style] : null;
3499     }
3501     if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3502     return value === 'auto' ? null : value;
3503   }
3505   function getRawStyle_IE(element, style) {
3506     var value = element.style[style];
3507     if (!value && element.currentStyle) {
3508       value = element.currentStyle[style];
3509     }
3510     return value;
3511   }
3513   function getContentWidth(element, context) {
3514     var boxWidth = element.offsetWidth;
3516     var bl = getPixelValue(element, 'borderLeftWidth',  context) || 0;
3517     var br = getPixelValue(element, 'borderRightWidth', context) || 0;
3518     var pl = getPixelValue(element, 'paddingLeft',      context) || 0;
3519     var pr = getPixelValue(element, 'paddingRight',     context) || 0;
3521     return boxWidth - bl - br - pl - pr;
3522   }
3524   if (!Object.isUndefined(document.documentElement.currentStyle) && !Prototype.Browser.Opera) {
3525     getRawStyle = getRawStyle_IE;
3526   }
3529   function getPixelValue(value, property, context) {
3530     var element = null;
3531     if (Object.isElement(value)) {
3532       element = value;
3533       value = getRawStyle(element, property);
3534     }
3536     if (value === null || Object.isUndefined(value)) {
3537       return null;
3538     }
3540     if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
3541       return window.parseFloat(value);
3542     }
3544     var isPercentage = value.include('%'), isViewport = (context === document.viewport);
3546     if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
3547       var style = element.style.left, rStyle = element.runtimeStyle.left;
3548       element.runtimeStyle.left = element.currentStyle.left;
3549       element.style.left = value || 0;
3550       value = element.style.pixelLeft;
3551       element.style.left = style;
3552       element.runtimeStyle.left = rStyle;
3554       return value;
3555     }
3557     if (element && isPercentage) {
3558       context = context || element.parentNode;
3559       var decimal = toDecimal(value), whole = null;
3561       var isHorizontal = property.include('left') || property.include('right') ||
3562        property.include('width');
3564       var isVertical   = property.include('top') || property.include('bottom') ||
3565         property.include('height');
3567       if (context === document.viewport) {
3568         if (isHorizontal) {
3569           whole = document.viewport.getWidth();
3570         } else if (isVertical) {
3571           whole = document.viewport.getHeight();
3572         }
3573       } else {
3574         if (isHorizontal) {
3575           whole = $(context).measure('width');
3576         } else if (isVertical) {
3577           whole = $(context).measure('height');
3578         }
3579       }
3581       return (whole === null) ? 0 : whole * decimal;
3582     }
3584     return 0;
3585   }
3587   function toCSSPixels(number) {
3588     if (Object.isString(number) && number.endsWith('px'))
3589       return number;
3590     return number + 'px';
3591   }
3593   function isDisplayed(element) {
3594     while (element && element.parentNode) {
3595       var display = element.getStyle('display');
3596       if (display === 'none') {
3597         return false;
3598       }
3599       element = $(element.parentNode);
3600     }
3601     return true;
3602   }
3604   var hasLayout = Prototype.K;
3605   if ('currentStyle' in document.documentElement) {
3606     hasLayout = function(element) {
3607       if (!element.currentStyle.hasLayout) {
3608         element.style.zoom = 1;
3609       }
3610       return element;
3611     };
3612   }
3614   function cssNameFor(key) {
3615     if (key.include('border')) key = key + '-width';
3616     return key.camelize();
3617   }
3619   Element.Layout = Class.create(Hash, {
3620     initialize: function($super, element, preCompute) {
3621       $super();
3622       this.element = $(element);
3624       Element.Layout.PROPERTIES.each( function(property) {
3625         this._set(property, null);
3626       }, this);
3628       if (preCompute) {
3629         this._preComputing = true;
3630         this._begin();
3631         Element.Layout.PROPERTIES.each( this._compute, this );
3632         this._end();
3633         this._preComputing = false;
3634       }
3635     },
3637     _set: function(property, value) {
3638       return Hash.prototype.set.call(this, property, value);
3639     },
3641     set: function(property, value) {
3642       throw "Properties of Element.Layout are read-only.";
3643     },
3645     get: function($super, property) {
3646       var value = $super(property);
3647       return value === null ? this._compute(property) : value;
3648     },
3650     _begin: function() {
3651       if (this._isPrepared()) return;
3653       var element = this.element;
3654       if (isDisplayed(element)) {
3655         this._setPrepared(true);
3656         return;
3657       }
3660       var originalStyles = {
3661         position:   element.style.position   || '',
3662         width:      element.style.width      || '',
3663         visibility: element.style.visibility || '',
3664         display:    element.style.display    || ''
3665       };
3667       element.store('prototype_original_styles', originalStyles);
3669       var position = getRawStyle(element, 'position'), width = element.offsetWidth;
3671       if (width === 0 || width === null) {
3672         element.style.display = 'block';
3673         width = element.offsetWidth;
3674       }
3676       var context = (position === 'fixed') ? document.viewport :
3677        element.parentNode;
3679       var tempStyles = {
3680         visibility: 'hidden',
3681         display:    'block'
3682       };
3684       if (position !== 'fixed') tempStyles.position = 'absolute';
3686       element.setStyle(tempStyles);
3688       var positionedWidth = element.offsetWidth, newWidth;
3689       if (width && (positionedWidth === width)) {
3690         newWidth = getContentWidth(element, context);
3691       } else if (position === 'absolute' || position === 'fixed') {
3692         newWidth = getContentWidth(element, context);
3693       } else {
3694         var parent = element.parentNode, pLayout = $(parent).getLayout();
3696         newWidth = pLayout.get('width') -
3697          this.get('margin-left') -
3698          this.get('border-left') -
3699          this.get('padding-left') -
3700          this.get('padding-right') -
3701          this.get('border-right') -
3702          this.get('margin-right');
3703       }
3705       element.setStyle({ width: newWidth + 'px' });
3707       this._setPrepared(true);
3708     },
3710     _end: function() {
3711       var element = this.element;
3712       var originalStyles = element.retrieve('prototype_original_styles');
3713       element.store('prototype_original_styles', null);
3714       element.setStyle(originalStyles);
3715       this._setPrepared(false);
3716     },
3718     _compute: function(property) {
3719       var COMPUTATIONS = Element.Layout.COMPUTATIONS;
3720       if (!(property in COMPUTATIONS)) {
3721         throw "Property not found.";
3722       }
3724       return this._set(property, COMPUTATIONS[property].call(this, this.element));
3725     },
3727     _isPrepared: function() {
3728       return this.element.retrieve('prototype_element_layout_prepared', false);
3729     },
3731     _setPrepared: function(bool) {
3732       return this.element.store('prototype_element_layout_prepared', bool);
3733     },
3735     toObject: function() {
3736       var args = $A(arguments);
3737       var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3738        args.join(' ').split(' ');
3739       var obj = {};
3740       keys.each( function(key) {
3741         if (!Element.Layout.PROPERTIES.include(key)) return;
3742         var value = this.get(key);
3743         if (value != null) obj[key] = value;
3744       }, this);
3745       return obj;
3746     },
3748     toHash: function() {
3749       var obj = this.toObject.apply(this, arguments);
3750       return new Hash(obj);
3751     },
3753     toCSS: function() {
3754       var args = $A(arguments);
3755       var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3756        args.join(' ').split(' ');
3757       var css = {};
3759       keys.each( function(key) {
3760         if (!Element.Layout.PROPERTIES.include(key)) return;
3761         if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
3763         var value = this.get(key);
3764         if (value != null) css[cssNameFor(key)] = value + 'px';
3765       }, this);
3766       return css;
3767     },
3769     inspect: function() {
3770       return "#<Element.Layout>";
3771     }
3772   });
3774   Object.extend(Element.Layout, {
3775     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'),
3777     COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3779     COMPUTATIONS: {
3780       'height': function(element) {
3781         if (!this._preComputing) this._begin();
3783         var bHeight = this.get('border-box-height');
3784         if (bHeight <= 0) {
3785           if (!this._preComputing) this._end();
3786           return 0;
3787         }
3789         var bTop = this.get('border-top'),
3790          bBottom = this.get('border-bottom');
3792         var pTop = this.get('padding-top'),
3793          pBottom = this.get('padding-bottom');
3795         if (!this._preComputing) this._end();
3797         return bHeight - bTop - bBottom - pTop - pBottom;
3798       },
3800       'width': function(element) {
3801         if (!this._preComputing) this._begin();
3803         var bWidth = this.get('border-box-width');
3804         if (bWidth <= 0) {
3805           if (!this._preComputing) this._end();
3806           return 0;
3807         }
3809         var bLeft = this.get('border-left'),
3810          bRight = this.get('border-right');
3812         var pLeft = this.get('padding-left'),
3813          pRight = this.get('padding-right');
3815         if (!this._preComputing) this._end();
3816         return bWidth - bLeft - bRight - pLeft - pRight;
3817       },
3819       'padding-box-height': function(element) {
3820         var height = this.get('height'),
3821          pTop = this.get('padding-top'),
3822          pBottom = this.get('padding-bottom');
3824         return height + pTop + pBottom;
3825       },
3827       'padding-box-width': function(element) {
3828         var width = this.get('width'),
3829          pLeft = this.get('padding-left'),
3830          pRight = this.get('padding-right');
3832         return width + pLeft + pRight;
3833       },
3835       'border-box-height': function(element) {
3836         if (!this._preComputing) this._begin();
3837         var height = element.offsetHeight;
3838         if (!this._preComputing) this._end();
3839         return height;
3840       },
3842       'border-box-width': function(element) {
3843         if (!this._preComputing) this._begin();
3844         var width = element.offsetWidth;
3845         if (!this._preComputing) this._end();
3846         return width;
3847       },
3849       'margin-box-height': function(element) {
3850         var bHeight = this.get('border-box-height'),
3851          mTop = this.get('margin-top'),
3852          mBottom = this.get('margin-bottom');
3854         if (bHeight <= 0) return 0;
3856         return bHeight + mTop + mBottom;
3857       },
3859       'margin-box-width': function(element) {
3860         var bWidth = this.get('border-box-width'),
3861          mLeft = this.get('margin-left'),
3862          mRight = this.get('margin-right');
3864         if (bWidth <= 0) return 0;
3866         return bWidth + mLeft + mRight;
3867       },
3869       'top': function(element) {
3870         var offset = element.positionedOffset();
3871         return offset.top;
3872       },
3874       'bottom': function(element) {
3875         var offset = element.positionedOffset(),
3876          parent = element.getOffsetParent(),
3877          pHeight = parent.measure('height');
3879         var mHeight = this.get('border-box-height');
3881         return pHeight - mHeight - offset.top;
3882       },
3884       'left': function(element) {
3885         var offset = element.positionedOffset();
3886         return offset.left;
3887       },
3889       'right': function(element) {
3890         var offset = element.positionedOffset(),
3891          parent = element.getOffsetParent(),
3892          pWidth = parent.measure('width');
3894         var mWidth = this.get('border-box-width');
3896         return pWidth - mWidth - offset.left;
3897       },
3899       'padding-top': function(element) {
3900         return getPixelValue(element, 'paddingTop');
3901       },
3903       'padding-bottom': function(element) {
3904         return getPixelValue(element, 'paddingBottom');
3905       },
3907       'padding-left': function(element) {
3908         return getPixelValue(element, 'paddingLeft');
3909       },
3911       'padding-right': function(element) {
3912         return getPixelValue(element, 'paddingRight');
3913       },
3915       'border-top': function(element) {
3916         return getPixelValue(element, 'borderTopWidth');
3917       },
3919       'border-bottom': function(element) {
3920         return getPixelValue(element, 'borderBottomWidth');
3921       },
3923       'border-left': function(element) {
3924         return getPixelValue(element, 'borderLeftWidth');
3925       },
3927       'border-right': function(element) {
3928         return getPixelValue(element, 'borderRightWidth');
3929       },
3931       'margin-top': function(element) {
3932         return getPixelValue(element, 'marginTop');
3933       },
3935       'margin-bottom': function(element) {
3936         return getPixelValue(element, 'marginBottom');
3937       },
3939       'margin-left': function(element) {
3940         return getPixelValue(element, 'marginLeft');
3941       },
3943       'margin-right': function(element) {
3944         return getPixelValue(element, 'marginRight');
3945       }
3946     }
3947   });
3949   if ('getBoundingClientRect' in document.documentElement) {
3950     Object.extend(Element.Layout.COMPUTATIONS, {
3951       'right': function(element) {
3952         var parent = hasLayout(element.getOffsetParent());
3953         var rect = element.getBoundingClientRect(),
3954          pRect = parent.getBoundingClientRect();
3956         return (pRect.right - rect.right).round();
3957       },
3959       'bottom': function(element) {
3960         var parent = hasLayout(element.getOffsetParent());
3961         var rect = element.getBoundingClientRect(),
3962          pRect = parent.getBoundingClientRect();
3964         return (pRect.bottom - rect.bottom).round();
3965       }
3966     });
3967   }
3969   Element.Offset = Class.create({
3970     initialize: function(left, top) {
3971       this.left = left.round();
3972       this.top  = top.round();
3974       this[0] = this.left;
3975       this[1] = this.top;
3976     },
3978     relativeTo: function(offset) {
3979       return new Element.Offset(
3980         this.left - offset.left,
3981         this.top  - offset.top
3982       );
3983     },
3985     inspect: function() {
3986       return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3987     },
3989     toString: function() {
3990       return "[#{left}, #{top}]".interpolate(this);
3991     },
3993     toArray: function() {
3994       return [this.left, this.top];
3995     }
3996   });
3998   function getLayout(element, preCompute) {
3999     return new Element.Layout(element, preCompute);
4000   }
4002   function measure(element, property) {
4003     return $(element).getLayout().get(property);
4004   }
4006   function getHeight(element) {
4007     return Element.getDimensions(element).height;
4008   }
4010   function getWidth(element) {
4011     return Element.getDimensions(element).width;
4012   }
4014   function getDimensions(element) {
4015     element = $(element);
4016     var display = Element.getStyle(element, 'display');
4018     if (display && display !== 'none') {
4019       return { width: element.offsetWidth, height: element.offsetHeight };
4020     }
4022     var style = element.style;
4023     var originalStyles = {
4024       visibility: style.visibility,
4025       position:   style.position,
4026       display:    style.display
4027     };
4029     var newStyles = {
4030       visibility: 'hidden',
4031       display:    'block'
4032     };
4034     if (originalStyles.position !== 'fixed')
4035       newStyles.position = 'absolute';
4037     Element.setStyle(element, newStyles);
4039     var dimensions = {
4040       width:  element.offsetWidth,
4041       height: element.offsetHeight
4042     };
4044     Element.setStyle(element, originalStyles);
4046     return dimensions;
4047   }
4049   function getOffsetParent(element) {
4050     element = $(element);
4052     function selfOrBody(element) {
4053       return isHtml(element) ? $(document.body) : $(element);
4054     }
4056     if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4057       return $(document.body);
4059     var isInline = (Element.getStyle(element, 'display') === 'inline');
4060     if (!isInline && element.offsetParent) return selfOrBody(element.offsetParent);
4062     while ((element = element.parentNode) && element !== document.body) {
4063       if (Element.getStyle(element, 'position') !== 'static') {
4064         return selfOrBody(element);
4065       }
4066     }
4068     return $(document.body);
4069   }
4072   function cumulativeOffset(element) {
4073     element = $(element);
4074     var valueT = 0, valueL = 0;
4075     if (element.parentNode) {
4076       do {
4077         valueT += element.offsetTop  || 0;
4078         valueL += element.offsetLeft || 0;
4079         element = element.offsetParent;
4080       } while (element);
4081     }
4082     return new Element.Offset(valueL, valueT);
4083   }
4085   function positionedOffset(element) {
4086     element = $(element);
4088     var layout = element.getLayout();
4090     var valueT = 0, valueL = 0;
4091     do {
4092       valueT += element.offsetTop  || 0;
4093       valueL += element.offsetLeft || 0;
4094       element = element.offsetParent;
4095       if (element) {
4096         if (isBody(element)) break;
4097         var p = Element.getStyle(element, 'position');
4098         if (p !== 'static') break;
4099       }
4100     } while (element);
4102     valueL -= layout.get('margin-left');
4103     valueT -= layout.get('margin-top');
4105     return new Element.Offset(valueL, valueT);
4106   }
4108   function cumulativeScrollOffset(element) {
4109     var valueT = 0, valueL = 0;
4110     do {
4111       if (element === document.body) {
4112         var bodyScrollNode = document.documentElement || document.body.parentNode || document.body;
4113         valueT += !Object.isUndefined(window.pageYOffset) ? window.pageYOffset : bodyScrollNode.scrollTop || 0;
4114         valueL += !Object.isUndefined(window.pageXOffset) ? window.pageXOffset : bodyScrollNode.scrollLeft || 0;
4115         break;
4116       } else {
4117         valueT += element.scrollTop  || 0;
4118         valueL += element.scrollLeft || 0;
4119         element = element.parentNode;
4120       }
4121     } while (element);
4122     return new Element.Offset(valueL, valueT);
4123   }
4125   function viewportOffset(forElement) {
4126     var valueT = 0, valueL = 0, docBody = document.body;
4128     forElement = $(forElement);
4129     var element = forElement;
4130     do {
4131       valueT += element.offsetTop  || 0;
4132       valueL += element.offsetLeft || 0;
4133       if (element.offsetParent == docBody &&
4134         Element.getStyle(element, 'position') == 'absolute') break;
4135     } while (element = element.offsetParent);
4137     element = forElement;
4138     do {
4139       if (element != docBody) {
4140         valueT -= element.scrollTop  || 0;
4141         valueL -= element.scrollLeft || 0;
4142       }
4143     } while (element = element.parentNode);
4144     return new Element.Offset(valueL, valueT);
4145   }
4147   function absolutize(element) {
4148     element = $(element);
4150     if (Element.getStyle(element, 'position') === 'absolute') {
4151       return element;
4152     }
4154     var offsetParent = getOffsetParent(element);
4155     var eOffset = element.viewportOffset(),
4156      pOffset = offsetParent.viewportOffset();
4158     var offset = eOffset.relativeTo(pOffset);
4159     var layout = element.getLayout();
4161     element.store('prototype_absolutize_original_styles', {
4162       position: element.getStyle('position'),
4163       left:     element.getStyle('left'),
4164       top:      element.getStyle('top'),
4165       width:    element.getStyle('width'),
4166       height:   element.getStyle('height')
4167     });
4169     element.setStyle({
4170       position: 'absolute',
4171       top:    offset.top + 'px',
4172       left:   offset.left + 'px',
4173       width:  layout.get('width') + 'px',
4174       height: layout.get('height') + 'px'
4175     });
4177     return element;
4178   }
4180   function relativize(element) {
4181     element = $(element);
4182     if (Element.getStyle(element, 'position') === 'relative') {
4183       return element;
4184     }
4186     var originalStyles =
4187      element.retrieve('prototype_absolutize_original_styles');
4189     if (originalStyles) element.setStyle(originalStyles);
4190     return element;
4191   }
4194   function scrollTo(element) {
4195     element = $(element);
4196     var pos = Element.cumulativeOffset(element);
4197     window.scrollTo(pos.left, pos.top);
4198     return element;
4199   }
4202   function makePositioned(element) {
4203     element = $(element);
4204     var position = Element.getStyle(element, 'position'), styles = {};
4205     if (position === 'static' || !position) {
4206       styles.position = 'relative';
4207       if (Prototype.Browser.Opera) {
4208         styles.top  = 0;
4209         styles.left = 0;
4210       }
4211       Element.setStyle(element, styles);
4212       Element.store(element, 'prototype_made_positioned', true);
4213     }
4214     return element;
4215   }
4217   function undoPositioned(element) {
4218     element = $(element);
4219     var storage = Element.getStorage(element),
4220      madePositioned = storage.get('prototype_made_positioned');
4222     if (madePositioned) {
4223       storage.unset('prototype_made_positioned');
4224       Element.setStyle(element, {
4225         position: '',
4226         top:      '',
4227         bottom:   '',
4228         left:     '',
4229         right:    ''
4230       });
4231     }
4232     return element;
4233   }
4235   function makeClipping(element) {
4236     element = $(element);
4238     var storage = Element.getStorage(element),
4239      madeClipping = storage.get('prototype_made_clipping');
4241     if (Object.isUndefined(madeClipping)) {
4242       var overflow = Element.getStyle(element, 'overflow');
4243       storage.set('prototype_made_clipping', overflow);
4244       if (overflow !== 'hidden')
4245         element.style.overflow = 'hidden';
4246     }
4248     return element;
4249   }
4251   function undoClipping(element) {
4252     element = $(element);
4253     var storage = Element.getStorage(element),
4254      overflow = storage.get('prototype_made_clipping');
4256     if (!Object.isUndefined(overflow)) {
4257       storage.unset('prototype_made_clipping');
4258       element.style.overflow = overflow || '';
4259     }
4261     return element;
4262   }
4264   function clonePosition(element, source, options) {
4265     options = Object.extend({
4266       setLeft:    true,
4267       setTop:     true,
4268       setWidth:   true,
4269       setHeight:  true,
4270       offsetTop:  0,
4271       offsetLeft: 0
4272     }, options || {});
4274     var docEl = document.documentElement;
4276     source  = $(source);
4277     element = $(element);
4278     var p, delta, layout, styles = {};
4280     if (options.setLeft || options.setTop) {
4281       p = Element.viewportOffset(source);
4282       delta = [0, 0];
4283       if (Element.getStyle(element, 'position') === 'absolute') {
4284         var parent = Element.getOffsetParent(element);
4285         if (parent !== document.body) delta = Element.viewportOffset(parent);
4286       }
4287     }
4289     function pageScrollXY() {
4290       var x = 0, y = 0;
4291       if (Object.isNumber(window.pageXOffset)) {
4292         x = window.pageXOffset;
4293         y = window.pageYOffset;
4294       } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
4295         x = document.body.scrollLeft;
4296         y = document.body.scrollTop;
4297       } else if (docEl && (docEl.scrollLeft || docEl.scrollTop)) {
4298         x = docEl.scrollLeft;
4299         y = docEl.scrollTop;
4300       }
4301       return { x: x, y: y };
4302     }
4304     var pageXY = pageScrollXY();
4307     if (options.setWidth || options.setHeight) {
4308       layout = Element.getLayout(source);
4309     }
4311     if (options.setLeft)
4312       styles.left = (p[0] + pageXY.x - delta[0] + options.offsetLeft) + 'px';
4313     if (options.setTop)
4314       styles.top  = (p[1] + pageXY.y - delta[1] + options.offsetTop)  + 'px';
4316     var currentLayout = element.getLayout();
4318     if (options.setWidth) {
4319       styles.width = layout.get('width')  + 'px';
4320     }
4321     if (options.setHeight) {
4322       styles.height = layout.get('height') + 'px';
4323     }
4325     return Element.setStyle(element, styles);
4326   }
4329   if (Prototype.Browser.IE) {
4330     getOffsetParent = getOffsetParent.wrap(
4331       function(proceed, element) {
4332         element = $(element);
4334         if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4335           return $(document.body);
4337         var position = element.getStyle('position');
4338         if (position !== 'static') return proceed(element);
4340         element.setStyle({ position: 'relative' });
4341         var value = proceed(element);
4342         element.setStyle({ position: position });
4343         return value;
4344       }
4345     );
4347     positionedOffset = positionedOffset.wrap(function(proceed, element) {
4348       element = $(element);
4349       if (!element.parentNode) return new Element.Offset(0, 0);
4350       var position = element.getStyle('position');
4351       if (position !== 'static') return proceed(element);
4353       var offsetParent = element.getOffsetParent();
4354       if (offsetParent && offsetParent.getStyle('position') === 'fixed')
4355         hasLayout(offsetParent);
4357       element.setStyle({ position: 'relative' });
4358       var value = proceed(element);
4359       element.setStyle({ position: position });
4360       return value;
4361     });
4362   } else if (Prototype.Browser.Webkit) {
4363     cumulativeOffset = function(element) {
4364       element = $(element);
4365       var valueT = 0, valueL = 0;
4366       do {
4367         valueT += element.offsetTop  || 0;
4368         valueL += element.offsetLeft || 0;
4369         if (element.offsetParent == document.body) {
4370           if (Element.getStyle(element, 'position') == 'absolute') break;
4371         }
4373         element = element.offsetParent;
4374       } while (element);
4376       return new Element.Offset(valueL, valueT);
4377     };
4378   }
4381   Element.addMethods({
4382     getLayout:              getLayout,
4383     measure:                measure,
4384     getWidth:               getWidth,
4385     getHeight:              getHeight,
4386     getDimensions:          getDimensions,
4387     getOffsetParent:        getOffsetParent,
4388     cumulativeOffset:       cumulativeOffset,
4389     positionedOffset:       positionedOffset,
4390     cumulativeScrollOffset: cumulativeScrollOffset,
4391     viewportOffset:         viewportOffset,
4392     absolutize:             absolutize,
4393     relativize:             relativize,
4394     scrollTo:               scrollTo,
4395     makePositioned:         makePositioned,
4396     undoPositioned:         undoPositioned,
4397     makeClipping:           makeClipping,
4398     undoClipping:           undoClipping,
4399     clonePosition:          clonePosition
4400   });
4402   function isBody(element) {
4403     return element.nodeName.toUpperCase() === 'BODY';
4404   }
4406   function isHtml(element) {
4407     return element.nodeName.toUpperCase() === 'HTML';
4408   }
4410   function isDocument(element) {
4411     return element.nodeType === Node.DOCUMENT_NODE;
4412   }
4414   function isDetached(element) {
4415     return element !== document.body &&
4416      !Element.descendantOf(element, document.body);
4417   }
4419   if ('getBoundingClientRect' in document.documentElement) {
4420     Element.addMethods({
4421       viewportOffset: function(element) {
4422         element = $(element);
4423         if (isDetached(element)) return new Element.Offset(0, 0);
4425         var rect = element.getBoundingClientRect(),
4426          docEl = document.documentElement;
4427         return new Element.Offset(rect.left - docEl.clientLeft,
4428          rect.top - docEl.clientTop);
4429       }
4430     });
4431   }
4434 })();
4436 (function() {
4438   var IS_OLD_OPERA = Prototype.Browser.Opera &&
4439    (window.parseFloat(window.opera.version()) < 9.5);
4440   var ROOT = null;
4441   function getRootElement() {
4442     if (ROOT) return ROOT;
4443     ROOT = IS_OLD_OPERA ? document.body : document.documentElement;
4444     return ROOT;
4445   }
4447   function getDimensions() {
4448     return { width: this.getWidth(), height: this.getHeight() };
4449   }
4451   function getWidth() {
4452     return getRootElement().clientWidth;
4453   }
4455   function getHeight() {
4456     return getRootElement().clientHeight;
4457   }
4459   function getScrollOffsets() {
4460     var x = window.pageXOffset || document.documentElement.scrollLeft ||
4461      document.body.scrollLeft;
4462     var y = window.pageYOffset || document.documentElement.scrollTop ||
4463      document.body.scrollTop;
4465     return new Element.Offset(x, y);
4466   }
4468   document.viewport = {
4469     getDimensions:    getDimensions,
4470     getWidth:         getWidth,
4471     getHeight:        getHeight,
4472     getScrollOffsets: getScrollOffsets
4473   };
4475 })();
4476 window.$$ = function() {
4477   var expression = $A(arguments).join(', ');
4478   return Prototype.Selector.select(expression, document);
4481 Prototype.Selector = (function() {
4483   function select() {
4484     throw new Error('Method "Prototype.Selector.select" must be defined.');
4485   }
4487   function match() {
4488     throw new Error('Method "Prototype.Selector.match" must be defined.');
4489   }
4491   function find(elements, expression, index) {
4492     index = index || 0;
4493     var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
4495     for (i = 0; i < length; i++) {
4496       if (match(elements[i], expression) && index == matchIndex++) {
4497         return Element.extend(elements[i]);
4498       }
4499     }
4500   }
4502   function extendElements(elements) {
4503     for (var i = 0, length = elements.length; i < length; i++) {
4504       Element.extend(elements[i]);
4505     }
4506     return elements;
4507   }
4510   var K = Prototype.K;
4512   return {
4513     select: select,
4514     match: match,
4515     find: find,
4516     extendElements: (Element.extend === K) ? K : extendElements,
4517     extendElement: Element.extend
4518   };
4519 })();
4520 Prototype._original_property = window.Sizzle;
4522 ;(function () {
4523   function fakeDefine(fn) {
4524     Prototype._actual_sizzle = fn();
4525   }
4526   fakeDefine.amd = true;
4528   if (typeof define !== 'undefined' && define.amd) {
4529     Prototype._original_define = define;
4530     Prototype._actual_sizzle = null;
4531     window.define = fakeDefine;
4532   }
4533 })();
4536  * Sizzle CSS Selector Engine v1.10.18
4537  * http://sizzlejs.com/
4539  * Copyright 2013 jQuery Foundation, Inc. and other contributors
4540  * Released under the MIT license
4541  * http://jquery.org/license
4543  * Date: 2014-02-05
4544  */
4545 (function( window ) {
4547 var i,
4548         support,
4549         Expr,
4550         getText,
4551         isXML,
4552         compile,
4553         select,
4554         outermostContext,
4555         sortInput,
4556         hasDuplicate,
4558         setDocument,
4559         document,
4560         docElem,
4561         documentIsHTML,
4562         rbuggyQSA,
4563         rbuggyMatches,
4564         matches,
4565         contains,
4567         expando = "sizzle" + -(new Date()),
4568         preferredDoc = window.document,
4569         dirruns = 0,
4570         done = 0,
4571         classCache = createCache(),
4572         tokenCache = createCache(),
4573         compilerCache = createCache(),
4574         sortOrder = function( a, b ) {
4575                 if ( a === b ) {
4576                         hasDuplicate = true;
4577                 }
4578                 return 0;
4579         },
4581         strundefined = typeof undefined,
4582         MAX_NEGATIVE = 1 << 31,
4584         hasOwn = ({}).hasOwnProperty,
4585         arr = [],
4586         pop = arr.pop,
4587         push_native = arr.push,
4588         push = arr.push,
4589         slice = arr.slice,
4590         indexOf = arr.indexOf || function( elem ) {
4591                 var i = 0,
4592                         len = this.length;
4593                 for ( ; i < len; i++ ) {
4594                         if ( this[i] === elem ) {
4595                                 return i;
4596                         }
4597                 }
4598                 return -1;
4599         },
4601         booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
4604         whitespace = "[\\x20\\t\\r\\n\\f]",
4605         characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
4607         identifier = characterEncoding.replace( "w", "w#" ),
4609         attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
4610                 "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
4612         pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
4614         rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
4616         rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
4617         rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
4619         rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
4621         rpseudo = new RegExp( pseudos ),
4622         ridentifier = new RegExp( "^" + identifier + "$" ),
4624         matchExpr = {
4625                 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
4626                 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
4627                 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
4628                 "ATTR": new RegExp( "^" + attributes ),
4629                 "PSEUDO": new RegExp( "^" + pseudos ),
4630                 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
4631                         "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
4632                         "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
4633                 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
4634                 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
4635                         whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
4636         },
4638         rinputs = /^(?:input|select|textarea|button)$/i,
4639         rheader = /^h\d$/i,
4641         rnative = /^[^{]+\{\s*\[native \w/,
4643         rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
4645         rsibling = /[+~]/,
4646         rescape = /'|\\/g,
4648         runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
4649         funescape = function( _, escaped, escapedWhitespace ) {
4650                 var high = "0x" + escaped - 0x10000;
4651                 return high !== high || escapedWhitespace ?
4652                         escaped :
4653                         high < 0 ?
4654                                 String.fromCharCode( high + 0x10000 ) :
4655                                 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
4656         };
4658 try {
4659         push.apply(
4660                 (arr = slice.call( preferredDoc.childNodes )),
4661                 preferredDoc.childNodes
4662         );
4663         arr[ preferredDoc.childNodes.length ].nodeType;
4664 } catch ( e ) {
4665         push = { apply: arr.length ?
4667                 function( target, els ) {
4668                         push_native.apply( target, slice.call(els) );
4669                 } :
4671                 function( target, els ) {
4672                         var j = target.length,
4673                                 i = 0;
4674                         while ( (target[j++] = els[i++]) ) {}
4675                         target.length = j - 1;
4676                 }
4677         };
4680 function Sizzle( selector, context, results, seed ) {
4681         var match, elem, m, nodeType,
4682                 i, groups, old, nid, newContext, newSelector;
4684         if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
4685                 setDocument( context );
4686         }
4688         context = context || document;
4689         results = results || [];
4691         if ( !selector || typeof selector !== "string" ) {
4692                 return results;
4693         }
4695         if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
4696                 return [];
4697         }
4699         if ( documentIsHTML && !seed ) {
4701                 if ( (match = rquickExpr.exec( selector )) ) {
4702                         if ( (m = match[1]) ) {
4703                                 if ( nodeType === 9 ) {
4704                                         elem = context.getElementById( m );
4705                                         if ( elem && elem.parentNode ) {
4706                                                 if ( elem.id === m ) {
4707                                                         results.push( elem );
4708                                                         return results;
4709                                                 }
4710                                         } else {
4711                                                 return results;
4712                                         }
4713                                 } else {
4714                                         if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
4715                                                 contains( context, elem ) && elem.id === m ) {
4716                                                 results.push( elem );
4717                                                 return results;
4718                                         }
4719                                 }
4721                         } else if ( match[2] ) {
4722                                 push.apply( results, context.getElementsByTagName( selector ) );
4723                                 return results;
4725                         } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
4726                                 push.apply( results, context.getElementsByClassName( m ) );
4727                                 return results;
4728                         }
4729                 }
4731                 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
4732                         nid = old = expando;
4733                         newContext = context;
4734                         newSelector = nodeType === 9 && selector;
4736                         if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
4737                                 groups = tokenize( selector );
4739                                 if ( (old = context.getAttribute("id")) ) {
4740                                         nid = old.replace( rescape, "\\$&" );
4741                                 } else {
4742                                         context.setAttribute( "id", nid );
4743                                 }
4744                                 nid = "[id='" + nid + "'] ";
4746                                 i = groups.length;
4747                                 while ( i-- ) {
4748                                         groups[i] = nid + toSelector( groups[i] );
4749                                 }
4750                                 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
4751                                 newSelector = groups.join(",");
4752                         }
4754                         if ( newSelector ) {
4755                                 try {
4756                                         push.apply( results,
4757                                                 newContext.querySelectorAll( newSelector )
4758                                         );
4759                                         return results;
4760                                 } catch(qsaError) {
4761                                 } finally {
4762                                         if ( !old ) {
4763                                                 context.removeAttribute("id");
4764                                         }
4765                                 }
4766                         }
4767                 }
4768         }
4770         return select( selector.replace( rtrim, "$1" ), context, results, seed );
4774  * Create key-value caches of limited size
4775  * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
4776  *      property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
4777  *      deleting the oldest entry
4778  */
4779 function createCache() {
4780         var keys = [];
4782         function cache( key, value ) {
4783                 if ( keys.push( key + " " ) > Expr.cacheLength ) {
4784                         delete cache[ keys.shift() ];
4785                 }
4786                 return (cache[ key + " " ] = value);
4787         }
4788         return cache;
4792  * Mark a function for special use by Sizzle
4793  * @param {Function} fn The function to mark
4794  */
4795 function markFunction( fn ) {
4796         fn[ expando ] = true;
4797         return fn;
4801  * Support testing using an element
4802  * @param {Function} fn Passed the created div and expects a boolean result
4803  */
4804 function assert( fn ) {
4805         var div = document.createElement("div");
4807         try {
4808                 return !!fn( div );
4809         } catch (e) {
4810                 return false;
4811         } finally {
4812                 if ( div.parentNode ) {
4813                         div.parentNode.removeChild( div );
4814                 }
4815                 div = null;
4816         }
4820  * Adds the same handler for all of the specified attrs
4821  * @param {String} attrs Pipe-separated list of attributes
4822  * @param {Function} handler The method that will be applied
4823  */
4824 function addHandle( attrs, handler ) {
4825         var arr = attrs.split("|"),
4826                 i = attrs.length;
4828         while ( i-- ) {
4829                 Expr.attrHandle[ arr[i] ] = handler;
4830         }
4834  * Checks document order of two siblings
4835  * @param {Element} a
4836  * @param {Element} b
4837  * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
4838  */
4839 function siblingCheck( a, b ) {
4840         var cur = b && a,
4841                 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
4842                         ( ~b.sourceIndex || MAX_NEGATIVE ) -
4843                         ( ~a.sourceIndex || MAX_NEGATIVE );
4845         if ( diff ) {
4846                 return diff;
4847         }
4849         if ( cur ) {
4850                 while ( (cur = cur.nextSibling) ) {
4851                         if ( cur === b ) {
4852                                 return -1;
4853                         }
4854                 }
4855         }
4857         return a ? 1 : -1;
4861  * Returns a function to use in pseudos for input types
4862  * @param {String} type
4863  */
4864 function createInputPseudo( type ) {
4865         return function( elem ) {
4866                 var name = elem.nodeName.toLowerCase();
4867                 return name === "input" && elem.type === type;
4868         };
4872  * Returns a function to use in pseudos for buttons
4873  * @param {String} type
4874  */
4875 function createButtonPseudo( type ) {
4876         return function( elem ) {
4877                 var name = elem.nodeName.toLowerCase();
4878                 return (name === "input" || name === "button") && elem.type === type;
4879         };
4883  * Returns a function to use in pseudos for positionals
4884  * @param {Function} fn
4885  */
4886 function createPositionalPseudo( fn ) {
4887         return markFunction(function( argument ) {
4888                 argument = +argument;
4889                 return markFunction(function( seed, matches ) {
4890                         var j,
4891                                 matchIndexes = fn( [], seed.length, argument ),
4892                                 i = matchIndexes.length;
4894                         while ( i-- ) {
4895                                 if ( seed[ (j = matchIndexes[i]) ] ) {
4896                                         seed[j] = !(matches[j] = seed[j]);
4897                                 }
4898                         }
4899                 });
4900         });
4904  * Checks a node for validity as a Sizzle context
4905  * @param {Element|Object=} context
4906  * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
4907  */
4908 function testContext( context ) {
4909         return context && typeof context.getElementsByTagName !== strundefined && context;
4912 support = Sizzle.support = {};
4915  * Detects XML nodes
4916  * @param {Element|Object} elem An element or a document
4917  * @returns {Boolean} True iff elem is a non-HTML XML node
4918  */
4919 isXML = Sizzle.isXML = function( elem ) {
4920         var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4921         return documentElement ? documentElement.nodeName !== "HTML" : false;
4925  * Sets document-related variables once based on the current document
4926  * @param {Element|Object} [doc] An element or document object to use to set the document
4927  * @returns {Object} Returns the current document
4928  */
4929 setDocument = Sizzle.setDocument = function( node ) {
4930         var hasCompare,
4931                 doc = node ? node.ownerDocument || node : preferredDoc,
4932                 parent = doc.defaultView;
4934         if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4935                 return document;
4936         }
4938         document = doc;
4939         docElem = doc.documentElement;
4941         documentIsHTML = !isXML( doc );
4943         if ( parent && parent !== parent.top ) {
4944                 if ( parent.addEventListener ) {
4945                         parent.addEventListener( "unload", function() {
4946                                 setDocument();
4947                         }, false );
4948                 } else if ( parent.attachEvent ) {
4949                         parent.attachEvent( "onunload", function() {
4950                                 setDocument();
4951                         });
4952                 }
4953         }
4955         /* Attributes
4956         ---------------------------------------------------------------------- */
4958         support.attributes = assert(function( div ) {
4959                 div.className = "i";
4960                 return !div.getAttribute("className");
4961         });
4963         /* getElement(s)By*
4964         ---------------------------------------------------------------------- */
4966         support.getElementsByTagName = assert(function( div ) {
4967                 div.appendChild( doc.createComment("") );
4968                 return !div.getElementsByTagName("*").length;
4969         });
4971         support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
4972                 div.innerHTML = "<div class='a'></div><div class='a i'></div>";
4974                 div.firstChild.className = "i";
4975                 return div.getElementsByClassName("i").length === 2;
4976         });
4978         support.getById = assert(function( div ) {
4979                 docElem.appendChild( div ).id = expando;
4980                 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
4981         });
4983         if ( support.getById ) {
4984                 Expr.find["ID"] = function( id, context ) {
4985                         if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
4986                                 var m = context.getElementById( id );
4987                                 return m && m.parentNode ? [m] : [];
4988                         }
4989                 };
4990                 Expr.filter["ID"] = function( id ) {
4991                         var attrId = id.replace( runescape, funescape );
4992                         return function( elem ) {
4993                                 return elem.getAttribute("id") === attrId;
4994                         };
4995                 };
4996         } else {
4997                 delete Expr.find["ID"];
4999                 Expr.filter["ID"] =  function( id ) {
5000                         var attrId = id.replace( runescape, funescape );
5001                         return function( elem ) {
5002                                 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
5003                                 return node && node.value === attrId;
5004                         };
5005                 };
5006         }
5008         Expr.find["TAG"] = support.getElementsByTagName ?
5009                 function( tag, context ) {
5010                         if ( typeof context.getElementsByTagName !== strundefined ) {
5011                                 return context.getElementsByTagName( tag );
5012                         }
5013                 } :
5014                 function( tag, context ) {
5015                         var elem,
5016                                 tmp = [],
5017                                 i = 0,
5018                                 results = context.getElementsByTagName( tag );
5020                         if ( tag === "*" ) {
5021                                 while ( (elem = results[i++]) ) {
5022                                         if ( elem.nodeType === 1 ) {
5023                                                 tmp.push( elem );
5024                                         }
5025                                 }
5027                                 return tmp;
5028                         }
5029                         return results;
5030                 };
5032         Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
5033                 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
5034                         return context.getElementsByClassName( className );
5035                 }
5036         };
5038         /* QSA/matchesSelector
5039         ---------------------------------------------------------------------- */
5042         rbuggyMatches = [];
5044         rbuggyQSA = [];
5046         if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
5047                 assert(function( div ) {
5048                         div.innerHTML = "<select t=''><option selected=''></option></select>";
5050                         if ( div.querySelectorAll("[t^='']").length ) {
5051                                 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
5052                         }
5054                         if ( !div.querySelectorAll("[selected]").length ) {
5055                                 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
5056                         }
5058                         if ( !div.querySelectorAll(":checked").length ) {
5059                                 rbuggyQSA.push(":checked");
5060                         }
5061                 });
5063                 assert(function( div ) {
5064                         var input = doc.createElement("input");
5065                         input.setAttribute( "type", "hidden" );
5066                         div.appendChild( input ).setAttribute( "name", "D" );
5068                         if ( div.querySelectorAll("[name=d]").length ) {
5069                                 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
5070                         }
5072                         if ( !div.querySelectorAll(":enabled").length ) {
5073                                 rbuggyQSA.push( ":enabled", ":disabled" );
5074                         }
5076                         div.querySelectorAll("*,:x");
5077                         rbuggyQSA.push(",.*:");
5078                 });
5079         }
5081         if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
5082                 docElem.mozMatchesSelector ||
5083                 docElem.oMatchesSelector ||
5084                 docElem.msMatchesSelector) )) ) {
5086                 assert(function( div ) {
5087                         support.disconnectedMatch = matches.call( div, "div" );
5089                         matches.call( div, "[s!='']:x" );
5090                         rbuggyMatches.push( "!=", pseudos );
5091                 });
5092         }
5094         rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
5095         rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
5097         /* Contains
5098         ---------------------------------------------------------------------- */
5099         hasCompare = rnative.test( docElem.compareDocumentPosition );
5101         contains = hasCompare || rnative.test( docElem.contains ) ?
5102                 function( a, b ) {
5103                         var adown = a.nodeType === 9 ? a.documentElement : a,
5104                                 bup = b && b.parentNode;
5105                         return a === bup || !!( bup && bup.nodeType === 1 && (
5106                                 adown.contains ?
5107                                         adown.contains( bup ) :
5108                                         a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
5109                         ));
5110                 } :
5111                 function( a, b ) {
5112                         if ( b ) {
5113                                 while ( (b = b.parentNode) ) {
5114                                         if ( b === a ) {
5115                                                 return true;
5116                                         }
5117                                 }
5118                         }
5119                         return false;
5120                 };
5122         /* Sorting
5123         ---------------------------------------------------------------------- */
5125         sortOrder = hasCompare ?
5126         function( a, b ) {
5128                 if ( a === b ) {
5129                         hasDuplicate = true;
5130                         return 0;
5131                 }
5133                 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
5134                 if ( compare ) {
5135                         return compare;
5136                 }
5138                 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
5139                         a.compareDocumentPosition( b ) :
5141                         1;
5143                 if ( compare & 1 ||
5144                         (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
5146                         if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
5147                                 return -1;
5148                         }
5149                         if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
5150                                 return 1;
5151                         }
5153                         return sortInput ?
5154                                 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5155                                 0;
5156                 }
5158                 return compare & 4 ? -1 : 1;
5159         } :
5160         function( a, b ) {
5161                 if ( a === b ) {
5162                         hasDuplicate = true;
5163                         return 0;
5164                 }
5166                 var cur,
5167                         i = 0,
5168                         aup = a.parentNode,
5169                         bup = b.parentNode,
5170                         ap = [ a ],
5171                         bp = [ b ];
5173                 if ( !aup || !bup ) {
5174                         return a === doc ? -1 :
5175                                 b === doc ? 1 :
5176                                 aup ? -1 :
5177                                 bup ? 1 :
5178                                 sortInput ?
5179                                 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5180                                 0;
5182                 } else if ( aup === bup ) {
5183                         return siblingCheck( a, b );
5184                 }
5186                 cur = a;
5187                 while ( (cur = cur.parentNode) ) {
5188                         ap.unshift( cur );
5189                 }
5190                 cur = b;
5191                 while ( (cur = cur.parentNode) ) {
5192                         bp.unshift( cur );
5193                 }
5195                 while ( ap[i] === bp[i] ) {
5196                         i++;
5197                 }
5199                 return i ?
5200                         siblingCheck( ap[i], bp[i] ) :
5202                         ap[i] === preferredDoc ? -1 :
5203                         bp[i] === preferredDoc ? 1 :
5204                         0;
5205         };
5207         return doc;
5210 Sizzle.matches = function( expr, elements ) {
5211         return Sizzle( expr, null, null, elements );
5214 Sizzle.matchesSelector = function( elem, expr ) {
5215         if ( ( elem.ownerDocument || elem ) !== document ) {
5216                 setDocument( elem );
5217         }
5219         expr = expr.replace( rattributeQuotes, "='$1']" );
5221         if ( support.matchesSelector && documentIsHTML &&
5222                 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
5223                 ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
5225                 try {
5226                         var ret = matches.call( elem, expr );
5228                         if ( ret || support.disconnectedMatch ||
5229                                         elem.document && elem.document.nodeType !== 11 ) {
5230                                 return ret;
5231                         }
5232                 } catch(e) {}
5233         }
5235         return Sizzle( expr, document, null, [elem] ).length > 0;
5238 Sizzle.contains = function( context, elem ) {
5239         if ( ( context.ownerDocument || context ) !== document ) {
5240                 setDocument( context );
5241         }
5242         return contains( context, elem );
5245 Sizzle.attr = function( elem, name ) {
5246         if ( ( elem.ownerDocument || elem ) !== document ) {
5247                 setDocument( elem );
5248         }
5250         var fn = Expr.attrHandle[ name.toLowerCase() ],
5251                 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
5252                         fn( elem, name, !documentIsHTML ) :
5253                         undefined;
5255         return val !== undefined ?
5256                 val :
5257                 support.attributes || !documentIsHTML ?
5258                         elem.getAttribute( name ) :
5259                         (val = elem.getAttributeNode(name)) && val.specified ?
5260                                 val.value :
5261                                 null;
5264 Sizzle.error = function( msg ) {
5265         throw new Error( "Syntax error, unrecognized expression: " + msg );
5269  * Document sorting and removing duplicates
5270  * @param {ArrayLike} results
5271  */
5272 Sizzle.uniqueSort = function( results ) {
5273         var elem,
5274                 duplicates = [],
5275                 j = 0,
5276                 i = 0;
5278         hasDuplicate = !support.detectDuplicates;
5279         sortInput = !support.sortStable && results.slice( 0 );
5280         results.sort( sortOrder );
5282         if ( hasDuplicate ) {
5283                 while ( (elem = results[i++]) ) {
5284                         if ( elem === results[ i ] ) {
5285                                 j = duplicates.push( i );
5286                         }
5287                 }
5288                 while ( j-- ) {
5289                         results.splice( duplicates[ j ], 1 );
5290                 }
5291         }
5293         sortInput = null;
5295         return results;
5299  * Utility function for retrieving the text value of an array of DOM nodes
5300  * @param {Array|Element} elem
5301  */
5302 getText = Sizzle.getText = function( elem ) {
5303         var node,
5304                 ret = "",
5305                 i = 0,
5306                 nodeType = elem.nodeType;
5308         if ( !nodeType ) {
5309                 while ( (node = elem[i++]) ) {
5310                         ret += getText( node );
5311                 }
5312         } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
5313                 if ( typeof elem.textContent === "string" ) {
5314                         return elem.textContent;
5315                 } else {
5316                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5317                                 ret += getText( elem );
5318                         }
5319                 }
5320         } else if ( nodeType === 3 || nodeType === 4 ) {
5321                 return elem.nodeValue;
5322         }
5324         return ret;
5327 Expr = Sizzle.selectors = {
5329         cacheLength: 50,
5331         createPseudo: markFunction,
5333         match: matchExpr,
5335         attrHandle: {},
5337         find: {},
5339         relative: {
5340                 ">": { dir: "parentNode", first: true },
5341                 " ": { dir: "parentNode" },
5342                 "+": { dir: "previousSibling", first: true },
5343                 "~": { dir: "previousSibling" }
5344         },
5346         preFilter: {
5347                 "ATTR": function( match ) {
5348                         match[1] = match[1].replace( runescape, funescape );
5350                         match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
5352                         if ( match[2] === "~=" ) {
5353                                 match[3] = " " + match[3] + " ";
5354                         }
5356                         return match.slice( 0, 4 );
5357                 },
5359                 "CHILD": function( match ) {
5360                         /* matches from matchExpr["CHILD"]
5361                                 1 type (only|nth|...)
5362                                 2 what (child|of-type)
5363                                 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
5364                                 4 xn-component of xn+y argument ([+-]?\d*n|)
5365                                 5 sign of xn-component
5366                                 6 x of xn-component
5367                                 7 sign of y-component
5368                                 8 y of y-component
5369                         */
5370                         match[1] = match[1].toLowerCase();
5372                         if ( match[1].slice( 0, 3 ) === "nth" ) {
5373                                 if ( !match[3] ) {
5374                                         Sizzle.error( match[0] );
5375                                 }
5377                                 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
5378                                 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
5380                         } else if ( match[3] ) {
5381                                 Sizzle.error( match[0] );
5382                         }
5384                         return match;
5385                 },
5387                 "PSEUDO": function( match ) {
5388                         var excess,
5389                                 unquoted = !match[5] && match[2];
5391                         if ( matchExpr["CHILD"].test( match[0] ) ) {
5392                                 return null;
5393                         }
5395                         if ( match[3] && match[4] !== undefined ) {
5396                                 match[2] = match[4];
5398                         } else if ( unquoted && rpseudo.test( unquoted ) &&
5399                                 (excess = tokenize( unquoted, true )) &&
5400                                 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
5402                                 match[0] = match[0].slice( 0, excess );
5403                                 match[2] = unquoted.slice( 0, excess );
5404                         }
5406                         return match.slice( 0, 3 );
5407                 }
5408         },
5410         filter: {
5412                 "TAG": function( nodeNameSelector ) {
5413                         var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
5414                         return nodeNameSelector === "*" ?
5415                                 function() { return true; } :
5416                                 function( elem ) {
5417                                         return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
5418                                 };
5419                 },
5421                 "CLASS": function( className ) {
5422                         var pattern = classCache[ className + " " ];
5424                         return pattern ||
5425                                 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
5426                                 classCache( className, function( elem ) {
5427                                         return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
5428                                 });
5429                 },
5431                 "ATTR": function( name, operator, check ) {
5432                         return function( elem ) {
5433                                 var result = Sizzle.attr( elem, name );
5435                                 if ( result == null ) {
5436                                         return operator === "!=";
5437                                 }
5438                                 if ( !operator ) {
5439                                         return true;
5440                                 }
5442                                 result += "";
5444                                 return operator === "=" ? result === check :
5445                                         operator === "!=" ? result !== check :
5446                                         operator === "^=" ? check && result.indexOf( check ) === 0 :
5447                                         operator === "*=" ? check && result.indexOf( check ) > -1 :
5448                                         operator === "$=" ? check && result.slice( -check.length ) === check :
5449                                         operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
5450                                         operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
5451                                         false;
5452                         };
5453                 },
5455                 "CHILD": function( type, what, argument, first, last ) {
5456                         var simple = type.slice( 0, 3 ) !== "nth",
5457                                 forward = type.slice( -4 ) !== "last",
5458                                 ofType = what === "of-type";
5460                         return first === 1 && last === 0 ?
5462                                 function( elem ) {
5463                                         return !!elem.parentNode;
5464                                 } :
5466                                 function( elem, context, xml ) {
5467                                         var cache, outerCache, node, diff, nodeIndex, start,
5468                                                 dir = simple !== forward ? "nextSibling" : "previousSibling",
5469                                                 parent = elem.parentNode,
5470                                                 name = ofType && elem.nodeName.toLowerCase(),
5471                                                 useCache = !xml && !ofType;
5473                                         if ( parent ) {
5475                                                 if ( simple ) {
5476                                                         while ( dir ) {
5477                                                                 node = elem;
5478                                                                 while ( (node = node[ dir ]) ) {
5479                                                                         if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
5480                                                                                 return false;
5481                                                                         }
5482                                                                 }
5483                                                                 start = dir = type === "only" && !start && "nextSibling";
5484                                                         }
5485                                                         return true;
5486                                                 }
5488                                                 start = [ forward ? parent.firstChild : parent.lastChild ];
5490                                                 if ( forward && useCache ) {
5491                                                         outerCache = parent[ expando ] || (parent[ expando ] = {});
5492                                                         cache = outerCache[ type ] || [];
5493                                                         nodeIndex = cache[0] === dirruns && cache[1];
5494                                                         diff = cache[0] === dirruns && cache[2];
5495                                                         node = nodeIndex && parent.childNodes[ nodeIndex ];
5497                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
5499                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
5501                                                                 if ( node.nodeType === 1 && ++diff && node === elem ) {
5502                                                                         outerCache[ type ] = [ dirruns, nodeIndex, diff ];
5503                                                                         break;
5504                                                                 }
5505                                                         }
5507                                                 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
5508                                                         diff = cache[1];
5510                                                 } else {
5511                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
5512                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
5514                                                                 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
5515                                                                         if ( useCache ) {
5516                                                                                 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
5517                                                                         }
5519                                                                         if ( node === elem ) {
5520                                                                                 break;
5521                                                                         }
5522                                                                 }
5523                                                         }
5524                                                 }
5526                                                 diff -= last;
5527                                                 return diff === first || ( diff % first === 0 && diff / first >= 0 );
5528                                         }
5529                                 };
5530                 },
5532                 "PSEUDO": function( pseudo, argument ) {
5533                         var args,
5534                                 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
5535                                         Sizzle.error( "unsupported pseudo: " + pseudo );
5537                         if ( fn[ expando ] ) {
5538                                 return fn( argument );
5539                         }
5541                         if ( fn.length > 1 ) {
5542                                 args = [ pseudo, pseudo, "", argument ];
5543                                 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
5544                                         markFunction(function( seed, matches ) {
5545                                                 var idx,
5546                                                         matched = fn( seed, argument ),
5547                                                         i = matched.length;
5548                                                 while ( i-- ) {
5549                                                         idx = indexOf.call( seed, matched[i] );
5550                                                         seed[ idx ] = !( matches[ idx ] = matched[i] );
5551                                                 }
5552                                         }) :
5553                                         function( elem ) {
5554                                                 return fn( elem, 0, args );
5555                                         };
5556                         }
5558                         return fn;
5559                 }
5560         },
5562         pseudos: {
5563                 "not": markFunction(function( selector ) {
5564                         var input = [],
5565                                 results = [],
5566                                 matcher = compile( selector.replace( rtrim, "$1" ) );
5568                         return matcher[ expando ] ?
5569                                 markFunction(function( seed, matches, context, xml ) {
5570                                         var elem,
5571                                                 unmatched = matcher( seed, null, xml, [] ),
5572                                                 i = seed.length;
5574                                         while ( i-- ) {
5575                                                 if ( (elem = unmatched[i]) ) {
5576                                                         seed[i] = !(matches[i] = elem);
5577                                                 }
5578                                         }
5579                                 }) :
5580                                 function( elem, context, xml ) {
5581                                         input[0] = elem;
5582                                         matcher( input, null, xml, results );
5583                                         return !results.pop();
5584                                 };
5585                 }),
5587                 "has": markFunction(function( selector ) {
5588                         return function( elem ) {
5589                                 return Sizzle( selector, elem ).length > 0;
5590                         };
5591                 }),
5593                 "contains": markFunction(function( text ) {
5594                         return function( elem ) {
5595                                 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
5596                         };
5597                 }),
5599                 "lang": markFunction( function( lang ) {
5600                         if ( !ridentifier.test(lang || "") ) {
5601                                 Sizzle.error( "unsupported lang: " + lang );
5602                         }
5603                         lang = lang.replace( runescape, funescape ).toLowerCase();
5604                         return function( elem ) {
5605                                 var elemLang;
5606                                 do {
5607                                         if ( (elemLang = documentIsHTML ?
5608                                                 elem.lang :
5609                                                 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
5611                                                 elemLang = elemLang.toLowerCase();
5612                                                 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
5613                                         }
5614                                 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
5615                                 return false;
5616                         };
5617                 }),
5619                 "target": function( elem ) {
5620                         var hash = window.location && window.location.hash;
5621                         return hash && hash.slice( 1 ) === elem.id;
5622                 },
5624                 "root": function( elem ) {
5625                         return elem === docElem;
5626                 },
5628                 "focus": function( elem ) {
5629                         return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
5630                 },
5632                 "enabled": function( elem ) {
5633                         return elem.disabled === false;
5634                 },
5636                 "disabled": function( elem ) {
5637                         return elem.disabled === true;
5638                 },
5640                 "checked": function( elem ) {
5641                         var nodeName = elem.nodeName.toLowerCase();
5642                         return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
5643                 },
5645                 "selected": function( elem ) {
5646                         if ( elem.parentNode ) {
5647                                 elem.parentNode.selectedIndex;
5648                         }
5650                         return elem.selected === true;
5651                 },
5653                 "empty": function( elem ) {
5654                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5655                                 if ( elem.nodeType < 6 ) {
5656                                         return false;
5657                                 }
5658                         }
5659                         return true;
5660                 },
5662                 "parent": function( elem ) {
5663                         return !Expr.pseudos["empty"]( elem );
5664                 },
5666                 "header": function( elem ) {
5667                         return rheader.test( elem.nodeName );
5668                 },
5670                 "input": function( elem ) {
5671                         return rinputs.test( elem.nodeName );
5672                 },
5674                 "button": function( elem ) {
5675                         var name = elem.nodeName.toLowerCase();
5676                         return name === "input" && elem.type === "button" || name === "button";
5677                 },
5679                 "text": function( elem ) {
5680                         var attr;
5681                         return elem.nodeName.toLowerCase() === "input" &&
5682                                 elem.type === "text" &&
5684                                 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
5685                 },
5687                 "first": createPositionalPseudo(function() {
5688                         return [ 0 ];
5689                 }),
5691                 "last": createPositionalPseudo(function( matchIndexes, length ) {
5692                         return [ length - 1 ];
5693                 }),
5695                 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
5696                         return [ argument < 0 ? argument + length : argument ];
5697                 }),
5699                 "even": createPositionalPseudo(function( matchIndexes, length ) {
5700                         var i = 0;
5701                         for ( ; i < length; i += 2 ) {
5702                                 matchIndexes.push( i );
5703                         }
5704                         return matchIndexes;
5705                 }),
5707                 "odd": createPositionalPseudo(function( matchIndexes, length ) {
5708                         var i = 1;
5709                         for ( ; i < length; i += 2 ) {
5710                                 matchIndexes.push( i );
5711                         }
5712                         return matchIndexes;
5713                 }),
5715                 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5716                         var i = argument < 0 ? argument + length : argument;
5717                         for ( ; --i >= 0; ) {
5718                                 matchIndexes.push( i );
5719                         }
5720                         return matchIndexes;
5721                 }),
5723                 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5724                         var i = argument < 0 ? argument + length : argument;
5725                         for ( ; ++i < length; ) {
5726                                 matchIndexes.push( i );
5727                         }
5728                         return matchIndexes;
5729                 })
5730         }
5733 Expr.pseudos["nth"] = Expr.pseudos["eq"];
5735 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5736         Expr.pseudos[ i ] = createInputPseudo( i );
5738 for ( i in { submit: true, reset: true } ) {
5739         Expr.pseudos[ i ] = createButtonPseudo( i );
5742 function setFilters() {}
5743 setFilters.prototype = Expr.filters = Expr.pseudos;
5744 Expr.setFilters = new setFilters();
5746 function tokenize( selector, parseOnly ) {
5747         var matched, match, tokens, type,
5748                 soFar, groups, preFilters,
5749                 cached = tokenCache[ selector + " " ];
5751         if ( cached ) {
5752                 return parseOnly ? 0 : cached.slice( 0 );
5753         }
5755         soFar = selector;
5756         groups = [];
5757         preFilters = Expr.preFilter;
5759         while ( soFar ) {
5761                 if ( !matched || (match = rcomma.exec( soFar )) ) {
5762                         if ( match ) {
5763                                 soFar = soFar.slice( match[0].length ) || soFar;
5764                         }
5765                         groups.push( (tokens = []) );
5766                 }
5768                 matched = false;
5770                 if ( (match = rcombinators.exec( soFar )) ) {
5771                         matched = match.shift();
5772                         tokens.push({
5773                                 value: matched,
5774                                 type: match[0].replace( rtrim, " " )
5775                         });
5776                         soFar = soFar.slice( matched.length );
5777                 }
5779                 for ( type in Expr.filter ) {
5780                         if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5781                                 (match = preFilters[ type ]( match ))) ) {
5782                                 matched = match.shift();
5783                                 tokens.push({
5784                                         value: matched,
5785                                         type: type,
5786                                         matches: match
5787                                 });
5788                                 soFar = soFar.slice( matched.length );
5789                         }
5790                 }
5792                 if ( !matched ) {
5793                         break;
5794                 }
5795         }
5797         return parseOnly ?
5798                 soFar.length :
5799                 soFar ?
5800                         Sizzle.error( selector ) :
5801                         tokenCache( selector, groups ).slice( 0 );
5804 function toSelector( tokens ) {
5805         var i = 0,
5806                 len = tokens.length,
5807                 selector = "";
5808         for ( ; i < len; i++ ) {
5809                 selector += tokens[i].value;
5810         }
5811         return selector;
5814 function addCombinator( matcher, combinator, base ) {
5815         var dir = combinator.dir,
5816                 checkNonElements = base && dir === "parentNode",
5817                 doneName = done++;
5819         return combinator.first ?
5820                 function( elem, context, xml ) {
5821                         while ( (elem = elem[ dir ]) ) {
5822                                 if ( elem.nodeType === 1 || checkNonElements ) {
5823                                         return matcher( elem, context, xml );
5824                                 }
5825                         }
5826                 } :
5828                 function( elem, context, xml ) {
5829                         var oldCache, outerCache,
5830                                 newCache = [ dirruns, doneName ];
5832                         if ( xml ) {
5833                                 while ( (elem = elem[ dir ]) ) {
5834                                         if ( elem.nodeType === 1 || checkNonElements ) {
5835                                                 if ( matcher( elem, context, xml ) ) {
5836                                                         return true;
5837                                                 }
5838                                         }
5839                                 }
5840                         } else {
5841                                 while ( (elem = elem[ dir ]) ) {
5842                                         if ( elem.nodeType === 1 || checkNonElements ) {
5843                                                 outerCache = elem[ expando ] || (elem[ expando ] = {});
5844                                                 if ( (oldCache = outerCache[ dir ]) &&
5845                                                         oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
5847                                                         return (newCache[ 2 ] = oldCache[ 2 ]);
5848                                                 } else {
5849                                                         outerCache[ dir ] = newCache;
5851                                                         if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
5852                                                                 return true;
5853                                                         }
5854                                                 }
5855                                         }
5856                                 }
5857                         }
5858                 };
5861 function elementMatcher( matchers ) {
5862         return matchers.length > 1 ?
5863                 function( elem, context, xml ) {
5864                         var i = matchers.length;
5865                         while ( i-- ) {
5866                                 if ( !matchers[i]( elem, context, xml ) ) {
5867                                         return false;
5868                                 }
5869                         }
5870                         return true;
5871                 } :
5872                 matchers[0];
5875 function multipleContexts( selector, contexts, results ) {
5876         var i = 0,
5877                 len = contexts.length;
5878         for ( ; i < len; i++ ) {
5879                 Sizzle( selector, contexts[i], results );
5880         }
5881         return results;
5884 function condense( unmatched, map, filter, context, xml ) {
5885         var elem,
5886                 newUnmatched = [],
5887                 i = 0,
5888                 len = unmatched.length,
5889                 mapped = map != null;
5891         for ( ; i < len; i++ ) {
5892                 if ( (elem = unmatched[i]) ) {
5893                         if ( !filter || filter( elem, context, xml ) ) {
5894                                 newUnmatched.push( elem );
5895                                 if ( mapped ) {
5896                                         map.push( i );
5897                                 }
5898                         }
5899                 }
5900         }
5902         return newUnmatched;
5905 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5906         if ( postFilter && !postFilter[ expando ] ) {
5907                 postFilter = setMatcher( postFilter );
5908         }
5909         if ( postFinder && !postFinder[ expando ] ) {
5910                 postFinder = setMatcher( postFinder, postSelector );
5911         }
5912         return markFunction(function( seed, results, context, xml ) {
5913                 var temp, i, elem,
5914                         preMap = [],
5915                         postMap = [],
5916                         preexisting = results.length,
5918                         elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5920                         matcherIn = preFilter && ( seed || !selector ) ?
5921                                 condense( elems, preMap, preFilter, context, xml ) :
5922                                 elems,
5924                         matcherOut = matcher ?
5925                                 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5927                                         [] :
5929                                         results :
5930                                 matcherIn;
5932                 if ( matcher ) {
5933                         matcher( matcherIn, matcherOut, context, xml );
5934                 }
5936                 if ( postFilter ) {
5937                         temp = condense( matcherOut, postMap );
5938                         postFilter( temp, [], context, xml );
5940                         i = temp.length;
5941                         while ( i-- ) {
5942                                 if ( (elem = temp[i]) ) {
5943                                         matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5944                                 }
5945                         }
5946                 }
5948                 if ( seed ) {
5949                         if ( postFinder || preFilter ) {
5950                                 if ( postFinder ) {
5951                                         temp = [];
5952                                         i = matcherOut.length;
5953                                         while ( i-- ) {
5954                                                 if ( (elem = matcherOut[i]) ) {
5955                                                         temp.push( (matcherIn[i] = elem) );
5956                                                 }
5957                                         }
5958                                         postFinder( null, (matcherOut = []), temp, xml );
5959                                 }
5961                                 i = matcherOut.length;
5962                                 while ( i-- ) {
5963                                         if ( (elem = matcherOut[i]) &&
5964                                                 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5966                                                 seed[temp] = !(results[temp] = elem);
5967                                         }
5968                                 }
5969                         }
5971                 } else {
5972                         matcherOut = condense(
5973                                 matcherOut === results ?
5974                                         matcherOut.splice( preexisting, matcherOut.length ) :
5975                                         matcherOut
5976                         );
5977                         if ( postFinder ) {
5978                                 postFinder( null, results, matcherOut, xml );
5979                         } else {
5980                                 push.apply( results, matcherOut );
5981                         }
5982                 }
5983         });
5986 function matcherFromTokens( tokens ) {
5987         var checkContext, matcher, j,
5988                 len = tokens.length,
5989                 leadingRelative = Expr.relative[ tokens[0].type ],
5990                 implicitRelative = leadingRelative || Expr.relative[" "],
5991                 i = leadingRelative ? 1 : 0,
5993                 matchContext = addCombinator( function( elem ) {
5994                         return elem === checkContext;
5995                 }, implicitRelative, true ),
5996                 matchAnyContext = addCombinator( function( elem ) {
5997                         return indexOf.call( checkContext, elem ) > -1;
5998                 }, implicitRelative, true ),
5999                 matchers = [ function( elem, context, xml ) {
6000                         return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
6001                                 (checkContext = context).nodeType ?
6002                                         matchContext( elem, context, xml ) :
6003                                         matchAnyContext( elem, context, xml ) );
6004                 } ];
6006         for ( ; i < len; i++ ) {
6007                 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
6008                         matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
6009                 } else {
6010                         matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
6012                         if ( matcher[ expando ] ) {
6013                                 j = ++i;
6014                                 for ( ; j < len; j++ ) {
6015                                         if ( Expr.relative[ tokens[j].type ] ) {
6016                                                 break;
6017                                         }
6018                                 }
6019                                 return setMatcher(
6020                                         i > 1 && elementMatcher( matchers ),
6021                                         i > 1 && toSelector(
6022                                                 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
6023                                         ).replace( rtrim, "$1" ),
6024                                         matcher,
6025                                         i < j && matcherFromTokens( tokens.slice( i, j ) ),
6026                                         j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
6027                                         j < len && toSelector( tokens )
6028                                 );
6029                         }
6030                         matchers.push( matcher );
6031                 }
6032         }
6034         return elementMatcher( matchers );
6037 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
6038         var bySet = setMatchers.length > 0,
6039                 byElement = elementMatchers.length > 0,
6040                 superMatcher = function( seed, context, xml, results, outermost ) {
6041                         var elem, j, matcher,
6042                                 matchedCount = 0,
6043                                 i = "0",
6044                                 unmatched = seed && [],
6045                                 setMatched = [],
6046                                 contextBackup = outermostContext,
6047                                 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
6048                                 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
6049                                 len = elems.length;
6051                         if ( outermost ) {
6052                                 outermostContext = context !== document && context;
6053                         }
6055                         for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
6056                                 if ( byElement && elem ) {
6057                                         j = 0;
6058                                         while ( (matcher = elementMatchers[j++]) ) {
6059                                                 if ( matcher( elem, context, xml ) ) {
6060                                                         results.push( elem );
6061                                                         break;
6062                                                 }
6063                                         }
6064                                         if ( outermost ) {
6065                                                 dirruns = dirrunsUnique;
6066                                         }
6067                                 }
6069                                 if ( bySet ) {
6070                                         if ( (elem = !matcher && elem) ) {
6071                                                 matchedCount--;
6072                                         }
6074                                         if ( seed ) {
6075                                                 unmatched.push( elem );
6076                                         }
6077                                 }
6078                         }
6080                         matchedCount += i;
6081                         if ( bySet && i !== matchedCount ) {
6082                                 j = 0;
6083                                 while ( (matcher = setMatchers[j++]) ) {
6084                                         matcher( unmatched, setMatched, context, xml );
6085                                 }
6087                                 if ( seed ) {
6088                                         if ( matchedCount > 0 ) {
6089                                                 while ( i-- ) {
6090                                                         if ( !(unmatched[i] || setMatched[i]) ) {
6091                                                                 setMatched[i] = pop.call( results );
6092                                                         }
6093                                                 }
6094                                         }
6096                                         setMatched = condense( setMatched );
6097                                 }
6099                                 push.apply( results, setMatched );
6101                                 if ( outermost && !seed && setMatched.length > 0 &&
6102                                         ( matchedCount + setMatchers.length ) > 1 ) {
6104                                         Sizzle.uniqueSort( results );
6105                                 }
6106                         }
6108                         if ( outermost ) {
6109                                 dirruns = dirrunsUnique;
6110                                 outermostContext = contextBackup;
6111                         }
6113                         return unmatched;
6114                 };
6116         return bySet ?
6117                 markFunction( superMatcher ) :
6118                 superMatcher;
6121 compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
6122         var i,
6123                 setMatchers = [],
6124                 elementMatchers = [],
6125                 cached = compilerCache[ selector + " " ];
6127         if ( !cached ) {
6128                 if ( !match ) {
6129                         match = tokenize( selector );
6130                 }
6131                 i = match.length;
6132                 while ( i-- ) {
6133                         cached = matcherFromTokens( match[i] );
6134                         if ( cached[ expando ] ) {
6135                                 setMatchers.push( cached );
6136                         } else {
6137                                 elementMatchers.push( cached );
6138                         }
6139                 }
6141                 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
6143                 cached.selector = selector;
6144         }
6145         return cached;
6149  * A low-level selection function that works with Sizzle's compiled
6150  *  selector functions
6151  * @param {String|Function} selector A selector or a pre-compiled
6152  *  selector function built with Sizzle.compile
6153  * @param {Element} context
6154  * @param {Array} [results]
6155  * @param {Array} [seed] A set of elements to match against
6156  */
6157 select = Sizzle.select = function( selector, context, results, seed ) {
6158         var i, tokens, token, type, find,
6159                 compiled = typeof selector === "function" && selector,
6160                 match = !seed && tokenize( (selector = compiled.selector || selector) );
6162         results = results || [];
6164         if ( match.length === 1 ) {
6166                 tokens = match[0] = match[0].slice( 0 );
6167                 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
6168                                 support.getById && context.nodeType === 9 && documentIsHTML &&
6169                                 Expr.relative[ tokens[1].type ] ) {
6171                         context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
6172                         if ( !context ) {
6173                                 return results;
6175                         } else if ( compiled ) {
6176                                 context = context.parentNode;
6177                         }
6179                         selector = selector.slice( tokens.shift().value.length );
6180                 }
6182                 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
6183                 while ( i-- ) {
6184                         token = tokens[i];
6186                         if ( Expr.relative[ (type = token.type) ] ) {
6187                                 break;
6188                         }
6189                         if ( (find = Expr.find[ type ]) ) {
6190                                 if ( (seed = find(
6191                                         token.matches[0].replace( runescape, funescape ),
6192                                         rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
6193                                 )) ) {
6195                                         tokens.splice( i, 1 );
6196                                         selector = seed.length && toSelector( tokens );
6197                                         if ( !selector ) {
6198                                                 push.apply( results, seed );
6199                                                 return results;
6200                                         }
6202                                         break;
6203                                 }
6204                         }
6205                 }
6206         }
6208         ( compiled || compile( selector, match ) )(
6209                 seed,
6210                 context,
6211                 !documentIsHTML,
6212                 results,
6213                 rsibling.test( selector ) && testContext( context.parentNode ) || context
6214         );
6215         return results;
6219 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
6221 support.detectDuplicates = !!hasDuplicate;
6223 setDocument();
6225 support.sortDetached = assert(function( div1 ) {
6226         return div1.compareDocumentPosition( document.createElement("div") ) & 1;
6229 if ( !assert(function( div ) {
6230         div.innerHTML = "<a href='#'></a>";
6231         return div.firstChild.getAttribute("href") === "#" ;
6232 }) ) {
6233         addHandle( "type|href|height|width", function( elem, name, isXML ) {
6234                 if ( !isXML ) {
6235                         return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
6236                 }
6237         });
6240 if ( !support.attributes || !assert(function( div ) {
6241         div.innerHTML = "<input/>";
6242         div.firstChild.setAttribute( "value", "" );
6243         return div.firstChild.getAttribute( "value" ) === "";
6244 }) ) {
6245         addHandle( "value", function( elem, name, isXML ) {
6246                 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
6247                         return elem.defaultValue;
6248                 }
6249         });
6252 if ( !assert(function( div ) {
6253         return div.getAttribute("disabled") == null;
6254 }) ) {
6255         addHandle( booleans, function( elem, name, isXML ) {
6256                 var val;
6257                 if ( !isXML ) {
6258                         return elem[ name ] === true ? name.toLowerCase() :
6259                                         (val = elem.getAttributeNode( name )) && val.specified ?
6260                                         val.value :
6261                                 null;
6262                 }
6263         });
6266 if ( typeof define === "function" && define.amd ) {
6267         define(function() { return Sizzle; });
6268 } else if ( typeof module !== "undefined" && module.exports ) {
6269         module.exports = Sizzle;
6270 } else {
6271         window.Sizzle = Sizzle;
6274 })( window );
6276 ;(function() {
6277   if (typeof Sizzle !== 'undefined') {
6278     return;
6279   }
6281   if (typeof define !== 'undefined' && define.amd) {
6282     window.Sizzle = Prototype._actual_sizzle;
6283     window.define = Prototype._original_define;
6284     delete Prototype._actual_sizzle;
6285     delete Prototype._original_define;
6286   } else if (typeof module !== 'undefined' && module.exports) {
6287     window.Sizzle = module.exports;
6288     module.exports = {};
6289   }
6290 })();
6292 ;(function(engine) {
6293   var extendElements = Prototype.Selector.extendElements;
6295   function select(selector, scope) {
6296     return extendElements(engine(selector, scope || document));
6297   }
6299   function match(element, selector) {
6300     return engine.matches(selector, [element]).length == 1;
6301   }
6303   Prototype.Selector.engine = engine;
6304   Prototype.Selector.select = select;
6305   Prototype.Selector.match = match;
6306 })(Sizzle);
6308 window.Sizzle = Prototype._original_property;
6309 delete Prototype._original_property;
6311 var Form = {
6312   reset: function(form) {
6313     form = $(form);
6314     form.reset();
6315     return form;
6316   },
6318   serializeElements: function(elements, options) {
6319     if (typeof options != 'object') options = { hash: !!options };
6320     else if (Object.isUndefined(options.hash)) options.hash = true;
6321     var key, value, submitted = false, submit = options.submit, accumulator, initial;
6323     if (options.hash) {
6324       initial = {};
6325       accumulator = function(result, key, value) {
6326         if (key in result) {
6327           if (!Object.isArray(result[key])) result[key] = [result[key]];
6328           result[key] = result[key].concat(value);
6329         } else result[key] = value;
6330         return result;
6331       };
6332     } else {
6333       initial = '';
6334       accumulator = function(result, key, values) {
6335         if (!Object.isArray(values)) {values = [values];}
6336         if (!values.length) {return result;}
6337         var encodedKey = encodeURIComponent(key).gsub(/%20/, '+');
6338         return result + (result ? "&" : "") + values.map(function (value) {
6339           value = value.gsub(/(\r)?\n/, '\r\n');
6340           value = encodeURIComponent(value);
6341           value = value.gsub(/%20/, '+');
6342           return encodedKey + "=" + value;
6343         }).join("&");
6344       };
6345     }
6347     return elements.inject(initial, function(result, element) {
6348       if (!element.disabled && element.name) {
6349         key = element.name; value = $(element).getValue();
6350         if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
6351             submit !== false && (!submit || key == submit) && (submitted = true)))) {
6352           result = accumulator(result, key, value);
6353         }
6354       }
6355       return result;
6356     });
6357   }
6360 Form.Methods = {
6361   serialize: function(form, options) {
6362     return Form.serializeElements(Form.getElements(form), options);
6363   },
6366   getElements: function(form) {
6367     var elements = $(form).getElementsByTagName('*');
6368     var element, results = [], serializers = Form.Element.Serializers;
6370     for (var i = 0; element = elements[i]; i++) {
6371       if (serializers[element.tagName.toLowerCase()])
6372         results.push(Element.extend(element));
6373     }
6374     return results;
6375   },
6377   getInputs: function(form, typeName, name) {
6378     form = $(form);
6379     var inputs = form.getElementsByTagName('input');
6381     if (!typeName && !name) return $A(inputs).map(Element.extend);
6383     for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
6384       var input = inputs[i];
6385       if ((typeName && input.type != typeName) || (name && input.name != name))
6386         continue;
6387       matchingInputs.push(Element.extend(input));
6388     }
6390     return matchingInputs;
6391   },
6393   disable: function(form) {
6394     form = $(form);
6395     Form.getElements(form).invoke('disable');
6396     return form;
6397   },
6399   enable: function(form) {
6400     form = $(form);
6401     Form.getElements(form).invoke('enable');
6402     return form;
6403   },
6405   findFirstElement: function(form) {
6406     var elements = $(form).getElements().findAll(function(element) {
6407       return 'hidden' != element.type && !element.disabled;
6408     });
6409     var firstByIndex = elements.findAll(function(element) {
6410       return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
6411     }).sortBy(function(element) { return element.tabIndex }).first();
6413     return firstByIndex ? firstByIndex : elements.find(function(element) {
6414       return /^(?:input|select|textarea)$/i.test(element.tagName);
6415     });
6416   },
6418   focusFirstElement: function(form) {
6419     form = $(form);
6420     var element = form.findFirstElement();
6421     if (element) element.activate();
6422     return form;
6423   },
6425   request: function(form, options) {
6426     form = $(form), options = Object.clone(options || { });
6428     var params = options.parameters, action = form.readAttribute('action') || '';
6429     if (action.blank()) action = window.location.href;
6430     options.parameters = form.serialize(true);
6432     if (params) {
6433       if (Object.isString(params)) params = params.toQueryParams();
6434       Object.extend(options.parameters, params);
6435     }
6437     if (form.hasAttribute('method') && !options.method)
6438       options.method = form.method;
6440     return new Ajax.Request(action, options);
6441   }
6444 /*--------------------------------------------------------------------------*/
6447 Form.Element = {
6448   focus: function(element) {
6449     $(element).focus();
6450     return element;
6451   },
6453   select: function(element) {
6454     $(element).select();
6455     return element;
6456   }
6459 Form.Element.Methods = {
6461   serialize: function(element) {
6462     element = $(element);
6463     if (!element.disabled && element.name) {
6464       var value = element.getValue();
6465       if (value != undefined) {
6466         var pair = { };
6467         pair[element.name] = value;
6468         return Object.toQueryString(pair);
6469       }
6470     }
6471     return '';
6472   },
6474   getValue: function(element) {
6475     element = $(element);
6476     var method = element.tagName.toLowerCase();
6477     return Form.Element.Serializers[method](element);
6478   },
6480   setValue: function(element, value) {
6481     element = $(element);
6482     var method = element.tagName.toLowerCase();
6483     Form.Element.Serializers[method](element, value);
6484     return element;
6485   },
6487   clear: function(element) {
6488     $(element).value = '';
6489     return element;
6490   },
6492   present: function(element) {
6493     return $(element).value != '';
6494   },
6496   activate: function(element) {
6497     element = $(element);
6498     try {
6499       element.focus();
6500       if (element.select && (element.tagName.toLowerCase() != 'input' ||
6501           !(/^(?:button|reset|submit)$/i.test(element.type))))
6502         element.select();
6503     } catch (e) { }
6504     return element;
6505   },
6507   disable: function(element) {
6508     element = $(element);
6509     element.disabled = true;
6510     return element;
6511   },
6513   enable: function(element) {
6514     element = $(element);
6515     element.disabled = false;
6516     return element;
6517   }
6520 /*--------------------------------------------------------------------------*/
6522 var Field = Form.Element;
6524 var $F = Form.Element.Methods.getValue;
6526 /*--------------------------------------------------------------------------*/
6528 Form.Element.Serializers = (function() {
6529   function input(element, value) {
6530     switch (element.type.toLowerCase()) {
6531       case 'checkbox':
6532       case 'radio':
6533         return inputSelector(element, value);
6534       default:
6535         return valueSelector(element, value);
6536     }
6537   }
6539   function inputSelector(element, value) {
6540     if (Object.isUndefined(value))
6541       return element.checked ? element.value : null;
6542     else element.checked = !!value;
6543   }
6545   function valueSelector(element, value) {
6546     if (Object.isUndefined(value)) return element.value;
6547     else element.value = value;
6548   }
6550   function select(element, value) {
6551     if (Object.isUndefined(value))
6552       return (element.type === 'select-one' ? selectOne : selectMany)(element);
6554     var opt, currentValue, single = !Object.isArray(value);
6555     for (var i = 0, length = element.length; i < length; i++) {
6556       opt = element.options[i];
6557       currentValue = this.optionValue(opt);
6558       if (single) {
6559         if (currentValue == value) {
6560           opt.selected = true;
6561           return;
6562         }
6563       }
6564       else opt.selected = value.include(currentValue);
6565     }
6566   }
6568   function selectOne(element) {
6569     var index = element.selectedIndex;
6570     return index >= 0 ? optionValue(element.options[index]) : null;
6571   }
6573   function selectMany(element) {
6574     var values, length = element.length;
6575     if (!length) return null;
6577     for (var i = 0, values = []; i < length; i++) {
6578       var opt = element.options[i];
6579       if (opt.selected) values.push(optionValue(opt));
6580     }
6581     return values;
6582   }
6584   function optionValue(opt) {
6585     return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
6586   }
6588   return {
6589     input:         input,
6590     inputSelector: inputSelector,
6591     textarea:      valueSelector,
6592     select:        select,
6593     selectOne:     selectOne,
6594     selectMany:    selectMany,
6595     optionValue:   optionValue,
6596     button:        valueSelector
6597   };
6598 })();
6600 /*--------------------------------------------------------------------------*/
6603 Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
6604   initialize: function($super, element, frequency, callback) {
6605     $super(callback, frequency);
6606     this.element   = $(element);
6607     this.lastValue = this.getValue();
6608   },
6610   execute: function() {
6611     var value = this.getValue();
6612     if (Object.isString(this.lastValue) && Object.isString(value) ?
6613         this.lastValue != value : String(this.lastValue) != String(value)) {
6614       this.callback(this.element, value);
6615       this.lastValue = value;
6616     }
6617   }
6620 Form.Element.Observer = Class.create(Abstract.TimedObserver, {
6621   getValue: function() {
6622     return Form.Element.getValue(this.element);
6623   }
6626 Form.Observer = Class.create(Abstract.TimedObserver, {
6627   getValue: function() {
6628     return Form.serialize(this.element);
6629   }
6632 /*--------------------------------------------------------------------------*/
6634 Abstract.EventObserver = Class.create({
6635   initialize: function(element, callback) {
6636     this.element  = $(element);
6637     this.callback = callback;
6639     this.lastValue = this.getValue();
6640     if (this.element.tagName.toLowerCase() == 'form')
6641       this.registerFormCallbacks();
6642     else
6643       this.registerCallback(this.element);
6644   },
6646   onElementEvent: function() {
6647     var value = this.getValue();
6648     if (this.lastValue != value) {
6649       this.callback(this.element, value);
6650       this.lastValue = value;
6651     }
6652   },
6654   registerFormCallbacks: function() {
6655     Form.getElements(this.element).each(this.registerCallback, this);
6656   },
6658   registerCallback: function(element) {
6659     if (element.type) {
6660       switch (element.type.toLowerCase()) {
6661         case 'checkbox':
6662         case 'radio':
6663           Event.observe(element, 'click', this.onElementEvent.bind(this));
6664           break;
6665         default:
6666           Event.observe(element, 'change', this.onElementEvent.bind(this));
6667           break;
6668       }
6669     }
6670   }
6673 Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
6674   getValue: function() {
6675     return Form.Element.getValue(this.element);
6676   }
6679 Form.EventObserver = Class.create(Abstract.EventObserver, {
6680   getValue: function() {
6681     return Form.serialize(this.element);
6682   }
6684 (function(GLOBAL) {
6685   var DIV = document.createElement('div');
6686   var docEl = document.documentElement;
6687   var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
6688    && 'onmouseleave' in docEl;
6690   var Event = {
6691     KEY_BACKSPACE: 8,
6692     KEY_TAB:       9,
6693     KEY_RETURN:   13,
6694     KEY_ESC:      27,
6695     KEY_LEFT:     37,
6696     KEY_UP:       38,
6697     KEY_RIGHT:    39,
6698     KEY_DOWN:     40,
6699     KEY_DELETE:   46,
6700     KEY_HOME:     36,
6701     KEY_END:      35,
6702     KEY_PAGEUP:   33,
6703     KEY_PAGEDOWN: 34,
6704     KEY_INSERT:   45
6705   };
6708   var isIELegacyEvent = function(event) { return false; };
6710   if (window.attachEvent) {
6711     if (window.addEventListener) {
6712       isIELegacyEvent = function(event) {
6713         return !(event instanceof window.Event);
6714       };
6715     } else {
6716       isIELegacyEvent = function(event) { return true; };
6717     }
6718   }
6720   var _isButton;
6722   function _isButtonForDOMEvents(event, code) {
6723     return event.which ? (event.which === code + 1) : (event.button === code);
6724   }
6726   var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
6727   function _isButtonForLegacyEvents(event, code) {
6728     return event.button === legacyButtonMap[code];
6729   }
6731   function _isButtonForWebKit(event, code) {
6732     switch (code) {
6733       case 0: return event.which == 1 && !event.metaKey;
6734       case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
6735       case 2: return event.which == 3;
6736       default: return false;
6737     }
6738   }
6740   if (window.attachEvent) {
6741     if (!window.addEventListener) {
6742       _isButton = _isButtonForLegacyEvents;
6743     } else {
6744       _isButton = function(event, code) {
6745         return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
6746          _isButtonForDOMEvents(event, code);
6747       }
6748     }
6749   } else if (Prototype.Browser.WebKit) {
6750     _isButton = _isButtonForWebKit;
6751   } else {
6752     _isButton = _isButtonForDOMEvents;
6753   }
6755   function isLeftClick(event)   { return _isButton(event, 0) }
6757   function isMiddleClick(event) { return _isButton(event, 1) }
6759   function isRightClick(event)  { return _isButton(event, 2) }
6761   function element(event) {
6762     return Element.extend(_element(event));
6763   }
6765   function _element(event) {
6766     event = Event.extend(event);
6768     var node = event.target, type = event.type,
6769      currentTarget = event.currentTarget;
6771     if (currentTarget && currentTarget.tagName) {
6772       if (type === 'load' || type === 'error' ||
6773         (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
6774           && currentTarget.type === 'radio'))
6775             node = currentTarget;
6776     }
6778     return node.nodeType == Node.TEXT_NODE ? node.parentNode : node;
6779   }
6781   function findElement(event, expression) {
6782     var element = _element(event), selector = Prototype.Selector;
6783     if (!expression) return Element.extend(element);
6784     while (element) {
6785       if (Object.isElement(element) && selector.match(element, expression))
6786         return Element.extend(element);
6787       element = element.parentNode;
6788     }
6789   }
6791   function pointer(event) {
6792     return { x: pointerX(event), y: pointerY(event) };
6793   }
6795   function pointerX(event) {
6796     var docElement = document.documentElement,
6797      body = document.body || { scrollLeft: 0 };
6799     return event.pageX || (event.clientX +
6800       (docElement.scrollLeft || body.scrollLeft) -
6801       (docElement.clientLeft || 0));
6802   }
6804   function pointerY(event) {
6805     var docElement = document.documentElement,
6806      body = document.body || { scrollTop: 0 };
6808     return  event.pageY || (event.clientY +
6809        (docElement.scrollTop || body.scrollTop) -
6810        (docElement.clientTop || 0));
6811   }
6814   function stop(event) {
6815     Event.extend(event);
6816     event.preventDefault();
6817     event.stopPropagation();
6819     event.stopped = true;
6820   }
6823   Event.Methods = {
6824     isLeftClick:   isLeftClick,
6825     isMiddleClick: isMiddleClick,
6826     isRightClick:  isRightClick,
6828     element:     element,
6829     findElement: findElement,
6831     pointer:  pointer,
6832     pointerX: pointerX,
6833     pointerY: pointerY,
6835     stop: stop
6836   };
6838   var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
6839     m[name] = Event.Methods[name].methodize();
6840     return m;
6841   });
6843   if (window.attachEvent) {
6844     function _relatedTarget(event) {
6845       var element;
6846       switch (event.type) {
6847         case 'mouseover':
6848         case 'mouseenter':
6849           element = event.fromElement;
6850           break;
6851         case 'mouseout':
6852         case 'mouseleave':
6853           element = event.toElement;
6854           break;
6855         default:
6856           return null;
6857       }
6858       return Element.extend(element);
6859     }
6861     var additionalMethods = {
6862       stopPropagation: function() { this.cancelBubble = true },
6863       preventDefault:  function() { this.returnValue = false },
6864       inspect: function() { return '[object Event]' }
6865     };
6867     Event.extend = function(event, element) {
6868       if (!event) return false;
6870       if (!isIELegacyEvent(event)) return event;
6872       if (event._extendedByPrototype) return event;
6873       event._extendedByPrototype = Prototype.emptyFunction;
6875       var pointer = Event.pointer(event);
6877       Object.extend(event, {
6878         target: event.srcElement || element,
6879         relatedTarget: _relatedTarget(event),
6880         pageX:  pointer.x,
6881         pageY:  pointer.y
6882       });
6884       Object.extend(event, methods);
6885       Object.extend(event, additionalMethods);
6887       return event;
6888     };
6889   } else {
6890     Event.extend = Prototype.K;
6891   }
6893   if (window.addEventListener) {
6894     Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
6895     Object.extend(Event.prototype, methods);
6896   }
6898   var EVENT_TRANSLATIONS = {
6899     mouseenter: 'mouseover',
6900     mouseleave: 'mouseout'
6901   };
6903   function getDOMEventName(eventName) {
6904     return EVENT_TRANSLATIONS[eventName] || eventName;
6905   }
6907   if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED)
6908     getDOMEventName = Prototype.K;
6910   function getUniqueElementID(element) {
6911     if (element === window) return 0;
6913     if (typeof element._prototypeUID === 'undefined')
6914       element._prototypeUID = Element.Storage.UID++;
6915     return element._prototypeUID;
6916   }
6918   function getUniqueElementID_IE(element) {
6919     if (element === window) return 0;
6920     if (element == document) return 1;
6921     return element.uniqueID;
6922   }
6924   if ('uniqueID' in DIV)
6925     getUniqueElementID = getUniqueElementID_IE;
6927   function isCustomEvent(eventName) {
6928     return eventName.include(':');
6929   }
6931   Event._isCustomEvent = isCustomEvent;
6933   function getOrCreateRegistryFor(element, uid) {
6934     var CACHE = GLOBAL.Event.cache;
6935     if (Object.isUndefined(uid))
6936       uid = getUniqueElementID(element);
6937     if (!CACHE[uid]) CACHE[uid] = { element: element };
6938     return CACHE[uid];
6939   }
6941   function destroyRegistryForElement(element, uid) {
6942     if (Object.isUndefined(uid))
6943       uid = getUniqueElementID(element);
6944     delete GLOBAL.Event.cache[uid];
6945   }
6948   function register(element, eventName, handler) {
6949     var registry = getOrCreateRegistryFor(element);
6950     if (!registry[eventName]) registry[eventName] = [];
6951     var entries = registry[eventName];
6953     var i = entries.length;
6954     while (i--)
6955       if (entries[i].handler === handler) return null;
6957     var uid = getUniqueElementID(element);
6958     var responder = GLOBAL.Event._createResponder(uid, eventName, handler);
6959     var entry = {
6960       responder: responder,
6961       handler:   handler
6962     };
6964     entries.push(entry);
6965     return entry;
6966   }
6968   function unregister(element, eventName, handler) {
6969     var registry = getOrCreateRegistryFor(element);
6970     var entries = registry[eventName] || [];
6972     var i = entries.length, entry;
6973     while (i--) {
6974       if (entries[i].handler === handler) {
6975         entry = entries[i];
6976         break;
6977       }
6978     }
6980     if (entry) {
6981       var index = entries.indexOf(entry);
6982       entries.splice(index, 1);
6983     }
6985     if (entries.length === 0) {
6986       delete registry[eventName];
6987       if (Object.keys(registry).length === 1 && ('element' in registry))
6988         destroyRegistryForElement(element);
6989     }
6991     return entry;
6992   }
6995   function observe(element, eventName, handler) {
6996     element = $(element);
6997     var entry = register(element, eventName, handler);
6999     if (entry === null) return element;
7001     var responder = entry.responder;
7002     if (isCustomEvent(eventName))
7003       observeCustomEvent(element, eventName, responder);
7004     else
7005       observeStandardEvent(element, eventName, responder);
7007     return element;
7008   }
7010   function observeStandardEvent(element, eventName, responder) {
7011     var actualEventName = getDOMEventName(eventName);
7012     if (element.addEventListener) {
7013       element.addEventListener(actualEventName, responder, false);
7014     } else {
7015       element.attachEvent('on' + actualEventName, responder);
7016     }
7017   }
7019   function observeCustomEvent(element, eventName, responder) {
7020     if (element.addEventListener) {
7021       element.addEventListener('dataavailable', responder, false);
7022     } else {
7023       element.attachEvent('ondataavailable', responder);
7024       element.attachEvent('onlosecapture',   responder);
7025     }
7026   }
7028   function stopObserving(element, eventName, handler) {
7029     element = $(element);
7030     var handlerGiven = !Object.isUndefined(handler),
7031      eventNameGiven = !Object.isUndefined(eventName);
7033     if (!eventNameGiven && !handlerGiven) {
7034       stopObservingElement(element);
7035       return element;
7036     }
7038     if (!handlerGiven) {
7039       stopObservingEventName(element, eventName);
7040       return element;
7041     }
7043     var entry = unregister(element, eventName, handler);
7045     if (!entry) return element;
7046     removeEvent(element, eventName, entry.responder);
7047     return element;
7048   }
7050   function stopObservingStandardEvent(element, eventName, responder) {
7051     var actualEventName = getDOMEventName(eventName);
7052     if (element.removeEventListener) {
7053       element.removeEventListener(actualEventName, responder, false);
7054     } else {
7055       element.detachEvent('on' + actualEventName, responder);
7056     }
7057   }
7059   function stopObservingCustomEvent(element, eventName, responder) {
7060     if (element.removeEventListener) {
7061       element.removeEventListener('dataavailable', responder, false);
7062     } else {
7063       element.detachEvent('ondataavailable', responder);
7064       element.detachEvent('onlosecapture',   responder);
7065     }
7066   }
7070   function stopObservingElement(element) {
7071     var uid = getUniqueElementID(element), registry = GLOBAL.Event.cache[uid];
7072     if (!registry) return;
7074     destroyRegistryForElement(element, uid);
7076     var entries, i;
7077     for (var eventName in registry) {
7078       if (eventName === 'element') continue;
7080       entries = registry[eventName];
7081       i = entries.length;
7082       while (i--)
7083         removeEvent(element, eventName, entries[i].responder);
7084     }
7085   }
7087   function stopObservingEventName(element, eventName) {
7088     var registry = getOrCreateRegistryFor(element);
7089     var entries = registry[eventName];
7090     if (entries) {
7091       delete registry[eventName];
7092     }
7094     entries = entries || [];
7096     var i = entries.length;
7097     while (i--)
7098       removeEvent(element, eventName, entries[i].responder);
7100     for (var name in registry) {
7101       if (name === 'element') continue;
7102       return; // There is another registered event
7103     }
7105     destroyRegistryForElement(element);
7106   }
7109   function removeEvent(element, eventName, handler) {
7110     if (isCustomEvent(eventName))
7111       stopObservingCustomEvent(element, eventName, handler);
7112     else
7113       stopObservingStandardEvent(element, eventName, handler);
7114   }
7118   function getFireTarget(element) {
7119     if (element !== document) return element;
7120     if (document.createEvent && !element.dispatchEvent)
7121       return document.documentElement;
7122     return element;
7123   }
7125   function fire(element, eventName, memo, bubble) {
7126     element = getFireTarget($(element));
7127     if (Object.isUndefined(bubble)) bubble = true;
7128     memo = memo || {};
7130     var event = fireEvent(element, eventName, memo, bubble);
7131     return Event.extend(event);
7132   }
7134   function fireEvent_DOM(element, eventName, memo, bubble) {
7135     var event = document.createEvent('HTMLEvents');
7136     event.initEvent('dataavailable', bubble, true);
7138     event.eventName = eventName;
7139     event.memo = memo;
7141     element.dispatchEvent(event);
7142     return event;
7143   }
7145   function fireEvent_IE(element, eventName, memo, bubble) {
7146     var event = document.createEventObject();
7147     event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
7149     event.eventName = eventName;
7150     event.memo = memo;
7152     element.fireEvent(event.eventType, event);
7153     return event;
7154   }
7156   var fireEvent = document.createEvent ? fireEvent_DOM : fireEvent_IE;
7160   Event.Handler = Class.create({
7161     initialize: function(element, eventName, selector, callback) {
7162       this.element   = $(element);
7163       this.eventName = eventName;
7164       this.selector  = selector;
7165       this.callback  = callback;
7166       this.handler   = this.handleEvent.bind(this);
7167     },
7170     start: function() {
7171       Event.observe(this.element, this.eventName, this.handler);
7172       return this;
7173     },
7175     stop: function() {
7176       Event.stopObserving(this.element, this.eventName, this.handler);
7177       return this;
7178     },
7180     handleEvent: function(event) {
7181       var element = Event.findElement(event, this.selector);
7182       if (element) this.callback.call(this.element, event, element);
7183     }
7184   });
7186   function on(element, eventName, selector, callback) {
7187     element = $(element);
7188     if (Object.isFunction(selector) && Object.isUndefined(callback)) {
7189       callback = selector, selector = null;
7190     }
7192     return new Event.Handler(element, eventName, selector, callback).start();
7193   }
7195   Object.extend(Event, Event.Methods);
7197   Object.extend(Event, {
7198     fire:          fire,
7199     observe:       observe,
7200     stopObserving: stopObserving,
7201     on:            on
7202   });
7204   Element.addMethods({
7205     fire:          fire,
7207     observe:       observe,
7209     stopObserving: stopObserving,
7211     on:            on
7212   });
7214   Object.extend(document, {
7215     fire:          fire.methodize(),
7217     observe:       observe.methodize(),
7219     stopObserving: stopObserving.methodize(),
7221     on:            on.methodize(),
7223     loaded:        false
7224   });
7226   if (GLOBAL.Event) Object.extend(window.Event, Event);
7227   else GLOBAL.Event = Event;
7229   GLOBAL.Event.cache = {};
7231   function destroyCache_IE() {
7232     GLOBAL.Event.cache = null;
7233   }
7235   if (window.attachEvent)
7236     window.attachEvent('onunload', destroyCache_IE);
7238   DIV = null;
7239   docEl = null;
7240 })(this);
7242 (function(GLOBAL) {
7243   /* Code for creating leak-free event responders is based on work by
7244    John-David Dalton. */
7246   var docEl = document.documentElement;
7247   var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
7248     && 'onmouseleave' in docEl;
7250   function isSimulatedMouseEnterLeaveEvent(eventName) {
7251     return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
7252      (eventName === 'mouseenter' || eventName === 'mouseleave');
7253   }
7255   function createResponder(uid, eventName, handler) {
7256     if (Event._isCustomEvent(eventName))
7257       return createResponderForCustomEvent(uid, eventName, handler);
7258     if (isSimulatedMouseEnterLeaveEvent(eventName))
7259       return createMouseEnterLeaveResponder(uid, eventName, handler);
7261     return function(event) {
7262       if (!Event.cache) return;
7264       var element = Event.cache[uid].element;
7265       Event.extend(event, element);
7266       handler.call(element, event);
7267     };
7268   }
7270   function createResponderForCustomEvent(uid, eventName, handler) {
7271     return function(event) {
7272       var cache = Event.cache[uid];
7273       var element =  cache && cache.element;
7275       if (Object.isUndefined(event.eventName))
7276         return false;
7278       if (event.eventName !== eventName)
7279         return false;
7281       Event.extend(event, element);
7282       handler.call(element, event);
7283     };
7284   }
7286   function createMouseEnterLeaveResponder(uid, eventName, handler) {
7287     return function(event) {
7288       var element = Event.cache[uid].element;
7290       Event.extend(event, element);
7291       var parent = event.relatedTarget;
7293       while (parent && parent !== element) {
7294         try { parent = parent.parentNode; }
7295         catch(e) { parent = element; }
7296       }
7298       if (parent === element) return;
7299       handler.call(element, event);
7300     }
7301   }
7303   GLOBAL.Event._createResponder = createResponder;
7304   docEl = null;
7305 })(this);
7307 (function(GLOBAL) {
7308   /* Support for the DOMContentLoaded event is based on work by Dan Webb,
7309      Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
7311   var TIMER;
7313   function fireContentLoadedEvent() {
7314     if (document.loaded) return;
7315     if (TIMER) window.clearTimeout(TIMER);
7316     document.loaded = true;
7317     document.fire('dom:loaded');
7318   }
7320   function checkReadyState() {
7321     if (document.readyState === 'complete') {
7322       document.detachEvent('onreadystatechange', checkReadyState);
7323       fireContentLoadedEvent();
7324     }
7325   }
7327   function pollDoScroll() {
7328     try {
7329       document.documentElement.doScroll('left');
7330     } catch (e) {
7331       TIMER = pollDoScroll.defer();
7332       return;
7333     }
7335     fireContentLoadedEvent();
7336   }
7339   if (document.readyState === 'complete') {
7340     fireContentLoadedEvent();
7341     return;
7342   }
7344   if (document.addEventListener) {
7345     document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
7346   } else {
7347     document.attachEvent('onreadystatechange', checkReadyState);
7348     if (window == top) TIMER = pollDoScroll.defer();
7349   }
7351   Event.observe(window, 'load', fireContentLoadedEvent);
7352 })(this);
7355 Element.addMethods();
7356 /*------------------------------- DEPRECATED -------------------------------*/
7358 Hash.toQueryString = Object.toQueryString;
7360 var Toggle = { display: Element.toggle };
7362 Element.addMethods({
7363   childOf: Element.Methods.descendantOf
7366 var Insertion = {
7367   Before: function(element, content) {
7368     return Element.insert(element, {before:content});
7369   },
7371   Top: function(element, content) {
7372     return Element.insert(element, {top:content});
7373   },
7375   Bottom: function(element, content) {
7376     return Element.insert(element, {bottom:content});
7377   },
7379   After: function(element, content) {
7380     return Element.insert(element, {after:content});
7381   }
7384 var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
7386 var Position = {
7387   includeScrollOffsets: false,
7389   prepare: function() {
7390     this.deltaX =  window.pageXOffset
7391                 || document.documentElement.scrollLeft
7392                 || document.body.scrollLeft
7393                 || 0;
7394     this.deltaY =  window.pageYOffset
7395                 || document.documentElement.scrollTop
7396                 || document.body.scrollTop
7397                 || 0;
7398   },
7400   within: function(element, x, y) {
7401     if (this.includeScrollOffsets)
7402       return this.withinIncludingScrolloffsets(element, x, y);
7403     this.xcomp = x;
7404     this.ycomp = y;
7405     this.offset = Element.cumulativeOffset(element);
7407     return (y >= this.offset[1] &&
7408             y <  this.offset[1] + element.offsetHeight &&
7409             x >= this.offset[0] &&
7410             x <  this.offset[0] + element.offsetWidth);
7411   },
7413   withinIncludingScrolloffsets: function(element, x, y) {
7414     var offsetcache = Element.cumulativeScrollOffset(element);
7416     this.xcomp = x + offsetcache[0] - this.deltaX;
7417     this.ycomp = y + offsetcache[1] - this.deltaY;
7418     this.offset = Element.cumulativeOffset(element);
7420     return (this.ycomp >= this.offset[1] &&
7421             this.ycomp <  this.offset[1] + element.offsetHeight &&
7422             this.xcomp >= this.offset[0] &&
7423             this.xcomp <  this.offset[0] + element.offsetWidth);
7424   },
7426   overlap: function(mode, element) {
7427     if (!mode) return 0;
7428     if (mode == 'vertical')
7429       return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
7430         element.offsetHeight;
7431     if (mode == 'horizontal')
7432       return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
7433         element.offsetWidth;
7434   },
7437   cumulativeOffset: Element.Methods.cumulativeOffset,
7439   positionedOffset: Element.Methods.positionedOffset,
7441   absolutize: function(element) {
7442     Position.prepare();
7443     return Element.absolutize(element);
7444   },
7446   relativize: function(element) {
7447     Position.prepare();
7448     return Element.relativize(element);
7449   },
7451   realOffset: Element.Methods.cumulativeScrollOffset,
7453   offsetParent: Element.Methods.getOffsetParent,
7455   page: Element.Methods.viewportOffset,
7457   clone: function(source, target, options) {
7458     options = options || { };
7459     return Element.clonePosition(target, source, options);
7460   }
7463 /*--------------------------------------------------------------------------*/
7465 if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
7466   function iter(name) {
7467     return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
7468   }
7470   instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
7471   function(element, className) {
7472     className = className.toString().strip();
7473     var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
7474     return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
7475   } : function(element, className) {
7476     className = className.toString().strip();
7477     var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
7478     if (!classNames && !className) return elements;
7480     var nodes = $(element).getElementsByTagName('*');
7481     className = ' ' + className + ' ';
7483     for (var i = 0, child, cn; child = nodes[i]; i++) {
7484       if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
7485           (classNames && classNames.all(function(name) {
7486             return !name.toString().blank() && cn.include(' ' + name + ' ');
7487           }))))
7488         elements.push(Element.extend(child));
7489     }
7490     return elements;
7491   };
7493   return function(className, parentElement) {
7494     return $(parentElement || document.body).getElementsByClassName(className);
7495   };
7496 }(Element.Methods);
7498 /*--------------------------------------------------------------------------*/
7500 Element.ClassNames = Class.create();
7501 Element.ClassNames.prototype = {
7502   initialize: function(element) {
7503     this.element = $(element);
7504   },
7506   _each: function(iterator, context) {
7507     this.element.className.split(/\s+/).select(function(name) {
7508       return name.length > 0;
7509     })._each(iterator, context);
7510   },
7512   set: function(className) {
7513     this.element.className = className;
7514   },
7516   add: function(classNameToAdd) {
7517     if (this.include(classNameToAdd)) return;
7518     this.set($A(this).concat(classNameToAdd).join(' '));
7519   },
7521   remove: function(classNameToRemove) {
7522     if (!this.include(classNameToRemove)) return;
7523     this.set($A(this).without(classNameToRemove).join(' '));
7524   },
7526   toString: function() {
7527     return $A(this).join(' ');
7528   }
7531 Object.extend(Element.ClassNames.prototype, Enumerable);
7533 /*--------------------------------------------------------------------------*/
7535 (function() {
7536   window.Selector = Class.create({
7537     initialize: function(expression) {
7538       this.expression = expression.strip();
7539     },
7541     findElements: function(rootElement) {
7542       return Prototype.Selector.select(this.expression, rootElement);
7543     },
7545     match: function(element) {
7546       return Prototype.Selector.match(element, this.expression);
7547     },
7549     toString: function() {
7550       return this.expression;
7551     },
7553     inspect: function() {
7554       return "#<Selector: " + this.expression + ">";
7555     }
7556   });
7558   Object.extend(Selector, {
7559     matchElements: function(elements, expression) {
7560       var match = Prototype.Selector.match,
7561           results = [];
7563       for (var i = 0, length = elements.length; i < length; i++) {
7564         var element = elements[i];
7565         if (match(element, expression)) {
7566           results.push(Element.extend(element));
7567         }
7568       }
7569       return results;
7570     },
7572     findElement: function(elements, expression, index) {
7573       index = index || 0;
7574       var matchIndex = 0, element;
7575       for (var i = 0, length = elements.length; i < length; i++) {
7576         element = elements[i];
7577         if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
7578           return Element.extend(element);
7579         }
7580       }
7581     },
7583     findChildElements: function(element, expressions) {
7584       var selector = expressions.toArray().join(', ');
7585       return Prototype.Selector.select(selector, element || document);
7586     }
7587   });
7588 })();