PageSourceSearch

https://thejns.org/assets/meta/z48b58321/tapestry5/scriptaculous_1_9_0/prototype.js

js thejns.org collected 2026-09-24 08:38:50 UTC 199,802 bytes, 7,588 lines download raw bytes

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

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.