PageSourceSearch

https://www.mtg-forum.de/public/js/3rd_party/prototype.js

js mtg-forum.de collected 2026-09-24 09:21:40 UTC 180,829 bytes, 7,036 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.