text: /*  Prototype JavaScript framework, version 1.7.3
   *  (c) 2005-2010 Sam Stephenson
   *
   *  Prototype is freely distributable under the terms of an MIT-style license.
   *  For details, see the Prototype web site: http://www.prototypejs.org/
   *
   *--------------------------------------------------------------------------*/
  
  var Prototype = {
  
      Version: '1.7.3',
  
      Browser: (function () {
          var ua = navigator.userAgent;
          var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
          return {
              IE: !!window.attachEvent && !isOpera,
              Opera: isOpera,
              WebKit: ua.indexOf('AppleWebKit/') > -1,
              Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
              MobileSafari: /Apple.*Mobile/.test(ua)
          }
      })(),
  
      BrowserFeatures: {
          XPath: !!document.evaluate,
  
          SelectorsAPI: !!document.querySelector,
  
          ElementExtensions: (function () {
              var constructor = window.Element || window.HTMLElement;
              return !!(constructor && constructor.prototype);
          })(),
          SpecificElementExtensions: (function () {
              if (typeof window.HTMLDivElement !== 'undefined')
                  return true;
  
              var div = document.createElement('div'),
                  form = document.createElement('form'),
                  isSupported = false;
  
              if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
                  isSupported = true;
              }
  
              div = form = null;
  
              return isSupported;
          })()
      },
  
      ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script\\s*>',
      JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
  
      emptyFunction: function () {
      },
  
      K: function (x) {
          return x
      }
  };
  
  if (Prototype.Browser.MobileSafari)
      Prototype.BrowserFeatures.SpecificElementExtensions = false;
  /* Based on Alex Arnell's inheritance implementation. */
  
  var Class = (function () {
  
      var IS_DONTENUM_BUGGY = (function () {
          for (var p in {toString: 1}) {
              if (p === 'toString') return false;
          }
          return true;
      })();
  
      function subclass() {
      };
  
      function create() {
          var parent = null, properties = $A(arguments);
          if (Object.isFunction(properties[0]))
              parent = properties.shift();
  
          function klass() {
              this.initialize.apply(this, arguments);
          }
  
          Object.extend(klass, Class.Methods);
          klass.superclass = parent;
          klass.subclasses = [];
  
          if (parent) {
              subclass.prototype = parent.prototype;
              klass.prototype = new subclass;
              parent.subclasses.push(klass);
          }
  
          for (var i = 0, length = properties.length; i < length; i++)
              klass.addMethods(properties[i]);
  
          if (!klass.prototype.initialize)
              klass.prototype.initialize = Prototype.emptyFunction;
  
          klass.prototype.constructor = klass;
          return klass;
      }
  
      function addMethods(source) {
          var ancestor = this.superclass && this.superclass.prototype,
              properties = Object.keys(source);
  
          if (IS_DONTENUM_BUGGY) {
              if (source.toString != Object.prototype.toString)
                  properties.push("toString");
              if (source.valueOf != Object.prototype.valueOf)
                  properties.push("valueOf");
          }
  
          for (var i = 0, length = properties.length; i < length; i++) {
              var property = properties[i], value = source[property];
              if (ancestor && Object.isFunction(value) &&
                  value.argumentNames()[0] == "$super") {
                  var method = value;
                  value = (function (m) {
                      return function () {
                          return ancestor[m].apply(this, arguments);
                      };
                  })(property).wrap(method);
  
                  value.valueOf = (function (method) {
                      return function () {
                          return method.valueOf.call(method);
                      };
                  })(method);
  
                  value.toString = (function (method) {
                      return function () {
                          return method.toString.call(method);
                      };
                  })(method);
              }
              this.prototype[property] = value;
          }
  
          return this;
      }
  
      return {
          create: create,
          Methods: {
              addMethods: addMethods
          }
      };
  })();
  (function () {
  
      var _toString = Object.prototype.toString,
          _hasOwnProperty = Object.prototype.hasOwnProperty,
          NULL_TYPE = 'Null',
          UNDEFINED_TYPE = 'Undefined',
          BOOLEAN_TYPE = 'Boolean',
          NUMBER_TYPE = 'Number',
          STRING_TYPE = 'String',
          OBJECT_TYPE = 'Object',
          FUNCTION_CLASS = '[object Function]',
          BOOLEAN_CLASS = '[object Boolean]',
          NUMBER_CLASS = '[object Number]',
          STRING_CLASS = '[object String]',
          ARRAY_CLASS = '[object Array]',
          DATE_CLASS = '[object Date]',
          NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
              typeof JSON.stringify === 'function' &&
              JSON.stringify(0) === '0' &&
              typeof JSON.stringify(Prototype.K) === 'undefined';
  
  
      var DONT_ENUMS = ['toString', 'toLocaleString', 'valueOf',
          'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
  
      var IS_DONTENUM_BUGGY = (function () {
          for (var p in {toString: 1}) {
              if (p === 'toString') return false;
          }
          return true;
      })();
  
      function Type(o) {
          switch (o) {
              case null:
                  return NULL_TYPE;
              case (void 0):
                  return UNDEFINED_TYPE;
          }
          var type = typeof o;
          switch (type) {
              case 'boolean':
                  return BOOLEAN_TYPE;
              case 'number':
                  return NUMBER_TYPE;
              case 'string':
                  return STRING_TYPE;
          }
          return OBJECT_TYPE;
      }
  
      function extend(destination, source) {
          for (var property in source)
              destination[property] = source[property];
          return destination;
      }
  
      function inspect(object) {
          try {
              if (isUndefined(object)) return 'undefined';
              if (object === null) return 'null';
              return object.inspect ? object.inspect() : String(object);
          } catch (e) {
              if (e instanceof RangeError) return '...';
              throw e;
          }
      }
  
      function toJSON(value) {
          return Str('', {'': value}, []);
      }
  
      function Str(key, holder, stack) {
          var value = holder[key];
          if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
              value = value.toJSON(key);
          }
  
          var _class = _toString.call(value);
  
          switch (_class) {
              case NUMBER_CLASS:
              case BOOLEAN_CLASS:
              case STRING_CLASS:
                  value = value.valueOf();
          }
  
          switch (value) {
              case null:
                  return 'null';
              case true:
                  return 'true';
              case false:
                  return 'false';
          }
  
          var type = typeof value;
          switch (type) {
              case 'string':
                  return value.inspect(true);
              case 'number':
                  return isFinite(value) ? String(value) : 'null';
              case 'object':
  
                  for (var i = 0, length = stack.length; i < length; i++) {
                      if (stack[i] === value) {
                          throw new TypeError("Cyclic reference to '" + value + "' in object");
                      }
                  }
                  stack.push(value);
  
                  var partial = [];
                  if (_class === ARRAY_CLASS) {
                      for (var i = 0, length = value.length; i < length; i++) {
                          var str = Str(i, value, stack);
                          partial.push(typeof str === 'undefined' ? 'null' : str);
                      }
                      partial = '[' + partial.join(',') + ']';
                  } else {
                      var keys = Object.keys(value);
                      for (var i = 0, length = keys.length; i < length; i++) {
                          var key = keys[i], str = Str(key, value, stack);
                          if (typeof str !== "undefined") {
                              partial.push(key.inspect(true) + ':' + str);
                          }
                      }
                      partial = '{' + partial.join(',') + '}';
                  }
                  stack.pop();
                  return partial;
          }
      }
  
      function stringify(object) {
          return JSON.stringify(object);
      }
  
      function toQueryString(object) {
          return $H(object).toQueryString();
      }
  
      function toHTML(object) {
          return object && object.toHTML ? object.toHTML() : String.interpret(object);
      }
  
      function keys(object) {
          if (Type(object) !== OBJECT_TYPE) {
              throw new TypeError();
          }
          var results = [];
          for (var property in object) {
              if (_hasOwnProperty.call(object, property))
                  results.push(property);
          }
  
          if (IS_DONTENUM_BUGGY) {
              for (var i = 0; property = DONT_ENUMS[i]; i++) {
                  if (_hasOwnProperty.call(object, property))
                      results.push(property);
              }
          }
  
          return results;
      }
  
      function values(object) {
          var results = [];
          for (var property in object)
              results.push(object[property]);
          return results;
      }
  
      function clone(object) {
          return extend({}, object);
      }
  
      function isElement(object) {
          return !!(object && object.nodeType == 1);
      }
  
      function isArray(object) {
          return _toString.call(object) === ARRAY_CLASS;
      }
  
      var hasNativeIsArray = (typeof Array.isArray == 'function')
          && Array.isArray([]) && !Array.isArray({});
  
      if (hasNativeIsArray) {
          isArray = Array.isArray;
      }
  
      function isHash(object) {
          return object instanceof Hash;
      }
  
      function isFunction(object) {
          return _toString.call(object) === FUNCTION_CLASS;
      }
  
      function isString(object) {
          return _toString.call(object) === STRING_CLASS;
      }
  
      function isNumber(object) {
          return _toString.call(object) === NUMBER_CLASS;
      }
  
      function isDate(object) {
          return _toString.call(object) === DATE_CLASS;
      }
  
      function isUndefined(object) {
          return typeof object === "undefined";
      }
  
      extend(Object, {
          extend: extend,
          inspect: inspect,
          toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
          toQueryString: toQueryString,
          toHTML: toHTML,
          keys: Object.keys || keys,
          values: values,
          clone: clone,
          isElement: isElement,
          isArray: isArray,
          isHash: isHash,
          isFunction: isFunction,
          isString: isString,
          isNumber: isNumber,
          isDate: isDate,
          isUndefined: isUndefined
      });
  })();
  Object.extend(Function.prototype, (function () {
      var slice = Array.prototype.slice;
  
      function update(array, args) {
          var arrayLength = array.length, length = args.length;
          while (length--) array[arrayLength + length] = args[length];
          return array;
      }
  
      function merge(array, args) {
          array = slice.call(array, 0);
          return update(array, args);
      }
  
      function argumentNames() {
          var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
              .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
              .replace(/\s+/g, '').split(',');
          return names.length == 1 && !names[0] ? [] : names;
      }
  
  
      function bind(context) {
          if (arguments.length < 2 && Object.isUndefined(arguments[0]))
              return this;
  
          if (!Object.isFunction(this))
              throw new TypeError("The object is not callable.");
  
          var nop = function () {
          };
          var __method = this, args = slice.call(arguments, 1);
  
          var bound = function () {
              var a = merge(args, arguments);
              var c = this instanceof bound ? this : context;
              return __method.apply(c, a);
          };
  
          nop.prototype = this.prototype;
          bound.prototype = new nop();
  
          return bound;
      }
  
      function bindAsEventListener(context) {
          var __method = this, args = slice.call(arguments, 1);
          return function (event) {
              var a = update([event || window.event], args);
              return __method.apply(context, a);
          }
      }
  
      function curry() {
          if (!arguments.length) return this;
          var __method = this, args = slice.call(arguments, 0);
          return function () {
              var a = merge(args, arguments);
              return __method.apply(this, a);
          }
      }
  
      function delay(timeout) {
          var __method = this, args = slice.call(arguments, 1);
          timeout = timeout * 1000;
          return window.setTimeout(function () {
              return __method.apply(__method, args);
          }, timeout);
      }
  
      function defer() {
          var args = update([0.01], arguments);
          return this.delay.apply(this, args);
      }
  
      function wrap(wrapper) {
          var __method = this;
          return function () {
              var a = update([__method.bind(this)], arguments);
              return wrapper.apply(this, a);
          }
      }
  
      function methodize() {
          if (this._methodized) return this._methodized;
          var __method = this;
          return this._methodized = function () {
              var a = update([this], arguments);
              return __method.apply(null, a);
          };
      }
  
      var extensions = {
          argumentNames: argumentNames,
          bindAsEventListener: bindAsEventListener,
          curry: curry,
          delay: delay,
          defer: defer,
          wrap: wrap,
          methodize: methodize
      };
  
      if (!Function.prototype.bind)
          extensions.bind = bind;
  
      return extensions;
  })());
  
  
  (function (proto) {
  
  
      function toISOString() {
          return this.getUTCFullYear() + '-' +
              (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
              this.getUTCDate().toPaddedString(2) + 'T' +
              this.getUTCHours().toPaddedString(2) + ':' +
              this.getUTCMinutes().toPaddedString(2) + ':' +
              this.getUTCSeconds().toPaddedString(2) + 'Z';
      }
  
  
      function toJSON() {
          return this.toISOString();
      }
  
      if (!proto.toISOString) proto.toISOString = toISOString;
      if (!proto.toJSON) proto.toJSON = toJSON;
  
  })(Date.prototype);
  
  
  RegExp.prototype.match = RegExp.prototype.test;
  
  RegExp.escape = function (str) {
      return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
  };
  var PeriodicalExecuter = Class.create({
      initialize: function (callback, frequency) {
          this.callback = callback;
          this.frequency = frequency;
          this.currentlyExecuting = false;
  
          this.registerCallback();
      },
  
      registerCallback: function () {
          this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
      },
  
      execute: function () {
          this.callback(this);
      },
  
      stop: function () {
          if (!this.timer) return;
          clearInterval(this.timer);
          this.timer = null;
      },
  
      onTimerEvent: function () {
          if (!this.currentlyExecuting) {
              try {
                  this.currentlyExecuting = true;
                  this.execute();
                  this.currentlyExecuting = false;
              } catch (e) {
                  this.currentlyExecuting = false;
                  throw e;
              }
          }
      }
  });
  Object.extend(String, {
      interpret: function (value) {
          return value == null ? '' : String(value);
      },
      specialChar: {
          '\b': '\\b',
          '\t': '\\t',
          '\n': '\\n',
          '\f': '\\f',
          '\r': '\\r',
          '\\': '\\\\'
      }
  });
  
  Object.extend(String.prototype, (function () {
      var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
          typeof JSON.parse === 'function' &&
          JSON.parse('{"test": true}').test;
  
      function prepareReplacement(replacement) {
          if (Object.isFunction(replacement)) return replacement;
          var template = new Template(replacement);
          return function (match) {
              return template.evaluate(match)
          };
      }
  
      function isNonEmptyRegExp(regexp) {
          return regexp.source && regexp.source !== '(?:)';
      }
  
  
      function gsub(pattern, replacement) {
          var result = '', source = this, match;
          replacement = prepareReplacement(replacement);
  
          if (Object.isString(pattern))
              pattern = RegExp.escape(pattern);
  
          if (!(pattern.length || isNonEmptyRegExp(pattern))) {
              replacement = replacement('');
              return replacement + source.split('').join(replacement) + replacement;
          }
  
          while (source.length > 0) {
              match = source.match(pattern)
              if (match && match[0].length > 0) {
                  result += source.slice(0, match.index);
                  result += String.interpret(replacement(match));
                  source = source.slice(match.index + match[0].length);
              } else {
                  result += source, source = '';
              }
          }
          return result;
      }
  
      function sub(pattern, replacement, count) {
          replacement = prepareReplacement(replacement);
          count = Object.isUndefined(count) ? 1 : count;
  
          return this.gsub(pattern, function (match) {
              if (--count < 0) return match[0];
              return replacement(match);
          });
      }
  
      function scan(pattern, iterator) {
          this.gsub(pattern, iterator);
          return String(this);
      }
  
      function truncate(length, truncation) {
          length = length || 30;
          truncation = Object.isUndefined(truncation) ? '...' : truncation;
          return this.length > length ?
              this.slice(0, length - truncation.length) + truncation : String(this);
      }
  
      function strip() {
          return this.replace(/^\s+/, '').replace(/\s+$/, '');
      }
  
      function stripTags() {
          return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?(\/)?>|<\/\w+>/gi, '');
      }
  
      function stripScripts() {
          return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
      }
  
      function extractScripts() {
          var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
              matchOne = new RegExp(Prototype.ScriptFragment, 'im');
          return (this.match(matchAll) || []).map(function (scriptTag) {
              return (scriptTag.match(matchOne) || ['', ''])[1];
          });
      }
  
      function evalScripts() {
          return this.extractScripts().map(function (script) {
              return eval(script);
          });
      }
  
      function escapeHTML() {
          return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
      }
  
      function unescapeHTML() {
          return this.stripTags().replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
      }
  
  
      function toQueryParams(separator) {
          var match = this.strip().match(/([^?#]*)(#.*)?$/);
          if (!match) return {};
  
          return match[1].split(separator || '&').inject({}, function (hash, pair) {
              if ((pair = pair.split('='))[0]) {
                  var key = decodeURIComponent(pair.shift()),
                      value = pair.length > 1 ? pair.join('=') : pair[0];
  
                  if (value != undefined) {
                      value = value.gsub('+', ' ');
                      value = decodeURIComponent(value);
                  }
  
                  if (key in hash) {
                      if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
                      hash[key].push(value);
                  } else hash[key] = value;
              }
              return hash;
          });
      }
  
      function toArray() {
          return this.split('');
      }
  
      function succ() {
          return this.slice(0, this.length - 1) +
              String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
      }
  
      function times(count) {
          return count < 1 ? '' : new Array(count + 1).join(this);
      }
  
      function camelize() {
          return this.replace(/-+(.)?/g, function (match, chr) {
              return chr ? chr.toUpperCase() : '';
          });
      }
  
      function capitalize() {
          return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
      }
  
      function underscore() {
          return this.replace(/::/g, '/')
              .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
              .replace(/([a-z\d])([A-Z])/g, '$1_$2')
              .replace(/-/g, '_')
              .toLowerCase();
      }
  
      function dasherize() {
          return this.replace(/_/g, '-');
      }
  
      function inspect(useDoubleQuotes) {
          var escapedString = this.replace(/[\x00-\x1f\\]/g, function (character) {
              if (character in String.specialChar) {
                  return String.specialChar[character];
              }
              return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
          });
          if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
          return "'" + escapedString.replace(/'/g, '\\\'') + "'";
      }
  
      function unfilterJSON(filter) {
          return this.replace(filter || Prototype.JSONFilter, '$1');
      }
  
      function isJSON() {
          var str = this;
          if (str.blank()) return false;
          str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
          str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
          str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
          return (/^[\],:{}\s]*$/).test(str);
      }
  
      function evalJSON(sanitize) {
          var json = this.unfilterJSON(),
              cx = /[\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff\u0000]/g;
          if (cx.test(json)) {
              json = json.replace(cx, function (a) {
                  return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
              });
          }
          try {
              if (!sanitize || json.isJSON()) return eval('(' + json + ')');
          } catch (e) {
          }
          throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
      }
  
      function parseJSON() {
          var json = this.unfilterJSON();
          return JSON.parse(json);
      }
  
      function include(pattern) {
          return this.indexOf(pattern) > -1;
      }
  
      function startsWith(pattern, position) {
          position = Object.isNumber(position) ? position : 0;
          return this.lastIndexOf(pattern, position) === position;
      }
  
      function endsWith(pattern, position) {
          pattern = String(pattern);
          position = Object.isNumber(position) ? position : this.length;
          if (position < 0) position = 0;
          if (position > this.length) position = this.length;
          var d = position - pattern.length;
          return d >= 0 && this.indexOf(pattern, d) === d;
      }
  
      function empty() {
          return this == '';
      }
  
      function blank() {
          return /^\s*$/.test(this);
      }
  
      function interpolate(object, pattern) {
          return new Template(this, pattern).evaluate(object);
      }
  
      return {
          gsub: gsub,
          sub: sub,
          scan: scan,
          truncate: truncate,
          strip: String.prototype.trim || strip,
          stripTags: stripTags,
          stripScripts: stripScripts,
          extractScripts: extractScripts,
          evalScripts: evalScripts,
          escapeHTML: escapeHTML,
          unescapeHTML: unescapeHTML,
          toQueryParams: toQueryParams,
          parseQuery: toQueryParams,
          toArray: toArray,
          succ: succ,
          times: times,
          camelize: camelize,
          capitalize: capitalize,
          underscore: underscore,
          dasherize: dasherize,
          inspect: inspect,
          unfilterJSON: unfilterJSON,
          isJSON: isJSON,
          evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
          include: include,
          startsWith: String.prototype.startsWith || startsWith,
          endsWith: String.prototype.endsWith || endsWith,
          empty: empty,
          blank: blank,
          interpolate: interpolate
      };
  })());
  
  var Template = Class.create({
      initialize: function (template, pattern) {
          this.template = template.toString();
          this.pattern = pattern || Template.Pattern;
      },
  
      evaluate: function (object) {
          if (object && Object.isFunction(object.toTemplateReplacements))
              object = object.toTemplateReplacements();
  
          return this.template.gsub(this.pattern, function (match) {
              if (object == null) return (match[1] + '');
  
              var before = match[1] || '';
              if (before == '\\') return match[2];
  
              var ctx = object, expr = match[3],
                  pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
  
              match = pattern.exec(expr);
              if (match == null) return before;
  
              while (match != null) {
                  var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
                  ctx = ctx[comp];
                  if (null == ctx || '' == match[3]) break;
                  expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
                  match = pattern.exec(expr);
              }
  
              return before + String.interpret(ctx);
          });
      }
  });
  Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
  
  var $break = {};
  
  var Enumerable = (function () {
      function each(iterator, context) {
          try {
              this._each(iterator, context);
          } catch (e) {
              if (e != $break) throw e;
          }
          return this;
      }
  
      function eachSlice(number, iterator, context) {
          var index = -number, slices = [], array = this.toArray();
          if (number < 1) return array;
          while ((index += number) < array.length)
              slices.push(array.slice(index, index + number));
          return slices.collect(iterator, context);
      }
  
      function all(iterator, context) {
          iterator = iterator || Prototype.K;
          var result = true;
          this.each(function (value, index) {
              result = result && !!iterator.call(context, value, index, this);
              if (!result) throw $break;
          }, this);
          return result;
      }
  
      function any(iterator, context) {
          iterator = iterator || Prototype.K;
          var result = false;
          this.each(function (value, index) {
              if (result = !!iterator.call(context, value, index, this))
                  throw $break;
          }, this);
          return result;
      }
  
      function collect(iterator, context) {
          iterator = iterator || Prototype.K;
          var results = [];
          this.each(function (value, index) {
              results.push(iterator.call(context, value, index, this));
          }, this);
          return results;
      }
  
      function detect(iterator, context) {
          var result;
          this.each(function (value, index) {
              if (iterator.call(context, value, index, this)) {
                  result = value;
                  throw $break;
              }
          }, this);
          return result;
      }
  
      function findAll(iterator, context) {
          var results = [];
          this.each(function (value, index) {
              if (iterator.call(context, value, index, this))
                  results.push(value);
          }, this);
          return results;
      }
  
      function grep(filter, iterator, context) {
          iterator = iterator || Prototype.K;
          var results = [];
  
          if (Object.isString(filter))
              filter = new RegExp(RegExp.escape(filter));
  
          this.each(function (value, index) {
              if (filter.match(value))
                  results.push(iterator.call(context, value, index, this));
          }, this);
          return results;
      }
  
      function include(object) {
          if (Object.isFunction(this.indexOf) && this.indexOf(object) != -1)
              return true;
  
          var found = false;
          this.each(function (value) {
              if (value == object) {
                  found = true;
                  throw $break;
              }
          });
          return found;
      }
  
      function inGroupsOf(number, fillWith) {
          fillWith = Object.isUndefined(fillWith) ? null : fillWith;
          return this.eachSlice(number, function (slice) {
              while (slice.length < number) slice.push(fillWith);
              return slice;
          });
      }
  
      function inject(memo, iterator, context) {
          this.each(function (value, index) {
              memo = iterator.call(context, memo, value, index, this);
          }, this);
          return memo;
      }
  
      function invoke(method) {
          var args = $A(arguments).slice(1);
          return this.map(function (value) {
              return value[method].apply(value, args);
          });
      }
  
      function max(iterator, context) {
          iterator = iterator || Prototype.K;
          var result;
          this.each(function (value, index) {
              value = iterator.call(context, value, index, this);
              if (result == null || value >= result)
                  result = value;
          }, this);
          return result;
      }
  
      function min(iterator, context) {
          iterator = iterator || Prototype.K;
          var result;
          this.each(function (value, index) {
              value = iterator.call(context, value, index, this);
              if (result == null || value < result)
                  result = value;
          }, this);
          return result;
      }
  
      function partition(iterator, context) {
          iterator = iterator || Prototype.K;
          var trues = [], falses = [];
          this.each(function (value, index) {
              (iterator.call(context, value, index, this) ?
                  trues : falses).push(value);
          }, this);
          return [trues, falses];
      }
  
      function pluck(property) {
          var results = [];
          this.each(function (value) {
              results.push(value[property]);
          });
          return results;
      }
  
      function reject(iterator, context) {
          var results = [];
          this.each(function (value, index) {
              if (!iterator.call(context, value, index, this))
                  results.push(value);
          }, this);
          return results;
      }
  
      function sortBy(iterator, context) {
          return this.map(function (value, index) {
              return {
                  value: value,
                  criteria: iterator.call(context, value, index, this)
              };
          }, this).sort(function (left, right) {
              var a = left.criteria, b = right.criteria;
              return a < b ? -1 : a > b ? 1 : 0;
          }).pluck('value');
      }
  
      function toArray() {
          return this.map();
      }
  
      function zip() {
          var iterator = Prototype.K, args = $A(arguments);
          if (Object.isFunction(args.last()))
              iterator = args.pop();
  
          var collections = [this].concat(args).map($A);
          return this.map(function (value, index) {
              return iterator(collections.pluck(index));
          });
      }
  
      function size() {
          return this.toArray().length;
      }
  
      function inspect() {
          return '#<Enumerable:' + this.toArray().inspect() + '>';
      }
  
  
      return {
          each: each,
          eachSlice: eachSlice,
          all: all,
          every: all,
          any: any,
          some: any,
          collect: collect,
          map: collect,
          detect: detect,
          findAll: findAll,
          select: findAll,
          filter: findAll,
          grep: grep,
          include: include,
          member: include,
          inGroupsOf: inGroupsOf,
          inject: inject,
          invoke: invoke,
          max: max,
          min: min,
          partition: partition,
          pluck: pluck,
          reject: reject,
          sortBy: sortBy,
          toArray: toArray,
          entries: toArray,
          zip: zip,
          size: size,
          inspect: inspect,
          find: detect
      };
  })();
  
  function $A(iterable) {
      if (!iterable) return [];
      if ('toArray' in Object(iterable)) return iterable.toArray();
      var length = iterable.length || 0, results = new Array(length);
      while (length--) results[length] = iterable[length];
      return results;
  }
  
  
  function $w(string) {
      if (!Object.isString(string)) return [];
      string = string.strip();
      return string ? string.split(/\s+/) : [];
  }
  
  Array.from = $A;
  
  
  (function () {
      var arrayProto = Array.prototype,
          slice = arrayProto.slice,
          _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
  
      function each(iterator, context) {
          for (var i = 0, length = this.length >>> 0; i < length; i++) {
              if (i in this) iterator.call(context, this[i], i, this);
          }
      }
  
      if (!_each) _each = each;
  
      function clear() {
          this.length = 0;
          return this;
      }
  
      function first() {
          return this[0];
      }
  
      function last() {
          return this[this.length - 1];
      }
  
      function compact() {
          return this.select(function (value) {
              return value != null;
          });
      }
  
      function flatten() {
          return this.inject([], function (array, value) {
              if (Object.isArray(value))
                  return array.concat(value.flatten());
              array.push(value);
              return array;
          });
      }
  
      function without() {
          var values = slice.call(arguments, 0);
          return this.select(function (value) {
              return !values.include(value);
          });
      }
  
      function reverse(inline) {
          return (inline === false ? this.toArray() : this)._reverse();
      }
  
      function uniq(sorted) {
          return this.inject([], function (array, value, index) {
              if (0 == index || (sorted ? array.last() != value : !array.include(value)))
                  array.push(value);
              return array;
          });
      }
  
      function intersect(array) {
          return this.uniq().findAll(function (item) {
              return array.indexOf(item) !== -1;
          });
      }
  
  
      function clone() {
          return slice.call(this, 0);
      }
  
      function size() {
          return this.length;
      }
  
      function inspect() {
          return '[' + this.map(Object.inspect).join(', ') + ']';
      }
  
      function indexOf(item, i) {
          if (this == null) throw new TypeError();
  
          var array = Object(this), length = array.length >>> 0;
          if (length === 0) return -1;
  
          i = Number(i);
          if (isNaN(i)) {
              i = 0;
          } else if (i !== 0 && isFinite(i)) {
              i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
          }
  
          if (i > length) return -1;
  
          var k = i >= 0 ? i : Math.max(length - Math.abs(i), 0);
          for (; k < length; k++)
              if (k in array && array[k] === item) return k;
          return -1;
      }
  
  
      function lastIndexOf(item, i) {
          if (this == null) throw new TypeError();
  
          var array = Object(this), length = array.length >>> 0;
          if (length === 0) return -1;
  
          if (!Object.isUndefined(i)) {
              i = Number(i);
              if (isNaN(i)) {
                  i = 0;
              } else if (i !== 0 && isFinite(i)) {
                  i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
              }
          } else {
              i = length;
          }
  
          var k = i >= 0 ? Math.min(i, length - 1) :
              length - Math.abs(i);
  
          for (; k >= 0; k--)
              if (k in array && array[k] === item) return k;
          return -1;
      }
  
      function concat(_) {
          var array = [], items = slice.call(arguments, 0), item, n = 0;
          items.unshift(this);
          for (var i = 0, length = items.length; i < length; i++) {
              item = items[i];
              if (Object.isArray(item) && !('callee' in item)) {
                  for (var j = 0, arrayLength = item.length; j < arrayLength; j++) {
                      if (j in item) array[n] = item[j];
                      n++;
                  }
              } else {
                  array[n++] = item;
              }
          }
          array.length = n;
          return array;
      }
  
  
      function wrapNative(method) {
          return function () {
              if (arguments.length === 0) {
                  return method.call(this, Prototype.K);
              } else if (arguments[0] === undefined) {
                  var args = slice.call(arguments, 1);
                  args.unshift(Prototype.K);
                  return method.apply(this, args);
              } else {
                  return method.apply(this, arguments);
              }
          };
      }
  
  
      function map(iterator) {
          if (this == null) throw new TypeError();
          iterator = iterator || Prototype.K;
  
          var object = Object(this);
          var results = [], context = arguments[1], n = 0;
  
          for (var i = 0, length = object.length >>> 0; i < length; i++) {
              if (i in object) {
                  results[n] = iterator.call(context, object[i], i, object);
              }
              n++;
          }
          results.length = n;
          return results;
      }
  
      if (arrayProto.map) {
          map = wrapNative(Array.prototype.map);
      }
  
      function filter(iterator) {
          if (this == null || !Object.isFunction(iterator))
              throw new TypeError();
  
          var object = Object(this);
          var results = [], context = arguments[1], value;
  
          for (var i = 0, length = object.length >>> 0; i < length; i++) {
              if (i in object) {
                  value = object[i];
                  if (iterator.call(context, value, i, object)) {
                      results.push(value);
                  }
              }
          }
          return results;
      }
  
      if (arrayProto.filter) {
          filter = Array.prototype.filter;
      }
  
      function some(iterator) {
          if (this == null) throw new TypeError();
          iterator = iterator || Prototype.K;
          var context = arguments[1];
  
          var object = Object(this);
          for (var i = 0, length = object.length >>> 0; i < length; i++) {
              if (i in object && iterator.call(context, object[i], i, object)) {
                  return true;
              }
          }
  
          return false;
      }
  
      if (arrayProto.some) {
          some = wrapNative(Array.prototype.some);
      }
  
      function every(iterator) {
          if (this == null) throw new TypeError();
          iterator = iterator || Prototype.K;
          var context = arguments[1];
  
          var object = Object(this);
          for (var i = 0, length = object.length >>> 0; i < length; i++) {
              if (i in object && !iterator.call(context, object[i], i, object)) {
                  return false;
              }
          }
  
          return true;
      }
  
      if (arrayProto.every) {
          every = wrapNative(Array.prototype.every);
      }
  
  
      Object.extend(arrayProto, Enumerable);
  
      if (arrayProto.entries === Enumerable.entries) {
          delete arrayProto.entries;
      }
  
      if (!arrayProto._reverse)
          arrayProto._reverse = arrayProto.reverse;
  
      Object.extend(arrayProto, {
          _each: _each,
  
          map: map,
          collect: map,
          select: filter,
          filter: filter,
          findAll: filter,
          some: some,
          any: some,
          every: every,
          all: every,
  
          clear: clear,
          first: first,
          last: last,
          compact: compact,
          flatten: flatten,
          without: without,
          reverse: reverse,
          uniq: uniq,
          intersect: intersect,
          clone: clone,
          toArray: clone,
          size: size,
          inspect: inspect
      });
  
      var CONCAT_ARGUMENTS_BUGGY = (function () {
          return [].concat(arguments)[0][0] !== 1;
      })(1, 2);
  
      if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
  
      if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
      if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
  })();
  
  function $H(object) {
      return new Hash(object);
  };
  
  var Hash = Class.create(Enumerable, (function () {
      function initialize(object) {
          this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
      }
  
  
      function _each(iterator, context) {
          var i = 0;
          for (var key in this._object) {
              var value = this._object[key], pair = [key, value];
              pair.key = key;
              pair.value = value;
              iterator.call(context, pair, i);
              i++;
          }
      }
  
      function set(key, value) {
          return this._object[key] = value;
      }
  
      function get(key) {
          if (this._object[key] !== Object.prototype[key])
              return this._object[key];
      }
  
      function unset(key) {
          var value = this._object[key];
          delete this._object[key];
          return value;
      }
  
      function toObject() {
          return Object.clone(this._object);
      }
  
  
      function keys() {
          return this.pluck('key');
      }
  
      function values() {
          return this.pluck('value');
      }
  
      function index(value) {
          var match = this.detect(function (pair) {
              return pair.value === value;
          });
          return match && match.key;
      }
  
      function merge(object) {
          return this.clone().update(object);
      }
  
      function update(object) {
          return new Hash(object).inject(this, function (result, pair) {
              result.set(pair.key, pair.value);
              return result;
          });
      }
  
      function toQueryPair(key, value) {
          if (Object.isUndefined(value)) return key;
  
          value = String.interpret(value);
  
          value = value.gsub(/(\r)?\n/, '\r\n');
          value = encodeURIComponent(value);
          value = value.gsub(/%20/, '+');
          return key + '=' + value;
      }
  
      function toQueryString() {
          return this.inject([], function (results, pair) {
              var key = encodeURIComponent(pair.key), values = pair.value;
  
              if (values && typeof values == 'object') {
                  if (Object.isArray(values)) {
                      var queryValues = [];
                      for (var i = 0, len = values.length, value; i < len; i++) {
                          value = values[i];
                          queryValues.push(toQueryPair(key, value));
                      }
                      return results.concat(queryValues);
                  }
              } else results.push(toQueryPair(key, values));
              return results;
          }).join('&');
      }
  
      function inspect() {
          return '#<Hash:{' + this.map(function (pair) {
              return pair.map(Object.inspect).join(': ');
          }).join(', ') + '}>';
      }
  
      function clone() {
          return new Hash(this);
      }
  
      return {
          initialize: initialize,
          _each: _each,
          set: set,
          get: get,
          unset: unset,
          toObject: toObject,
          toTemplateReplacements: toObject,
          keys: keys,
          values: values,
          index: index,
          merge: merge,
          update: update,
          toQueryString: toQueryString,
          inspect: inspect,
          toJSON: toObject,
          clone: clone
      };
  })());
  
  Hash.from = $H;
  Object.extend(Number.prototype, (function () {
      function toColorPart() {
          return this.toPaddedString(2, 16);
      }
  
      function succ() {
          return this + 1;
      }
  
      function times(iterator, context) {
          $R(0, this, true).each(iterator, context);
          return this;
      }
  
      function toPaddedString(length, radix) {
          var string = this.toString(radix || 10);
          return '0'.times(length - string.length) + string;
      }
  
      function abs() {
          return Math.abs(this);
      }
  
      function round() {
          return Math.round(this);
      }
  
      function ceil() {
          return Math.ceil(this);
      }
  
      function floor() {
          return Math.floor(this);
      }
  
      return {
          toColorPart: toColorPart,
          succ: succ,
          times: times,
          toPaddedString: toPaddedString,
          abs: abs,
          round: round,
          ceil: ceil,
          floor: floor
      };
  })());
  
  function $R(start, end, exclusive) {
      return new ObjectRange(start, end, exclusive);
  }
  
  var ObjectRange = Class.create(Enumerable, (function () {
      function initialize(start, end, exclusive) {
          this.start = start;
          this.end = end;
          this.exclusive = exclusive;
      }
  
      function _each(iterator, context) {
          var value = this.start, i;
          for (i = 0; this.include(value); i++) {
              iterator.call(context, value, i);
              value = value.succ();
          }
      }
  
      function include(value) {
          if (value < this.start)
              return false;
          if (this.exclusive)
              return value < this.end;
          return value <= this.end;
      }
  
      return {
          initialize: initialize,
          _each: _each,
          include: include
      };
  })());
  
  
  var Abstract = {};
  
  
  var Try = {
      these: function () {
          var returnValue;
  
          for (var i = 0, length = arguments.length; i < length; i++) {
              var lambda = arguments[i];
              try {
                  returnValue = lambda();
                  break;
              } catch (e) {
              }
          }
  
          return returnValue;
      }
  };
  
  var Ajax = {
      getTransport: function () {
          return Try.these(
              function () {
                  return new XMLHttpRequest()
              },
              function () {
                  return new ActiveXObject('Msxml2.XMLHTTP')
              },
              function () {
                  return new ActiveXObject('Microsoft.XMLHTTP')
              }
          ) || false;
      },
  
      activeRequestCount: 0
  };
  
  Ajax.Responders = {
      responders: [],
  
      _each: function (iterator, context) {
          this.responders._each(iterator, context);
      },
  
      register: function (responder) {
          if (!this.include(responder))
              this.responders.push(responder);
      },
  
      unregister: function (responder) {
          this.responders = this.responders.without(responder);
      },
  
      dispatch: function (callback, request, transport, json) {
          this.each(function (responder) {
              if (Object.isFunction(responder[callback])) {
                  try {
                      responder[callback].apply(responder, [request, transport, json]);
                  } catch (e) {
                  }
              }
          });
      }
  };
  
  Object.extend(Ajax.Responders, Enumerable);
  
  Ajax.Responders.register({
      onCreate: function () {
          Ajax.activeRequestCount++
      },
      onComplete: function () {
          Ajax.activeRequestCount--
      }
  });
  Ajax.Base = Class.create({
      initialize: function (options) {
          this.options = {
              method: 'post',
              asynchronous: true,
              contentType: 'application/x-www-form-urlencoded',
              encoding: 'UTF-8',
              parameters: '',
              evalJSON: true,
              evalJS: true
          };
          Object.extend(this.options, options || {});
  
          this.options.method = this.options.method.toLowerCase();
  
          if (Object.isHash(this.options.parameters))
              this.options.parameters = this.options.parameters.toObject();
      }
  });
  Ajax.Request = Class.create(Ajax.Base, {
      _complete: false,
  
      initialize: function ($super, url, options) {
          $super(options);
          this.transport = Ajax.getTransport();
          this.request(url);
      },
  
      request: function (url) {
          this.url = url;
          this.method = this.options.method;
          var params = Object.isString(this.options.parameters) ?
              this.options.parameters :
              Object.toQueryString(this.options.parameters);
  
          if (!['get', 'post'].include(this.method)) {
              params += (params ? '&' : '') + "_method=" + this.method;
              this.method = 'post';
          }
  
          if (params && this.method === 'get') {
              this.url += (this.url.include('?') ? '&' : '?') + params;
          }
  
          this.parameters = params.toQueryParams();
  
          try {
              var response = new Ajax.Response(this);
              if (this.options.onCreate) this.options.onCreate(response);
              Ajax.Responders.dispatch('onCreate', this, response);
  
              this.transport.open(this.method.toUpperCase(), this.url,
                  this.options.asynchronous);
  
              if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
  
              this.transport.onreadystatechange = this.onStateChange.bind(this);
              this.setRequestHeaders();
  
              this.body = this.method == 'post' ? (this.options.postBody || params) : null;
              this.transport.send(this.body);
  
              /* Force Firefox to handle ready state 4 for synchronous requests */
              if (!this.options.asynchronous && this.transport.overrideMimeType)
                  this.onStateChange();
  
          } catch (e) {
              this.dispatchException(e);
          }
      },
  
      onStateChange: function () {
          var readyState = this.transport.readyState;
          if (readyState > 1 && !((readyState == 4) && this._complete))
              this.respondToReadyState(this.transport.readyState);
      },
  
      setRequestHeaders: function () {
          var headers = {
              'X-Requested-With': 'XMLHttpRequest',
              'X-Prototype-Version': Prototype.Version,
              'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
          };
  
          if (this.method == 'post') {
              headers['Content-type'] = this.options.contentType +
                  (this.options.encoding ? '; charset=' + this.options.encoding : '');
  
              /* Force "Connection: close" for older Mozilla browsers to work
         * around a bug where XMLHttpRequest sends an incorrect
         * Content-length header. See Mozilla Bugzilla #246651.
         */
              if (this.transport.overrideMimeType &&
                  (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0, 2005])[1] < 2005)
                  headers['Connection'] = 'close';
          }
  
          if (typeof this.options.requestHeaders == 'object') {
              var extras = this.options.requestHeaders;
  
              if (Object.isFunction(extras.push))
                  for (var i = 0, length = extras.length; i < length; i += 2)
                      headers[extras[i]] = extras[i + 1];
              else
                  $H(extras).each(function (pair) {
                      headers[pair.key] = pair.value
                  });
          }
  
          for (var name in headers)
              if (headers[name] != null)
                  this.transport.setRequestHeader(name, headers[name]);
      },
  
      success: function () {
          var status = this.getStatus();
          return !status || (status >= 200 && status < 300) || status == 304;
      },
  
      getStatus: function () {
          try {
              if (this.transport.status === 1223) return 204;
              return this.transport.status || 0;
          } catch (e) {
              return 0
          }
      },
  
      respondToReadyState: function (readyState) {
          var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
  
          if (state == 'Complete') {
              try {
                  this._complete = true;
                  (this.options['on' + response.status]
                      || this.options['on' + (this.success() ? 'Success' : 'Failure')]
                      || Prototype.emptyFunction)(response, response.headerJSON);
              } catch (e) {
                  this.dispatchException(e);
              }
  
              var contentType = response.getHeader('Content-type');
              if (this.options.evalJS == 'force'
                  || (this.options.evalJS && this.isSameOrigin() && contentType
                      && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
                  this.evalResponse();
          }
  
          try {
              (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
              Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
          } catch (e) {
              this.dispatchException(e);
          }
  
          if (state == 'Complete') {
              this.transport.onreadystatechange = Prototype.emptyFunction;
          }
      },
  
      isSameOrigin: function () {
          var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
          return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
              protocol: location.protocol,
              domain: document.domain,
              port: location.port ? ':' + location.port : ''
          }));
      },
  
      getHeader: function (name) {
          try {
              return this.transport.getResponseHeader(name) || null;
          } catch (e) {
              return null;
          }
      },
  
      evalResponse: function () {
          try {
              return eval((this.transport.responseText || '').unfilterJSON());
          } catch (e) {
              this.dispatchException(e);
          }
      },
  
      dispatchException: function (exception) {
          (this.options.onException || Prototype.emptyFunction)(this, exception);
          Ajax.Responders.dispatch('onException', this, exception);
      }
  });
  
  Ajax.Request.Events =
      ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
  
  
  Ajax.Response = Class.create({
      initialize: function (request) {
          this.request = request;
          var transport = this.transport = request.transport,
              readyState = this.readyState = transport.readyState;
  
          if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
              this.status = this.getStatus();
              this.statusText = this.getStatusText();
              this.responseText = String.interpret(transport.responseText);
              this.headerJSON = this._getHeaderJSON();
          }
  
          if (readyState == 4) {
              var xml = transport.responseXML;
              this.responseXML = Object.isUndefined(xml) ? null : xml;
              this.responseJSON = this._getResponseJSON();
          }
      },
  
      status: 0,
  
      statusText: '',
  
      getStatus: Ajax.Request.prototype.getStatus,
  
      getStatusText: function () {
          try {
              return this.transport.statusText || '';
          } catch (e) {
              return ''
          }
      },
  
      getHeader: Ajax.Request.prototype.getHeader,
  
      getAllHeaders: function () {
          try {
              return this.getAllResponseHeaders();
          } catch (e) {
              return null
          }
      },
  
      getResponseHeader: function (name) {
          return this.transport.getResponseHeader(name);
      },
  
      getAllResponseHeaders: function () {
          return this.transport.getAllResponseHeaders();
      },
  
      _getHeaderJSON: function () {
          var json = this.getHeader('X-JSON');
          if (!json) return null;
  
          try {
              json = decodeURIComponent(escape(json));
          } catch (e) {
          }
  
          try {
              return json.evalJSON(this.request.options.sanitizeJSON ||
                  !this.request.isSameOrigin());
          } catch (e) {
              this.request.dispatchException(e);
          }
      },
  
      _getResponseJSON: function () {
          var options = this.request.options;
          if (!options.evalJSON || (options.evalJSON != 'force' &&
                  !(this.getHeader('Content-type') || '').include('application/json')) ||
              this.responseText.blank())
              return null;
          try {
              return this.responseText.evalJSON(options.sanitizeJSON ||
                  !this.request.isSameOrigin());
          } catch (e) {
              this.request.dispatchException(e);
          }
      }
  });
  
  Ajax.Updater = Class.create(Ajax.Request, {
      initialize: function ($super, container, url, options) {
          this.container = {
              success: (container.success || container),
              failure: (container.failure || (container.success ? null : container))
          };
  
          options = Object.clone(options);
          var onComplete = options.onComplete;
          options.onComplete = (function (response, json) {
              this.updateContent(response.responseText);
              if (Object.isFunction(onComplete)) onComplete(response, json);
          }).bind(this);
  
          $super(url, options);
      },
  
      updateContent: function (responseText) {
          var receiver = this.container[this.success() ? 'success' : 'failure'],
              options = this.options;
  
          if (!options.evalScripts) responseText = responseText.stripScripts();
  
          if (receiver = $(receiver)) {
              if (options.insertion) {
                  if (Object.isString(options.insertion)) {
                      var insertion = {};
                      insertion[options.insertion] = responseText;
                      receiver.insert(insertion);
                  } else options.insertion(receiver, responseText);
              } else receiver.update(responseText);
          }
      }
  });
  
  Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
      initialize: function ($super, container, url, options) {
          $super(options);
          this.onComplete = this.options.onComplete;
  
          this.frequency = (this.options.frequency || 2);
          this.decay = (this.options.decay || 1);
  
          this.updater = {};
          this.container = container;
          this.url = url;
  
          this.start();
      },
  
      start: function () {
          this.options.onComplete = this.updateComplete.bind(this);
          this.onTimerEvent();
      },
  
      stop: function () {
          this.updater.options.onComplete = undefined;
          clearTimeout(this.timer);
          (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
      },
  
      updateComplete: function (response) {
          if (this.options.decay) {
              this.decay = (response.responseText == this.lastText ?
                  this.decay * this.options.decay : 1);
  
              this.lastText = response.responseText;
          }
          this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
      },
  
      onTimerEvent: function () {
          this.updater = new Ajax.Updater(this.container, this.url, this.options);
      }
  });
  
  (function (GLOBAL) {
  
      var UNDEFINED;
      var SLICE = Array.prototype.slice;
  
      var DIV = document.createElement('div');
  
  
      function $(element) {
          if (arguments.length > 1) {
              for (var i = 0, elements = [], length = arguments.length; i < length; i++)
                  elements.push($(arguments[i]));
              return elements;
          }
  
          if (Object.isString(element))
              element = document.getElementById(element);
          return Element.extend(element);
      }
  
      GLOBAL.$ = $;
  
  
      if (!GLOBAL.Node) GLOBAL.Node = {};
  
      if (!GLOBAL.Node.ELEMENT_NODE) {
          Object.extend(GLOBAL.Node, {
              ELEMENT_NODE: 1,
              ATTRIBUTE_NODE: 2,
              TEXT_NODE: 3,
              CDATA_SECTION_NODE: 4,
              ENTITY_REFERENCE_NODE: 5,
              ENTITY_NODE: 6,
              PROCESSING_INSTRUCTION_NODE: 7,
              COMMENT_NODE: 8,
              DOCUMENT_NODE: 9,
              DOCUMENT_TYPE_NODE: 10,
              DOCUMENT_FRAGMENT_NODE: 11,
              NOTATION_NODE: 12
          });
      }
  
      var ELEMENT_CACHE = {};
  
      function shouldUseCreationCache(tagName, attributes) {
          if (tagName === 'select') return false;
          if ('type' in attributes) return false;
          return true;
      }
  
      var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function () {
          try {
              var el = document.createElement('<input name="x">');
              return el.tagName.toLowerCase() === 'input' && el.name === 'x';
          } catch (err) {
              return false;
          }
      })();
  
  
      var oldElement = GLOBAL.Element;
  
      function Element(tagName, attributes) {
          attributes = attributes || {};
          tagName = tagName.toLowerCase();
  
          if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
              tagName = '<' + tagName + ' name="' + attributes.name + '">';
              delete attributes.name;
              return Element.writeAttribute(document.createElement(tagName), attributes);
          }
  
          if (!ELEMENT_CACHE[tagName])
              ELEMENT_CACHE[tagName] = Element.extend(document.createElement(tagName));
  
          var node = shouldUseCreationCache(tagName, attributes) ?
              ELEMENT_CACHE[tagName].cloneNode(false) : document.createElement(tagName);
  
          return Element.writeAttribute(node, attributes);
      }
  
      GLOBAL.Element = Element;
  
      Object.extend(GLOBAL.Element, oldElement || {});
      if (oldElement) GLOBAL.Element.prototype = oldElement.prototype;
  
      Element.Methods = {ByTag: {}, Simulated: {}};
  
      var methods = {};
  
      var INSPECT_ATTRIBUTES = {id: 'id', className: 'class'};
  
      function inspect(element) {
          element = $(element);
          var result = '<' + element.tagName.toLowerCase();
  
          var attribute, value;
          for (var property in INSPECT_ATTRIBUTES) {
              attribute = INSPECT_ATTRIBUTES[property];
              value = (element[property] || '').toString();
              if (value) result += ' ' + attribute + '=' + value.inspect(true);
          }
  
          return result + '>';
      }
  
      methods.inspect = inspect;
  
  
      function visible(element) {
          return $(element).getStyle('display') !== 'none';
      }
  
      function toggle(element, bool) {
          element = $(element);
          if (typeof bool !== 'boolean')
              bool = !Element.visible(element);
          Element[bool ? 'show' : 'hide'](element);
  
          return element;
      }
  
      function hide(element) {
          element = $(element);
          element.style.display = 'none';
          return element;
      }
  
      function show(element) {
          element = $(element);
          element.style.display = '';
          return element;
      }
  
  
      Object.extend(methods, {
          visible: visible,
          toggle: toggle,
          hide: hide,
          show: show
      });
  
  
      function remove(element) {
          element = $(element);
          element.parentNode.removeChild(element);
          return element;
      }
  
      var SELECT_ELEMENT_INNERHTML_BUGGY = (function () {
          var el = document.createElement("select"),
              isBuggy = true;
          el.innerHTML = "<option value=\"test\">test</option>";
          if (el.options && el.options[0]) {
              isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
          }
          el = null;
          return isBuggy;
      })();
  
      var TABLE_ELEMENT_INNERHTML_BUGGY = (function () {
          try {
              var el = document.createElement("table");
              if (el && el.tBodies) {
                  el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
                  var isBuggy = typeof el.tBodies[0] == "undefined";
                  el = null;
                  return isBuggy;
              }
          } catch (e) {
              return true;
          }
      })();
  
      var LINK_ELEMENT_INNERHTML_BUGGY = (function () {
          try {
              var el = document.createElement('div');
              el.innerHTML = "<link />";
              var isBuggy = (el.childNodes.length === 0);
              el = null;
              return isBuggy;
          } catch (e) {
              return true;
          }
      })();
  
      var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
          TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
  
      var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
          var s = document.createElement("script"),
              isBuggy = false;
          try {
              s.appendChild(document.createTextNode(""));
              isBuggy = !s.firstChild ||
                  s.firstChild && s.firstChild.nodeType !== 3;
          } catch (e) {
              isBuggy = true;
          }
          s = null;
          return isBuggy;
      })();
  
      function update(element, content) {
          element = $(element);
  
          var descendants = element.getElementsByTagName('*'),
              i = descendants.length;
          while (i--) purgeElement(descendants[i]);
  
          if (content && content.toElement)
              content = content.toElement();
  
          if (Object.isElement(content))
              return element.update().insert(content);
  
  
          content = Object.toHTML(content);
          var tagName = element.tagName.toUpperCase();
  
          if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
              element.text = content;
              return element;
          }
  
          if (ANY_INNERHTML_BUGGY) {
              if (tagName in INSERTION_TRANSLATIONS.tags) {
                  while (element.firstChild)
                      element.removeChild(element.firstChild);
  
                  var nodes = getContentFromAnonymousElement(tagName, content.stripScripts());
                  for (var i = 0, node; node = nodes[i]; i++)
                      element.appendChild(node);
  
              } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
                  while (element.firstChild)
                      element.removeChild(element.firstChild);
  
                  var nodes = getContentFromAnonymousElement(tagName,
                      content.stripScripts(), true);
  
                  for (var i = 0, node; node = nodes[i]; i++)
                      element.appendChild(node);
              } else {
                  element.innerHTML = content.stripScripts();
              }
          } else {
              element.innerHTML = content.stripScripts();
          }
  
          content.evalScripts.bind(content).defer();
          return element;
      }
  
      function replace(element, content) {
          element = $(element);
  
          if (content && content.toElement) {
              content = content.toElement();
          } else if (!Object.isElement(content)) {
              content = Object.toHTML(content);
              var range = element.ownerDocument.createRange();
              range.selectNode(element);
              content.evalScripts.bind(content).defer();
              content = range.createContextualFragment(content.stripScripts());
          }
  
          element.parentNode.replaceChild(content, element);
          return element;
      }
  
      var INSERTION_TRANSLATIONS = {
          before: function (element, node) {
              element.parentNode.insertBefore(node, element);
          },
          top: function (element, node) {
              element.insertBefore(node, element.firstChild);
          },
          bottom: function (element, node) {
              element.appendChild(node);
          },
          after: function (element, node) {
              element.parentNode.insertBefore(node, element.nextSibling);
          },
  
          tags: {
              TABLE: ['<table>', '</table>', 1],
              TBODY: ['<table><tbody>', '</tbody></table>', 2],
              TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
              TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
              SELECT: ['<select>', '</select>', 1]
          }
      };
  
      var tags = INSERTION_TRANSLATIONS.tags;
  
      Object.extend(tags, {
          THEAD: tags.TBODY,
          TFOOT: tags.TBODY,
          TH: tags.TD
      });
  
      function replace_IE(element, content) {
          element = $(element);
          if (content && content.toElement)
              content = content.toElement();
          if (Object.isElement(content)) {
              element.parentNode.replaceChild(content, element);
              return element;
          }
  
          content = Object.toHTML(content);
          var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
  
          if (tagName in INSERTION_TRANSLATIONS.tags) {
              var nextSibling = Element.next(element);
              var fragments = getContentFromAnonymousElement(
                  tagName, content.stripScripts());
  
              parent.removeChild(element);
  
              var iterator;
              if (nextSibling)
                  iterator = function (node) {
                      parent.insertBefore(node, nextSibling)
                  };
              else
                  iterator = function (node) {
                      parent.appendChild(node);
                  }
  
              fragments.each(iterator);
          } else {
              element.outerHTML = content.stripScripts();
          }
  
          content.evalScripts.bind(content).defer();
          return element;
      }
  
      if ('outerHTML' in document.documentElement)
          replace = replace_IE;
  
      function isContent(content) {
          if (Object.isUndefined(content) || content === null) return false;
  
          if (Object.isString(content) || Object.isNumber(content)) return true;
          if (Object.isElement(content)) return true;
          if (content.toElement || content.toHTML) return true;
  
          return false;
      }
  
      function insertContentAt(element, content, position) {
          position = position.toLowerCase();
          var method = INSERTION_TRANSLATIONS[position];
  
          if (content && content.toElement) content = content.toElement();
          if (Object.isElement(content)) {
              method(element, content);
              return element;
          }
  
          content = Object.toHTML(content);
          var tagName = ((position === 'before' || position === 'after') ?
              element.parentNode : element).tagName.toUpperCase();
  
          var childNodes = getContentFromAnonymousElement(tagName, content.stripScripts());
  
          if (position === 'top' || position === 'after') childNodes.reverse();
  
          for (var i = 0, node; node = childNodes[i]; i++)
              method(element, node);
  
          content.evalScripts.bind(content).defer();
      }
  
      function insert(element, insertions) {
          element = $(element);
  
          if (isContent(insertions))
              insertions = {bottom: insertions};
  
          for (var position in insertions)
              insertContentAt(element, insertions[position], position);
  
          return element;
      }
  
      function wrap(element, wrapper, attributes) {
          element = $(element);
  
          if (Object.isElement(wrapper)) {
              $(wrapper).writeAttribute(attributes || {});
          } else if (Object.isString(wrapper)) {
              wrapper = new Element(wrapper, attributes);
          } else {
              wrapper = new Element('div', wrapper);
          }
  
          if (element.parentNode)
              element.parentNode.replaceChild(wrapper, element);
  
          wrapper.appendChild(element);
  
          return wrapper;
      }
  
      function cleanWhitespace(element) {
          element = $(element);
          var node = element.firstChild;
  
          while (node) {
              var nextNode = node.nextSibling;
              if (node.nodeType === Node.TEXT_NODE && !/\S/.test(node.nodeValue))
                  element.removeChild(node);
              node = nextNode;
          }
          return element;
      }
  
      function empty(element) {
          return $(element).innerHTML.blank();
      }
  
      function getContentFromAnonymousElement(tagName, html, force) {
          var t = INSERTION_TRANSLATIONS.tags[tagName], div = DIV;
  
          var workaround = !!t;
          if (!workaround && force) {
              workaround = true;
              t = ['', '', 0];
          }
  
          if (workaround) {
              div.innerHTML = '&#160;' + t[0] + html + t[1];
              div.removeChild(div.firstChild);
              for (var i = t[2]; i--;)
                  div = div.firstChild;
          } else {
              div.innerHTML = html;
          }
  
          return $A(div.childNodes);
      }
  
      function clone(element, deep) {
          if (!(element = $(element))) return;
          var clone = element.cloneNode(deep);
          if (!HAS_UNIQUE_ID_PROPERTY) {
              clone._prototypeUID = UNDEFINED;
              if (deep) {
                  var descendants = Element.select(clone, '*'),
                      i = descendants.length;
                  while (i--)
                      descendants[i]._prototypeUID = UNDEFINED;
              }
          }
          return Element.extend(clone);
      }
  
      function purgeElement(element) {
          var uid = getUniqueElementID(element);
          if (uid) {
              Element.stopObserving(element);
              if (!HAS_UNIQUE_ID_PROPERTY)
                  element._prototypeUID = UNDEFINED;
              delete Element.Storage[uid];
          }
      }
  
      function purgeCollection(elements) {
          var i = elements.length;
          while (i--)
              purgeElement(elements[i]);
      }
  
      function purgeCollection_IE(elements) {
          var i = elements.length, element, uid;
          while (i--) {
              element = elements[i];
              uid = getUniqueElementID(element);
              delete Element.Storage[uid];
              delete Event.cache[uid];
          }
      }
  
      if (HAS_UNIQUE_ID_PROPERTY) {
          purgeCollection = purgeCollection_IE;
      }
  
  
      function purge(element) {
          if (!(element = $(element))) return;
          purgeElement(element);
  
          var descendants = element.getElementsByTagName('*'),
              i = descendants.length;
  
          while (i--) purgeElement(descendants[i]);
  
          return null;
      }
  
      Object.extend(methods, {
          remove: remove,
          update: update,
          replace: replace,
          insert: insert,
          wrap: wrap,
          cleanWhitespace: cleanWhitespace,
          empty: empty,
          clone: clone,
          purge: purge
      });
  
  
      function recursivelyCollect(element, property, maximumLength) {
          element = $(element);
          maximumLength = maximumLength || -1;
          var elements = [];
  
          while (element = element[property]) {
              if (element.nodeType === Node.ELEMENT_NODE)
                  elements.push(Element.extend(element));
  
              if (elements.length === maximumLength) break;
          }
  
          return elements;
      }
  
  
      function ancestors(element) {
          return recursivelyCollect(element, 'parentNode');
      }
  
      function descendants(element) {
          return Element.select(element, '*');
      }
  
      function firstDescendant(element) {
          element = $(element).firstChild;
          while (element && element.nodeType !== Node.ELEMENT_NODE)
              element = element.nextSibling;
  
          return $(element);
      }
  
      function immediateDescendants(element) {
          var results = [], child = $(element).firstChild;
  
          while (child) {
              if (child.nodeType === Node.ELEMENT_NODE)
                  results.push(Element.extend(child));
  
              child = child.nextSibling;
          }
  
          return results;
      }
  
      function previousSiblings(element) {
          return recursivelyCollect(element, 'previousSibling');
      }
  
      function nextSiblings(element) {
          return recursivelyCollect(element, 'nextSibling');
      }
  
      function siblings(element) {
          element = $(element);
          var previous = previousSiblings(element),
              next = nextSiblings(element);
          return previous.reverse().concat(next);
      }
  
      function match(element, selector) {
          element = $(element);
  
          if (Object.isString(selector))
              return Prototype.Selector.match(element, selector);
  
          return selector.match(element);
      }
  
  
      function _recursivelyFind(element, property, expression, index) {
          element = $(element), expression = expression || 0, index = index || 0;
          if (Object.isNumber(expression)) {
              index = expression, expression = null;
          }
  
          while (element = element[property]) {
              if (element.nodeType !== 1) continue;
              if (expression && !Prototype.Selector.match(element, expression))
                  continue;
              if (--index >= 0) continue;
  
              return Element.extend(element);
          }
      }
  
  
      function up(element, expression, index) {
          element = $(element);
  
          if (arguments.length === 1) return $(element.parentNode);
          return _recursivelyFind(element, 'parentNode', expression, index);
      }
  
      function down(element, expression, index) {
          if (arguments.length === 1) return firstDescendant(element);
          element = $(element), expression = expression || 0, index = index || 0;
  
          if (Object.isNumber(expression))
              index = expression, expression = '*';
  
          var node = Prototype.Selector.select(expression, element)[index];
          return Element.extend(node);
      }
  
      function previous(element, expression, index) {
          return _recursivelyFind(element, 'previousSibling', expression, index);
      }
  
      function next(element, expression, index) {
          return _recursivelyFind(element, 'nextSibling', expression, index);
      }
  
      function select(element) {
          element = $(element);
          var expressions = SLICE.call(arguments, 1).join(', ');
          return Prototype.Selector.select(expressions, element);
      }
  
      function adjacent(element) {
          element = $(element);
          var expressions = SLICE.call(arguments, 1).join(', ');
          var siblings = Element.siblings(element), results = [];
          for (var i = 0, sibling; sibling = siblings[i]; i++) {
              if (Prototype.Selector.match(sibling, expressions))
                  results.push(sibling);
          }
  
          return results;
      }
  
      function descendantOf_DOM(element, ancestor) {
          element = $(element), ancestor = $(ancestor);
          if (!element || !ancestor) return false;
          while (element = element.parentNode)
              if (element === ancestor) return true;
          return false;
      }
  
      function descendantOf_contains(element, ancestor) {
          element = $(element), ancestor = $(ancestor);
          if (!element || !ancestor) return false;
          if (!ancestor.contains) return descendantOf_DOM(element, ancestor);
          return ancestor.contains(element) && ancestor !== element;
      }
  
      function descendantOf_compareDocumentPosition(element, ancestor) {
          element = $(element), ancestor = $(ancestor);
          if (!element || !ancestor) return false;
          return (element.compareDocumentPosition(ancestor) & 8) === 8;
      }
  
      var descendantOf;
      if (DIV.compareDocumentPosition) {
          descendantOf = descendantOf_compareDocumentPosition;
      } else if (DIV.contains) {
          descendantOf = descendantOf_contains;
      } else {
          descendantOf = descendantOf_DOM;
      }
  
  
      Object.extend(methods, {
          recursivelyCollect: recursivelyCollect,
          ancestors: ancestors,
          descendants: descendants,
          firstDescendant: firstDescendant,
          immediateDescendants: immediateDescendants,
          previousSiblings: previousSiblings,
          nextSiblings: nextSiblings,
          siblings: siblings,
          match: match,
          up: up,
          down: down,
          previous: previous,
          next: next,
          select: select,
          adjacent: adjacent,
          descendantOf: descendantOf,
  
          getElementsBySelector: select,
  
          childElements: immediateDescendants
      });
  
  
      var idCounter = 1;
  
      function identify(element) {
          element = $(element);
          var id = Element.readAttribute(element, 'id');
          if (id) return id;
  
          do {
              id = 'anonymous_element_' + idCounter++
          } while ($(id));
  
          Element.writeAttribute(element, 'id', id);
          return id;
      }
  
  
      function readAttribute(element, name) {
          return $(element).getAttribute(name);
      }
  
      function readAttribute_IE(element, name) {
          element = $(element);
  
          var table = ATTRIBUTE_TRANSLATIONS.read;
          if (table.values[name])
              return table.values[name](element, name);
  
          if (table.names[name]) name = table.names[name];
  
          if (name.include(':')) {
              if (!element.attributes || !element.attributes[name]) return null;
              return element.attributes[name].value;
          }
  
          return element.getAttribute(name);
      }
  
      function readAttribute_Opera(element, name) {
          if (name === 'title') return element.title;
          return element.getAttribute(name);
      }
  
      var PROBLEMATIC_ATTRIBUTE_READING = (function () {
          DIV.setAttribute('onclick', []);
          var value = DIV.getAttribute('onclick');
          var isFunction = Object.isArray(value);
          DIV.removeAttribute('onclick');
          return isFunction;
      })();
  
      if (PROBLEMATIC_ATTRIBUTE_READING) {
          readAttribute = readAttribute_IE;
      } else if (Prototype.Browser.Opera) {
          readAttribute = readAttribute_Opera;
      }
  
  
      function writeAttribute(element, name, value) {
          element = $(element);
          var attributes = {}, table = ATTRIBUTE_TRANSLATIONS.write;
  
          if (typeof name === 'object') {
              attributes = name;
          } else {
              attributes[name] = Object.isUndefined(value) ? true : value;
          }
  
          for (var attr in attributes) {
              name = table.names[attr] || attr;
              value = attributes[attr];
              if (table.values[attr]) {
                  value = table.values[attr](element, value);
                  if (Object.isUndefined(value)) continue;
              }
              if (value === false || value === null)
                  element.removeAttribute(name);
              else if (value === true)
                  element.setAttribute(name, name);
              else element.setAttribute(name, value);
          }
  
          return element;
      }
  
      var PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES = (function () {
          if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) {
              return false;
          }
          var checkbox = document.createElement('<input type="checkbox">');
          checkbox.checked = true;
          var node = checkbox.getAttributeNode('checked');
          return !node || !node.specified;
      })();
  
      function hasAttribute(element, attribute) {
          attribute = ATTRIBUTE_TRANSLATIONS.has[attribute] || attribute;
          var node = $(element).getAttributeNode(attribute);
          return !!(node && node.specified);
      }
  
      function hasAttribute_IE(element, attribute) {
          if (attribute === 'checked') {
              return element.checked;
          }
          return hasAttribute(element, attribute);
      }
  
      GLOBAL.Element.Methods.Simulated.hasAttribute =
          PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES ?
              hasAttribute_IE : hasAttribute;
  
      function classNames(element) {
          return new Element.ClassNames(element);
      }
  
      var regExpCache = {};
  
      function getRegExpForClassName(className) {
          if (regExpCache[className]) return regExpCache[className];
  
          var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
          regExpCache[className] = re;
          return re;
      }
  
      function hasClassName(element, className) {
          if (!(element = $(element))) return;
  
          var elementClassName = element.className;
  
          if (elementClassName.length === 0) return false;
          if (elementClassName === className) return true;
  
          return getRegExpForClassName(className).test(elementClassName);
      }
  
      function addClassName(element, className) {
          if (!(element = $(element))) return;
  
          if (!hasClassName(element, className))
              element.className += (element.className ? ' ' : '') + className;
  
          return element;
      }
  
      function removeClassName(element, className) {
          if (!(element = $(element))) return;
  
          element.className = element.className.replace(
              getRegExpForClassName(className), ' ').strip();
  
          return element;
      }
  
      function toggleClassName(element, className, bool) {
          if (!(element = $(element))) return;
  
          if (Object.isUndefined(bool))
              bool = !hasClassName(element, className);
  
          var method = Element[bool ? 'addClassName' : 'removeClassName'];
          return method(element, className);
      }
  
      var ATTRIBUTE_TRANSLATIONS = {};
  
      var classProp = 'className', forProp = 'for';
  
      DIV.setAttribute(classProp, 'x');
      if (DIV.className !== 'x') {
          DIV.setAttribute('class', 'x');
          if (DIV.className === 'x')
              classProp = 'class';
      }
  
      var LABEL = document.createElement('label');
      LABEL.setAttribute(forProp, 'x');
      if (LABEL.htmlFor !== 'x') {
          LABEL.setAttribute('htmlFor', 'x');
          if (LABEL.htmlFor === 'x')
              forProp = 'htmlFor';
      }
      LABEL = null;
  
      function _getAttr(element, attribute) {
          return element.getAttribute(attribute);
      }
  
      function _getAttr2(element, attribute) {
          return element.getAttribute(attribute, 2);
      }
  
      function _getAttrNode(element, attribute) {
          var node = element.getAttributeNode(attribute);
          return node ? node.value : '';
      }
  
      function _getFlag(element, attribute) {
          return $(element).hasAttribute(attribute) ? attribute : null;
      }
  
      DIV.onclick = Prototype.emptyFunction;
      var onclickValue = DIV.getAttribute('onclick');
  
      var _getEv;
  
      if (String(onclickValue).indexOf('{') > -1) {
          _getEv = function (element, attribute) {
              var value = element.getAttribute(attribute);
              if (!value) return null;
              value = value.toString();
              value = value.split('{')[1];
              value = value.split('}')[0];
              return value.strip();
          };
      } else if (onclickValue === '') {
          _getEv = function (element, attribute) {
              var value = element.getAttribute(attribute);
              if (!value) return null;
              return value.strip();
          };
      }
  
      ATTRIBUTE_TRANSLATIONS.read = {
          names: {
              'class': classProp,
              'className': classProp,
              'for': forProp,
              'htmlFor': forProp
          },
  
          values: {
              style: function (element) {
                  return element.style.cssText.toLowerCase();
              },
              title: function (element) {
                  return element.title;
              }
          }
      };
  
      ATTRIBUTE_TRANSLATIONS.write = {
          names: {
              className: 'class',
              htmlFor: 'for',
              cellpadding: 'cellPadding',
              cellspacing: 'cellSpacing'
          },
  
          values: {
              checked: function (element, value) {
                  value = !!value;
                  element.checked = value;
                  return value ? 'checked' : null;
              },
  
              style: function (element, value) {
                  element.style.cssText = value ? value : '';
              }
          }
      };
  
      ATTRIBUTE_TRANSLATIONS.has = {names: {}};
  
      Object.extend(ATTRIBUTE_TRANSLATIONS.write.names,
          ATTRIBUTE_TRANSLATIONS.read.names);
  
      var CAMEL_CASED_ATTRIBUTE_NAMES = $w('colSpan rowSpan vAlign dateTime ' +
          'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
  
      for (var i = 0, attr; attr = CAMEL_CASED_ATTRIBUTE_NAMES[i]; i++) {
          ATTRIBUTE_TRANSLATIONS.write.names[attr.toLowerCase()] = attr;
          ATTRIBUTE_TRANSLATIONS.has.names[attr.toLowerCase()] = attr;
      }
  
      Object.extend(ATTRIBUTE_TRANSLATIONS.read.values, {
          href: _getAttr2,
          src: _getAttr2,
          type: _getAttr,
          action: _getAttrNode,
          disabled: _getFlag,
          checked: _getFlag,
          readonly: _getFlag,
          multiple: _getFlag,
          onload: _getEv,
          onunload: _getEv,
          onclick: _getEv,
          ondblclick: _getEv,
          onmousedown: _getEv,
          onmouseup: _getEv,
          onmouseover: _getEv,
          onmousemove: _getEv,
          onmouseout: _getEv,
          onfocus: _getEv,
          onblur: _getEv,
          onkeypress: _getEv,
          onkeydown: _getEv,
          onkeyup: _getEv,
          onsubmit: _getEv,
          onreset: _getEv,
          onselect: _getEv,
          onchange: _getEv
      });
  
  
      Object.extend(methods, {
          identify: identify,
          readAttribute: readAttribute,
          writeAttribute: writeAttribute,
          classNames: classNames,
          hasClassName: hasClassName,
          addClassName: addClassName,
          removeClassName: removeClassName,
          toggleClassName: toggleClassName
      });
  
  
      function normalizeStyleName(style) {
          if (style === 'float' || style === 'styleFloat')
              return 'cssFloat';
          return style.camelize();
      }
  
      function normalizeStyleName_IE(style) {
          if (style === 'float' || style === 'cssFloat')
              return 'styleFloat';
          return style.camelize();
      }
  
      function setStyle(element, styles) {
          element = $(element);
          var elementStyle = element.style, match;
  
          if (Object.isString(styles)) {
              elementStyle.cssText += ';' + styles;
              if (styles.include('opacity')) {
                  var opacity = styles.match(/opacity:\s*(\d?\.?\d*)/)[1];
                  Element.setOpacity(element, opacity);
              }
              return element;
          }
  
          for (var property in styles) {
              if (property === 'opacity') {
                  Element.setOpacity(element, styles[property]);
              } else {
                  var value = styles[property];
                  if (property === 'float' || property === 'cssFloat') {
                      property = Object.isUndefined(elementStyle.styleFloat) ?
                          'cssFloat' : 'styleFloat';
                  }
                  elementStyle[property] = value;
              }
          }
  
          return element;
      }
  
  
      function getStyle(element, style) {
          element = $(element);
          style = normalizeStyleName(style);
  
          var value = element.style[style];
          if (!value || value === 'auto') {
              var css = document.defaultView.getComputedStyle(element, null);
              value = css ? css[style] : null;
          }
  
          if (style === 'opacity') return value ? parseFloat(value) : 1.0;
          return value === 'auto' ? null : value;
      }
  
      function getStyle_Opera(element, style) {
          switch (style) {
              case 'height':
              case 'width':
                  if (!Element.visible(element)) return null;
  
                  var dim = parseInt(getStyle(element, style), 10);
  
                  if (dim !== element['offset' + style.capitalize()])
                      return dim + 'px';
  
                  return Element.measure(element, style);
  
              default:
                  return getStyle(element, style);
          }
      }
  
      function getStyle_IE(element, style) {
          element = $(element);
          style = normalizeStyleName_IE(style);
  
          var value = element.style[style];
          if (!value && element.currentStyle) {
              value = element.currentStyle[style];
          }
  
          if (style === 'opacity') {
              if (!STANDARD_CSS_OPACITY_SUPPORTED)
                  return getOpacity_IE(element);
              else return value ? parseFloat(value) : 1.0;
          }
  
          if (value === 'auto') {
              if ((style === 'width' || style === 'height') && Element.visible(element))
                  return Element.measure(element, style) + 'px';
              return null;
          }
  
          return value;
      }
  
      function stripAlphaFromFilter_IE(filter) {
          return (filter || '').replace(/alpha\([^\)]*\)/gi, '');
      }
  
      function hasLayout_IE(element) {
          if (!element.currentStyle || !element.currentStyle.hasLayout)
              element.style.zoom = 1;
          return element;
      }
  
      var STANDARD_CSS_OPACITY_SUPPORTED = (function () {
          DIV.style.cssText = "opacity:.55";
          return /^0.55/.test(DIV.style.opacity);
      })();
  
      function setOpacity(element, value) {
          element = $(element);
          if (value == 1 || value === '') value = '';
          else if (value < 0.00001) value = 0;
          element.style.opacity = value;
          return element;
      }
  
      function setOpacity_IE(element, value) {
          if (STANDARD_CSS_OPACITY_SUPPORTED)
              return setOpacity(element, value);
  
          element = hasLayout_IE($(element));
          var filter = Element.getStyle(element, 'filter'),
              style = element.style;
  
          if (value == 1 || value === '') {
              filter = stripAlphaFromFilter_IE(filter);
              if (filter) style.filter = filter;
              else style.removeAttribute('filter');
              return element;
          }
  
          if (value < 0.00001) value = 0;
  
          style.filter = stripAlphaFromFilter_IE(filter) +
              ' alpha(opacity=' + (value * 100) + ')';
  
          return element;
      }
  
  
      function getOpacity(element) {
          return Element.getStyle(element, 'opacity');
      }
  
      function getOpacity_IE(element) {
          if (STANDARD_CSS_OPACITY_SUPPORTED)
              return getOpacity(element);
  
          var filter = Element.getStyle(element, 'filter');
          if (filter.length === 0) return 1.0;
          var match = (filter || '').match(/alpha\(opacity=(.*)\)/i);
          if (match && match[1]) return parseFloat(match[1]) / 100;
          return 1.0;
      }
  
  
      Object.extend(methods, {
          setStyle: setStyle,
          getStyle: getStyle,
          setOpacity: setOpacity,
          getOpacity: getOpacity
      });
  
      if ('styleFloat' in DIV.style) {
          methods.getStyle = getStyle_IE;
          methods.setOpacity = setOpacity_IE;
          methods.getOpacity = getOpacity_IE;
      }
  
      var UID = 0;
  
      GLOBAL.Element.Storage = {UID: 1};
  
      function getUniqueElementID(element) {
          if (element === window) return 0;
  
          if (typeof element._prototypeUID === 'undefined')
              element._prototypeUID = Element.Storage.UID++;
          return element._prototypeUID;
      }
  
      function getUniqueElementID_IE(element) {
          if (element === window) return 0;
          if (element == document) return 1;
          return element.uniqueID;
      }
  
      var HAS_UNIQUE_ID_PROPERTY = ('uniqueID' in DIV);
      if (HAS_UNIQUE_ID_PROPERTY)
          getUniqueElementID = getUniqueElementID_IE;
  
      function getStorage(element) {
          if (!(element = $(element))) return;
  
          var uid = getUniqueElementID(element);
  
          if (!Element.Storage[uid])
              Element.Storage[uid] = $H();
  
          return Element.Storage[uid];
      }
  
      function store(element, key, value) {
          if (!(element = $(element))) return;
          var storage = getStorage(element);
          if (arguments.length === 2) {
              storage.update(key);
          } else {
              storage.set(key, value);
          }
          return element;
      }
  
      function retrieve(element, key, defaultValue) {
          if (!(element = $(element))) return;
          var storage = getStorage(element), value = storage.get(key);
  
          if (Object.isUndefined(value)) {
              storage.set(key, defaultValue);
              value = defaultValue;
          }
  
          return value;
      }
  
  
      Object.extend(methods, {
          getStorage: getStorage,
          store: store,
          retrieve: retrieve
      });
  
  
      var Methods = {}, ByTag = Element.Methods.ByTag,
          F = Prototype.BrowserFeatures;
  
      if (!F.ElementExtensions && ('__proto__' in DIV)) {
          GLOBAL.HTMLElement = {};
          GLOBAL.HTMLElement.prototype = DIV['__proto__'];
          F.ElementExtensions = true;
      }
  
      function checkElementPrototypeDeficiency(tagName) {
          if (typeof window.Element === 'undefined') return false;
          if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) return false;
          var proto = window.Element.prototype;
          if (proto) {
              var id = '_' + (Math.random() + '').slice(2),
                  el = document.createElement(tagName);
              proto[id] = 'x';
              var isBuggy = (el[id] !== 'x');
              delete proto[id];
              el = null;
              return isBuggy;
          }
  
          return false;
      }
  
      var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY =
          checkElementPrototypeDeficiency('object');
  
      function extendElementWith(element, methods) {
          for (var property in methods) {
              var value = methods[property];
              if (Object.isFunction(value) && !(property in element))
                  element[property] = value.methodize();
          }
      }
  
      var EXTENDED = {};
  
      function elementIsExtended(element) {
          var uid = getUniqueElementID(element);
          return (uid in EXTENDED);
      }
  
      function extend(element) {
          if (!element || elementIsExtended(element)) return element;
          if (element.nodeType !== Node.ELEMENT_NODE || element == window)
              return element;
  
          var methods = Object.clone(Methods),
              tagName = element.tagName.toUpperCase();
  
          if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
  
          extendElementWith(element, methods);
          EXTENDED[getUniqueElementID(element)] = true;
          return element;
      }
  
      function extend_IE8(element) {
          if (!element || elementIsExtended(element)) return element;
  
          var t = element.tagName;
          if (t && (/^(?:object|applet|embed)$/i.test(t))) {
              extendElementWith(element, Element.Methods);
              extendElementWith(element, Element.Methods.Simulated);
              extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
          }
  
          return element;
      }
  
      if (F.SpecificElementExtensions) {
          extend = HTMLOBJECTELEMENT_PROTOTYPE_BUGGY ? extend_IE8 : Prototype.K;
      }
  
      function addMethodsToTagName(tagName, methods) {
          tagName = tagName.toUpperCase();
          if (!ByTag[tagName]) ByTag[tagName] = {};
          Object.extend(ByTag[tagName], methods);
      }
  
      function mergeMethods(destination, methods, onlyIfAbsent) {
          if (Object.isUndefined(onlyIfAbsent)) onlyIfAbsent = false;
          for (var property in methods) {
              var value = methods[property];
              if (!Object.isFunction(value)) continue;
              if (!onlyIfAbsent || !(property in destination))
                  destination[property] = value.methodize();
          }
      }
  
      function findDOMClass(tagName) {
          var klass;
          var trans = {
              "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
              "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
              "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
              "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
              "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
                  "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
                  "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
                  "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
                  "FrameSet", "IFRAME": "IFrame"
          };
          if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
          if (window[klass]) return window[klass];
          klass = 'HTML' + tagName + 'Element';
          if (window[klass]) return window[klass];
          klass = 'HTML' + tagName.capitalize() + 'Element';
          if (window[klass]) return window[klass];
  
          var element = document.createElement(tagName),
              proto = element['__proto__'] || element.constructor.prototype;
  
          element = null;
          return proto;
      }
  
      function addMethods(methods) {
          if (arguments.length === 0) addFormMethods();
  
          if (arguments.length === 2) {
              var tagName = methods;
              methods = arguments[1];
          }
  
          if (!tagName) {
              Object.extend(Element.Methods, methods || {});
          } else {
              if (Object.isArray(tagName)) {
                  for (var i = 0, tag; tag = tagName[i]; i++)
                      addMethodsToTagName(tag, methods);
              } else {
                  addMethodsToTagName(tagName, methods);
              }
          }
  
          var ELEMENT_PROTOTYPE = window.HTMLElement ? HTMLElement.prototype :
              Element.prototype;
  
          if (F.ElementExtensions) {
              mergeMethods(ELEMENT_PROTOTYPE, Element.Methods);
              mergeMethods(ELEMENT_PROTOTYPE, Element.Methods.Simulated, true);
          }
  
          if (F.SpecificElementExtensions) {
              for (var tag in Element.Methods.ByTag) {
                  var klass = findDOMClass(tag);
                  if (Object.isUndefined(klass)) continue;
                  mergeMethods(klass.prototype, ByTag[tag]);
              }
          }
  
          Object.extend(Element, Element.Methods);
          Object.extend(Element, Element.Methods.Simulated);
          delete Element.ByTag;
          delete Element.Simulated;
  
          Element.extend.refresh();
  
          ELEMENT_CACHE = {};
      }
  
      Object.extend(GLOBAL.Element, {
          extend: extend,
          addMethods: addMethods
      });
  
      if (extend === Prototype.K) {
          GLOBAL.Element.extend.refresh = Prototype.emptyFunction;
      } else {
          GLOBAL.Element.extend.refresh = function () {
              if (Prototype.BrowserFeatures.ElementExtensions) return;
              Object.extend(Methods, Element.Methods);
              Object.extend(Methods, Element.Methods.Simulated);
  
              EXTENDED = {};
          };
      }
  
      function addFormMethods() {
          Object.extend(Form, Form.Methods);
          Object.extend(Form.Element, Form.Element.Methods);
          Object.extend(Element.Methods.ByTag, {
              "FORM": Object.clone(Form.Methods),
              "INPUT": Object.clone(Form.Element.Methods),
              "SELECT": Object.clone(Form.Element.Methods),
              "TEXTAREA": Object.clone(Form.Element.Methods),
              "BUTTON": Object.clone(Form.Element.Methods)
          });
      }
  
      Element.addMethods(methods);
  
      function destroyCache_IE() {
          DIV = null;
          ELEMENT_CACHE = null;
      }
  
      if (window.attachEvent)
          window.attachEvent('onunload', destroyCache_IE);
  
  })(this);
  (function () {
  
      function toDecimal(pctString) {
          var match = pctString.match(/^(\d+)%?$/i);
          if (!match) return null;
          return (Number(match[1]) / 100);
      }
  
      function getRawStyle(element, style) {
          element = $(element);
  
          var value = element.style[style];
          if (!value || value === 'auto') {
              var css = document.defaultView.getComputedStyle(element, null);
              value = css ? css[style] : null;
          }
  
          if (style === 'opacity') return value ? parseFloat(value) : 1.0;
          return value === 'auto' ? null : value;
      }
  
      function getRawStyle_IE(element, style) {
          var value = element.style[style];
          if (!value && element.currentStyle) {
              value = element.currentStyle[style];
          }
          return value;
      }
  
      function getContentWidth(element, context) {
          var boxWidth = element.offsetWidth;
  
          var bl = getPixelValue(element, 'borderLeftWidth', context) || 0;
          var br = getPixelValue(element, 'borderRightWidth', context) || 0;
          var pl = getPixelValue(element, 'paddingLeft', context) || 0;
          var pr = getPixelValue(element, 'paddingRight', context) || 0;
  
          return boxWidth - bl - br - pl - pr;
      }
  
      if (!Object.isUndefined(document.documentElement.currentStyle) && !Prototype.Browser.Opera) {
          getRawStyle = getRawStyle_IE;
      }
  
  
      function getPixelValue(value, property, context) {
          var element = null;
          if (Object.isElement(value)) {
              element = value;
              value = getRawStyle(element, property);
          }
  
          if (value === null || Object.isUndefined(value)) {
              return null;
          }
  
          if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
              return window.parseFloat(value);
          }
  
          var isPercentage = value.include('%'), isViewport = (context === document.viewport);
  
          if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
              var style = element.style.left, rStyle = element.runtimeStyle.left;
              element.runtimeStyle.left = element.currentStyle.left;
              element.style.left = value || 0;
              value = element.style.pixelLeft;
              element.style.left = style;
              element.runtimeStyle.left = rStyle;
  
              return value;
          }
  
          if (element && isPercentage) {
              context = context || element.parentNode;
              var decimal = toDecimal(value), whole = null;
  
              var isHorizontal = property.include('left') || property.include('right') ||
                  property.include('width');
  
              var isVertical = property.include('top') || property.include('bottom') ||
                  property.include('height');
  
              if (context === document.viewport) {
                  if (isHorizontal) {
                      whole = document.viewport.getWidth();
                  } else if (isVertical) {
                      whole = document.viewport.getHeight();
                  }
              } else {
                  if (isHorizontal) {
                      whole = $(context).measure('width');
                  } else if (isVertical) {
                      whole = $(context).measure('height');
                  }
              }
  
              return (whole === null) ? 0 : whole * decimal;
          }
  
          return 0;
      }
  
      function toCSSPixels(number) {
          if (Object.isString(number) && number.endsWith('px'))
              return number;
          return number + 'px';
      }
  
      function isDisplayed(element) {
          while (element && element.parentNode) {
              var display = element.getStyle('display');
              if (display === 'none') {
                  return false;
              }
              element = $(element.parentNode);
          }
          return true;
      }
  
      var hasLayout = Prototype.K;
      if ('currentStyle' in document.documentElement) {
          hasLayout = function (element) {
              if (!element.currentStyle.hasLayout) {
                  element.style.zoom = 1;
              }
              return element;
          };
      }
  
      function cssNameFor(key) {
          if (key.include('border')) key = key + '-width';
          return key.camelize();
      }
  
      Element.Layout = Class.create(Hash, {
          initialize: function ($super, element, preCompute) {
              $super();
              this.element = $(element);
  
              Element.Layout.PROPERTIES.each(function (property) {
                  this._set(property, null);
              }, this);
  
              if (preCompute) {
                  this._preComputing = true;
                  this._begin();
                  Element.Layout.PROPERTIES.each(this._compute, this);
                  this._end();
                  this._preComputing = false;
              }
          },
  
          _set: function (property, value) {
              return Hash.prototype.set.call(this, property, value);
          },
  
          set: function (property, value) {
              throw "Properties of Element.Layout are read-only.";
          },
  
          get: function ($super, property) {
              var value = $super(property);
              return value === null ? this._compute(property) : value;
          },
  
          _begin: function () {
              if (this._isPrepared()) return;
  
              var element = this.element;
              if (isDisplayed(element)) {
                  this._setPrepared(true);
                  return;
              }
  
  
              var originalStyles = {
                  position: element.style.position || '',
                  width: element.style.width || '',
                  visibility: element.style.visibility || '',
                  display: element.style.display || ''
              };
  
              element.store('prototype_original_styles', originalStyles);
  
              var position = getRawStyle(element, 'position'), width = element.offsetWidth;
  
              if (width === 0 || width === null) {
                  element.style.display = 'block';
                  width = element.offsetWidth;
              }
  
              var context = (position === 'fixed') ? document.viewport :
                  element.parentNode;
  
              var tempStyles = {
                  visibility: 'hidden',
                  display: 'block'
              };
  
              if (position !== 'fixed') tempStyles.position = 'absolute';
  
              element.setStyle(tempStyles);
  
              var positionedWidth = element.offsetWidth, newWidth;
              if (width && (positionedWidth === width)) {
                  newWidth = getContentWidth(element, context);
              } else if (position === 'absolute' || position === 'fixed') {
                  newWidth = getContentWidth(element, context);
              } else {
                  var parent = element.parentNode, pLayout = $(parent).getLayout();
  
                  newWidth = pLayout.get('width') -
                      this.get('margin-left') -
                      this.get('border-left') -
                      this.get('padding-left') -
                      this.get('padding-right') -
                      this.get('border-right') -
                      this.get('margin-right');
              }
  
              element.setStyle({width: newWidth + 'px'});
  
              this._setPrepared(true);
          },
  
          _end: function () {
              var element = this.element;
              var originalStyles = element.retrieve('prototype_original_styles');
              element.store('prototype_original_styles', null);
              element.setStyle(originalStyles);
              this._setPrepared(false);
          },
  
          _compute: function (property) {
              var COMPUTATIONS = Element.Layout.COMPUTATIONS;
              if (!(property in COMPUTATIONS)) {
                  throw "Property not found.";
              }
  
              return this._set(property, COMPUTATIONS[property].call(this, this.element));
          },
  
          _isPrepared: function () {
              return this.element.retrieve('prototype_element_layout_prepared', false);
          },
  
          _setPrepared: function (bool) {
              return this.element.store('prototype_element_layout_prepared', bool);
          },
  
          toObject: function () {
              var args = $A(arguments);
              var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
                  args.join(' ').split(' ');
              var obj = {};
              keys.each(function (key) {
                  if (!Element.Layout.PROPERTIES.include(key)) return;
                  var value = this.get(key);
                  if (value != null) obj[key] = value;
              }, this);
              return obj;
          },
  
          toHash: function () {
              var obj = this.toObject.apply(this, arguments);
              return new Hash(obj);
          },
  
          toCSS: function () {
              var args = $A(arguments);
              var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
                  args.join(' ').split(' ');
              var css = {};
  
              keys.each(function (key) {
                  if (!Element.Layout.PROPERTIES.include(key)) return;
                  if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
  
                  var value = this.get(key);
                  if (value != null) css[cssNameFor(key)] = value + 'px';
              }, this);
              return css;
          },
  
          inspect: function () {
              return "#<Element.Layout>";
          }
      });
  
      Object.extend(Element.Layout, {
          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'),
  
          COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
  
          COMPUTATIONS: {
              'height': function (element) {
                  if (!this._preComputing) this._begin();
  
                  var bHeight = this.get('border-box-height');
                  if (bHeight <= 0) {
                      if (!this._preComputing) this._end();
                      return 0;
                  }
  
                  var bTop = this.get('border-top'),
                      bBottom = this.get('border-bottom');
  
                  var pTop = this.get('padding-top'),
                      pBottom = this.get('padding-bottom');
  
                  if (!this._preComputing) this._end();
  
                  return bHeight - bTop - bBottom - pTop - pBottom;
              },
  
              'width': function (element) {
                  if (!this._preComputing) this._begin();
  
                  var bWidth = this.get('border-box-width');
                  if (bWidth <= 0) {
                      if (!this._preComputing) this._end();
                      return 0;
                  }
  
                  var bLeft = this.get('border-left'),
                      bRight = this.get('border-right');
  
                  var pLeft = this.get('padding-left'),
                      pRight = this.get('padding-right');
  
                  if (!this._preComputing) this._end();
                  return bWidth - bLeft - bRight - pLeft - pRight;
              },
  
              'padding-box-height': function (element) {
                  var height = this.get('height'),
                      pTop = this.get('padding-top'),
                      pBottom = this.get('padding-bottom');
  
                  return height + pTop + pBottom;
              },
  
              'padding-box-width': function (element) {
                  var width = this.get('width'),
                      pLeft = this.get('padding-left'),
                      pRight = this.get('padding-right');
  
                  return width + pLeft + pRight;
              },
  
              'border-box-height': function (element) {
                  if (!this._preComputing) this._begin();
                  var height = element.offsetHeight;
                  if (!this._preComputing) this._end();
                  return height;
              },
  
              'border-box-width': function (element) {
                  if (!this._preComputing) this._begin();
                  var width = element.offsetWidth;
                  if (!this._preComputing) this._end();
                  return width;
              },
  
              'margin-box-height': function (element) {
                  var bHeight = this.get('border-box-height'),
                      mTop = this.get('margin-top'),
                      mBottom = this.get('margin-bottom');
  
                  if (bHeight <= 0) return 0;
  
                  return bHeight + mTop + mBottom;
              },
  
              'margin-box-width': function (element) {
                  var bWidth = this.get('border-box-width'),
                      mLeft = this.get('margin-left'),
                      mRight = this.get('margin-right');
  
                  if (bWidth <= 0) return 0;
  
                  return bWidth + mLeft + mRight;
              },
  
              'top': function (element) {
                  var offset = element.positionedOffset();
                  return offset.top;
              },
  
              'bottom': function (element) {
                  var offset = element.positionedOffset(),
                      parent = element.getOffsetParent(),
                      pHeight = parent.measure('height');
  
                  var mHeight = this.get('border-box-height');
  
                  return pHeight - mHeight - offset.top;
              },
  
              'left': function (element) {
                  var offset = element.positionedOffset();
                  return offset.left;
              },
  
              'right': function (element) {
                  var offset = element.positionedOffset(),
                      parent = element.getOffsetParent(),
                      pWidth = parent.measure('width');
  
                  var mWidth = this.get('border-box-width');
  
                  return pWidth - mWidth - offset.left;
              },
  
              'padding-top': function (element) {
                  return getPixelValue(element, 'paddingTop');
              },
  
              'padding-bottom': function (element) {
                  return getPixelValue(element, 'paddingBottom');
              },
  
              'padding-left': function (element) {
                  return getPixelValue(element, 'paddingLeft');
              },
  
              'padding-right': function (element) {
                  return getPixelValue(element, 'paddingRight');
              },
  
              'border-top': function (element) {
                  return getPixelValue(element, 'borderTopWidth');
              },
  
              'border-bottom': function (element) {
                  return getPixelValue(element, 'borderBottomWidth');
              },
  
              'border-left': function (element) {
                  return getPixelValue(element, 'borderLeftWidth');
              },
  
              'border-right': function (element) {
                  return getPixelValue(element, 'borderRightWidth');
              },
  
              'margin-top': function (element) {
                  return getPixelValue(element, 'marginTop');
              },
  
              'margin-bottom': function (element) {
                  return getPixelValue(element, 'marginBottom');
              },
  
              'margin-left': function (element) {
                  return getPixelValue(element, 'marginLeft');
              },
  
              'margin-right': function (element) {
                  return getPixelValue(element, 'marginRight');
              }
          }
      });
  
      if ('getBoundingClientRect' in document.documentElement) {
          Object.extend(Element.Layout.COMPUTATIONS, {
              'right': function (element) {
                  var parent = hasLayout(element.getOffsetParent());
                  var rect = element.getBoundingClientRect(),
                      pRect = parent.getBoundingClientRect();
  
                  return (pRect.right - rect.right).round();
              },
  
              'bottom': function (element) {
                  var parent = hasLayout(element.getOffsetParent());
                  var rect = element.getBoundingClientRect(),
                      pRect = parent.getBoundingClientRect();
  
                  return (pRect.bottom - rect.bottom).round();
              }
          });
      }
  
      Element.Offset = Class.create({
          initialize: function (left, top) {
              this.left = left.round();
              this.top = top.round();
  
              this[0] = this.left;
              this[1] = this.top;
          },
  
          relativeTo: function (offset) {
              return new Element.Offset(
                  this.left - offset.left,
                  this.top - offset.top
              );
          },
  
          inspect: function () {
              return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
          },
  
          toString: function () {
              return "[#{left}, #{top}]".interpolate(this);
          },
  
          toArray: function () {
              return [this.left, this.top];
          }
      });
  
      function getLayout(element, preCompute) {
          return new Element.Layout(element, preCompute);
      }
  
      function measure(element, property) {
          return $(element).getLayout().get(property);
      }
  
      function getHeight(element) {
          return Element.getDimensions(element).height;
      }
  
      function getWidth(element) {
          return Element.getDimensions(element).width;
      }
  
      function getDimensions(element) {
          element = $(element);
          var display = Element.getStyle(element, 'display');
  
          if (display && display !== 'none') {
              return {width: element.offsetWidth, height: element.offsetHeight};
          }
  
          var style = element.style;
          var originalStyles = {
              visibility: style.visibility,
              position: style.position,
              display: style.display
          };
  
          var newStyles = {
              visibility: 'hidden',
              display: 'block'
          };
  
          if (originalStyles.position !== 'fixed')
              newStyles.position = 'absolute';
  
          Element.setStyle(element, newStyles);
  
          var dimensions = {
              width: element.offsetWidth,
              height: element.offsetHeight
          };
  
          Element.setStyle(element, originalStyles);
  
          return dimensions;
      }
  
      function getOffsetParent(element) {
          element = $(element);
  
          function selfOrBody(element) {
              return isHtml(element) ? $(document.body) : $(element);
          }
  
          if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
              return $(document.body);
  
          var isInline = (Element.getStyle(element, 'display') === 'inline');
          if (!isInline && element.offsetParent) return selfOrBody(element.offsetParent);
  
          while ((element = element.parentNode) && element !== document.body) {
              if (Element.getStyle(element, 'position') !== 'static') {
                  return selfOrBody(element);
              }
          }
  
          return $(document.body);
      }
  
  
      function cumulativeOffset(element) {
          element = $(element);
          var valueT = 0, valueL = 0;
          if (element.parentNode) {
              do {
                  valueT += element.offsetTop || 0;
                  valueL += element.offsetLeft || 0;
                  element = element.offsetParent;
              } while (element);
          }
          return new Element.Offset(valueL, valueT);
      }
  
      function positionedOffset(element) {
          element = $(element);
  
          var layout = element.getLayout();
  
          var valueT = 0, valueL = 0;
          do {
              valueT += element.offsetTop || 0;
              valueL += element.offsetLeft || 0;
              element = element.offsetParent;
              if (element) {
                  if (isBody(element)) break;
                  var p = Element.getStyle(element, 'position');
                  if (p !== 'static') break;
              }
          } while (element);
  
          valueL -= layout.get('margin-left');
          valueT -= layout.get('margin-top');
  
          return new Element.Offset(valueL, valueT);
      }
  
      function cumulativeScrollOffset(element) {
          var valueT = 0, valueL = 0;
          do {
              if (element === document.body) {
                  var bodyScrollNode = document.documentElement || document.body.parentNode || document.body;
                  valueT += !Object.isUndefined(window.pageYOffset) ? window.pageYOffset : bodyScrollNode.scrollTop || 0;
                  valueL += !Object.isUndefined(window.pageXOffset) ? window.pageXOffset : bodyScrollNode.scrollLeft || 0;
                  break;
              } else {
                  valueT += element.scrollTop || 0;
                  valueL += element.scrollLeft || 0;
                  element = element.parentNode;
              }
          } while (element);
          return new Element.Offset(valueL, valueT);
      }
  
      function viewportOffset(forElement) {
          var valueT = 0, valueL = 0, docBody = document.body;
  
          forElement = $(forElement);
          var element = forElement;
          do {
              valueT += element.offsetTop || 0;
              valueL += element.offsetLeft || 0;
              if (element.offsetParent == docBody &&
                  Element.getStyle(element, 'position') == 'absolute') break;
          } while (element = element.offsetParent);
  
          element = forElement;
          do {
              if (element != docBody) {
                  valueT -= element.scrollTop || 0;
                  valueL -= element.scrollLeft || 0;
              }
          } while (element = element.parentNode);
          return new Element.Offset(valueL, valueT);
      }
  
      function absolutize(element) {
          element = $(element);
  
          if (Element.getStyle(element, 'position') === 'absolute') {
              return element;
          }
  
          var offsetParent = getOffsetParent(element);
          var eOffset = element.viewportOffset(),
              pOffset = offsetParent.viewportOffset();
  
          var offset = eOffset.relativeTo(pOffset);
          var layout = element.getLayout();
  
          element.store('prototype_absolutize_original_styles', {
              position: element.getStyle('position'),
              left: element.getStyle('left'),
              top: element.getStyle('top'),
              width: element.getStyle('width'),
              height: element.getStyle('height')
          });
  
          element.setStyle({
              position: 'absolute',
              top: offset.top + 'px',
              left: offset.left + 'px',
              width: layout.get('width') + 'px',
              height: layout.get('height') + 'px'
          });
  
          return element;
      }
  
      function relativize(element) {
          element = $(element);
          if (Element.getStyle(element, 'position') === 'relative') {
              return element;
          }
  
          var originalStyles =
              element.retrieve('prototype_absolutize_original_styles');
  
          if (originalStyles) element.setStyle(originalStyles);
          return element;
      }
  
  
      function scrollTo(element) {
          element = $(element);
          var pos = Element.cumulativeOffset(element);
          window.scrollTo(pos.left, pos.top);
          return element;
      }
  
  
      function makePositioned(element) {
          element = $(element);
          var position = Element.getStyle(element, 'position'), styles = {};
          if (position === 'static' || !position) {
              styles.position = 'relative';
              if (Prototype.Browser.Opera) {
                  styles.top = 0;
                  styles.left = 0;
              }
              Element.setStyle(element, styles);
              Element.store(element, 'prototype_made_positioned', true);
          }
          return element;
      }
  
      function undoPositioned(element) {
          element = $(element);
          var storage = Element.getStorage(element),
              madePositioned = storage.get('prototype_made_positioned');
  
          if (madePositioned) {
              storage.unset('prototype_made_positioned');
              Element.setStyle(element, {
                  position: '',
                  top: '',
                  bottom: '',
                  left: '',
                  right: ''
              });
          }
          return element;
      }
  
      function makeClipping(element) {
          element = $(element);
  
          var storage = Element.getStorage(element),
              madeClipping = storage.get('prototype_made_clipping');
  
          if (Object.isUndefined(madeClipping)) {
              var overflow = Element.getStyle(element, 'overflow');
              storage.set('prototype_made_clipping', overflow);
              if (overflow !== 'hidden')
                  element.style.overflow = 'hidden';
          }
  
          return element;
      }
  
      function undoClipping(element) {
          element = $(element);
          var storage = Element.getStorage(element),
              overflow = storage.get('prototype_made_clipping');
  
          if (!Object.isUndefined(overflow)) {
              storage.unset('prototype_made_clipping');
              element.style.overflow = overflow || '';
          }
  
          return element;
      }
  
      function clonePosition(element, source, options) {
          options = Object.extend({
              setLeft: true,
              setTop: true,
              setWidth: true,
              setHeight: true,
              offsetTop: 0,
              offsetLeft: 0
          }, options || {});
  
          var docEl = document.documentElement;
  
          source = $(source);
          element = $(element);
          var p, delta, layout, styles = {};
  
          if (options.setLeft || options.setTop) {
              p = Element.viewportOffset(source);
              delta = [0, 0];
              if (Element.getStyle(element, 'position') === 'absolute') {
                  var parent = Element.getOffsetParent(element);
                  if (parent !== document.body) delta = Element.viewportOffset(parent);
              }
          }
  
          function pageScrollXY() {
              var x = 0, y = 0;
              if (Object.isNumber(window.pageXOffset)) {
                  x = window.pageXOffset;
                  y = window.pageYOffset;
              } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
                  x = document.body.scrollLeft;
                  y = document.body.scrollTop;
              } else if (docEl && (docEl.scrollLeft || docEl.scrollTop)) {
                  x = docEl.scrollLeft;
                  y = docEl.scrollTop;
              }
              return {x: x, y: y};
          }
  
          var pageXY = pageScrollXY();
  
  
          if (options.setWidth || options.setHeight) {
              layout = Element.getLayout(source);
          }
  
          if (options.setLeft)
              styles.left = (p[0] + pageXY.x - delta[0] + options.offsetLeft) + 'px';
          if (options.setTop)
              styles.top = (p[1] + pageXY.y - delta[1] + options.offsetTop) + 'px';
  
          var currentLayout = element.getLayout();
  
          if (options.setWidth) {
              styles.width = layout.get('width') + 'px';
          }
          if (options.setHeight) {
              styles.height = layout.get('height') + 'px';
          }
  
          return Element.setStyle(element, styles);
      }
  
  
      if (Prototype.Browser.IE) {
          getOffsetParent = getOffsetParent.wrap(
              function (proceed, element) {
                  element = $(element);
  
                  if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
                      return $(document.body);
  
                  var position = element.getStyle('position');
                  if (position !== 'static') return proceed(element);
  
                  element.setStyle({position: 'relative'});
                  var value = proceed(element);
                  element.setStyle({position: position});
                  return value;
              }
          );
  
          positionedOffset = positionedOffset.wrap(function (proceed, element) {
              element = $(element);
              if (!element.parentNode) return new Element.Offset(0, 0);
              var position = element.getStyle('position');
              if (position !== 'static') return proceed(element);
  
              var offsetParent = element.getOffsetParent();
              if (offsetParent && offsetParent.getStyle('position') === 'fixed')
                  hasLayout(offsetParent);
  
              element.setStyle({position: 'relative'});
              var value = proceed(element);
              element.setStyle({position: position});
              return value;
          });
      } else if (Prototype.Browser.Webkit) {
          cumulativeOffset = function (element) {
              element = $(element);
              var valueT = 0, valueL = 0;
              do {
                  valueT += element.offsetTop || 0;
                  valueL += element.offsetLeft || 0;
                  if (element.offsetParent == document.body) {
                      if (Element.getStyle(element, 'position') == 'absolute') break;
                  }
  
                  element = element.offsetParent;
              } while (element);
  
              return new Element.Offset(valueL, valueT);
          };
      }
  
  
      Element.addMethods({
          getLayout: getLayout,
          measure: measure,
          getWidth: getWidth,
          getHeight: getHeight,
          getDimensions: getDimensions,
          getOffsetParent: getOffsetParent,
          cumulativeOffset: cumulativeOffset,
          positionedOffset: positionedOffset,
          cumulativeScrollOffset: cumulativeScrollOffset,
          viewportOffset: viewportOffset,
          absolutize: absolutize,
          relativize: relativize,
          scrollTo: scrollTo,
          makePositioned: makePositioned,
          undoPositioned: undoPositioned,
          makeClipping: makeClipping,
          undoClipping: undoClipping,
          clonePosition: clonePosition
      });
  
      function isBody(element) {
          return element.nodeName.toUpperCase() === 'BODY';
      }
  
      function isHtml(element) {
          return element.nodeName.toUpperCase() === 'HTML';
      }
  
      function isDocument(element) {
          return element.nodeType === Node.DOCUMENT_NODE;
      }
  
      function isDetached(element) {
          return element !== document.body &&
              !Element.descendantOf(element, document.body);
      }
  
      if ('getBoundingClientRect' in document.documentElement) {
          Element.addMethods({
              viewportOffset: function (element) {
                  element = $(element);
                  if (isDetached(element)) return new Element.Offset(0, 0);
  
                  var rect = element.getBoundingClientRect(),
                      docEl = document.documentElement;
                  return new Element.Offset(rect.left - docEl.clientLeft,
                      rect.top - docEl.clientTop);
              }
          });
      }
  
  
  })();
  
  (function () {
  
      var IS_OLD_OPERA = Prototype.Browser.Opera &&
          (window.parseFloat(window.opera.version()) < 9.5);
      var ROOT = null;
  
      function getRootElement() {
          if (ROOT) return ROOT;
          ROOT = IS_OLD_OPERA ? document.body : document.documentElement;
          return ROOT;
      }
  
      function getDimensions() {
          return {width: this.getWidth(), height: this.getHeight()};
      }
  
      function getWidth() {
          return getRootElement().clientWidth;
      }
  
      function getHeight() {
          return getRootElement().clientHeight;
      }
  
      function getScrollOffsets() {
          var x = window.pageXOffset || document.documentElement.scrollLeft ||
              document.body.scrollLeft;
          var y = window.pageYOffset || document.documentElement.scrollTop ||
              document.body.scrollTop;
  
          return new Element.Offset(x, y);
      }
  
      document.viewport = {
          getDimensions: getDimensions,
          getWidth: getWidth,
          getHeight: getHeight,
          getScrollOffsets: getScrollOffsets
      };
  
  })();
  window.$$ = function () {
      var expression = $A(arguments).join(', ');
      return Prototype.Selector.select(expression, document);
  };
  
  Prototype.Selector = (function () {
  
      function select() {
          throw new Error('Method "Prototype.Selector.select" must be defined.');
      }
  
      function match() {
          throw new Error('Method "Prototype.Selector.match" must be defined.');
      }
  
      function find(elements, expression, index) {
          index = index || 0;
          var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
  
          for (i = 0; i < length; i++) {
              if (match(elements[i], expression) && index == matchIndex++) {
                  return Element.extend(elements[i]);
              }
          }
      }
  
      function extendElements(elements) {
          for (var i = 0, length = elements.length; i < length; i++) {
              Element.extend(elements[i]);
          }
          return elements;
      }
  
  
      var K = Prototype.K;
  
      return {
          select: select,
          match: match,
          find: find,
          extendElements: (Element.extend === K) ? K : extendElements,
          extendElement: Element.extend
      };
  })();
  Prototype._original_property = window.Sizzle;
  
  ;(function () {
      function fakeDefine(fn) {
          Prototype._actual_sizzle = fn();
      }
  
      fakeDefine.amd = true;
  
      if (typeof define !== 'undefined' && define.amd) {
          Prototype._original_define = define;
          Prototype._actual_sizzle = null;
          window.define = fakeDefine;
      }
  })();
  
  /*!
   * Sizzle CSS Selector Engine v1.10.18
   * http://sizzlejs.com/
   *
   * Copyright 2013 jQuery Foundation, Inc. and other contributors
   * Released under the MIT license
   * http://jquery.org/license
   *
   * Date: 2014-02-05
   */
  (function (window) {
  
      var i,
          support,
          Expr,
          getText,
          isXML,
          compile,
          select,
          outermostContext,
          sortInput,
          hasDuplicate,
  
          setDocument,
          document,
          docElem,
          documentIsHTML,
          rbuggyQSA,
          rbuggyMatches,
          matches,
          contains,
  
          expando = "sizzle" + -(new Date()),
          preferredDoc = window.document,
          dirruns = 0,
          done = 0,
          classCache = createCache(),
          tokenCache = createCache(),
          compilerCache = createCache(),
          sortOrder = function (a, b) {
              if (a === b) {
                  hasDuplicate = true;
              }
              return 0;
          },
  
          strundefined = typeof undefined,
          MAX_NEGATIVE = 1 << 31,
  
          hasOwn = ({}).hasOwnProperty,
          arr = [],
          pop = arr.pop,
          push_native = arr.push,
          push = arr.push,
          slice = arr.slice,
          indexOf = arr.indexOf || function (elem) {
              var i = 0,
                  len = this.length;
              for (; i < len; i++) {
                  if (this[i] === elem) {
                      return i;
                  }
              }
              return -1;
          },
  
          booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
  
  
          whitespace = "[\\x20\\t\\r\\n\\f]",
          characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
  
          identifier = characterEncoding.replace("w", "w#"),
  
          attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
              "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
  
          pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace(3, 8) + ")*)|.*)\\)|)",
  
          rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"),
  
          rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"),
          rcombinators = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"),
  
          rattributeQuotes = new RegExp("=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g"),
  
          rpseudo = new RegExp(pseudos),
          ridentifier = new RegExp("^" + identifier + "$"),
  
          matchExpr = {
              "ID": new RegExp("^#(" + characterEncoding + ")"),
              "CLASS": new RegExp("^\\.(" + characterEncoding + ")"),
              "TAG": new RegExp("^(" + characterEncoding.replace("w", "w*") + ")"),
              "ATTR": new RegExp("^" + attributes),
              "PSEUDO": new RegExp("^" + pseudos),
              "CHILD": new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
                  "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
                  "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
              "bool": new RegExp("^(?:" + booleans + ")$", "i"),
              "needsContext": new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
                  whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
          },
  
          rinputs = /^(?:input|select|textarea|button)$/i,
          rheader = /^h\d$/i,
  
          rnative = /^[^{]+\{\s*\[native \w/,
  
          rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
  
          rsibling = /[+~]/,
          rescape = /'|\\/g,
  
          runescape = new RegExp("\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig"),
          funescape = function (_, escaped, escapedWhitespace) {
              var high = "0x" + escaped - 0x10000;
              return high !== high || escapedWhitespace ?
                  escaped :
                  high < 0 ?
                      String.fromCharCode(high + 0x10000) :
                      String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00);
          };
  
      try {
          push.apply(
              (arr = slice.call(preferredDoc.childNodes)),
              preferredDoc.childNodes
          );
          arr[preferredDoc.childNodes.length].nodeType;
      } catch (e) {
          push = {
              apply: arr.length ?
  
                  function (target, els) {
                      push_native.apply(target, slice.call(els));
                  } :
  
                  function (target, els) {
                      var j = target.length,
                          i = 0;
                      while ((target[j++] = els[i++])) {
                      }
                      target.length = j - 1;
                  }
          };
      }
  
      function Sizzle(selector, context, results, seed) {
          var match, elem, m, nodeType,
              i, groups, old, nid, newContext, newSelector;
  
          if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
              setDocument(context);
          }
  
          context = context || document;
          results = results || [];
  
          if (!selector || typeof selector !== "string") {
              return results;
          }
  
          if ((nodeType = context.nodeType) !== 1 && nodeType !== 9) {
              return [];
          }
  
          if (documentIsHTML && !seed) {
  
              if ((match = rquickExpr.exec(selector))) {
                  if ((m = match[1])) {
                      if (nodeType === 9) {
                          elem = context.getElementById(m);
                          if (elem && elem.parentNode) {
                              if (elem.id === m) {
                                  results.push(elem);
                                  return results;
                              }
                          } else {
                              return results;
                          }
                      } else {
                          if (context.ownerDocument && (elem = context.ownerDocument.getElementById(m)) &&
                              contains(context, elem) && elem.id === m) {
                              results.push(elem);
                              return results;
                          }
                      }
  
                  } else if (match[2]) {
                      push.apply(results, context.getElementsByTagName(selector));
                      return results;
  
                  } else if ((m = match[3]) && support.getElementsByClassName && context.getElementsByClassName) {
                      push.apply(results, context.getElementsByClassName(m));
                      return results;
                  }
              }
  
              if (support.qsa && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
                  nid = old = expando;
                  newContext = context;
                  newSelector = nodeType === 9 && selector;
  
                  if (nodeType === 1 && context.nodeName.toLowerCase() !== "object") {
                      groups = tokenize(selector);
  
                      if ((old = context.getAttribute("id"))) {
                          nid = old.replace(rescape, "\\$&");
                      } else {
                          context.setAttribute("id", nid);
                      }
                      nid = "[id='" + nid + "'] ";
  
                      i = groups.length;
                      while (i--) {
                          groups[i] = nid + toSelector(groups[i]);
                      }
                      newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
                      newSelector = groups.join(",");
                  }
  
                  if (newSelector) {
                      try {
                          push.apply(results,
                              newContext.querySelectorAll(newSelector)
                          );
                          return results;
                      } catch (qsaError) {
                      } finally {
                          if (!old) {
                              context.removeAttribute("id");
                          }
                      }
                  }
              }
          }
  
          return select(selector.replace(rtrim, "$1"), context, results, seed);
      }
  
      /**
       * Create key-value caches of limited size
       * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
       *    property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
       *    deleting the oldest entry
       */
      function createCache() {
          var keys = [];
  
          function cache(key, value) {
              if (keys.push(key + " ") > Expr.cacheLength) {
                  delete cache[keys.shift()];
              }
              return (cache[key + " "] = value);
          }
  
          return cache;
      }
  
      /**
       * Mark a function for special use by Sizzle
       * @param {Function} fn The function to mark
       */
      function markFunction(fn) {
          fn[expando] = true;
          return fn;
      }
  
      /**
       * Support testing using an element
       * @param {Function} fn Passed the created div and expects a boolean result
       */
      function assert(fn) {
          var div = document.createElement("div");
  
          try {
              return !!fn(div);
          } catch (e) {
              return false;
          } finally {
              if (div.parentNode) {
                  div.parentNode.removeChild(div);
              }
              div = null;
          }
      }
  
      /**
       * Adds the same handler for all of the specified attrs
       * @param {String} attrs Pipe-separated list of attributes
       * @param {Function} handler The method that will be applied
       */
      function addHandle(attrs, handler) {
          var arr = attrs.split("|"),
              i = attrs.length;
  
          while (i--) {
              Expr.attrHandle[arr[i]] = handler;
          }
      }
  
      /**
       * Checks document order of two siblings
       * @param {Element} a
       * @param {Element} b
       * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
       */
      function siblingCheck(a, b) {
          var cur = b && a,
              diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
                  (~b.sourceIndex || MAX_NEGATIVE) -
                  (~a.sourceIndex || MAX_NEGATIVE);
  
          if (diff) {
              return diff;
          }
  
          if (cur) {
              while ((cur = cur.nextSibling)) {
                  if (cur === b) {
                      return -1;
                  }
              }
          }
  
          return a ? 1 : -1;
      }
  
      /**
       * Returns a function to use in pseudos for input types
       * @param {String} type
       */
      function createInputPseudo(type) {
          return function (elem) {
              var name = elem.nodeName.toLowerCase();
              return name === "input" && elem.type === type;
          };
      }
  
      /**
       * Returns a function to use in pseudos for buttons
       * @param {String} type
       */
      function createButtonPseudo(type) {
          return function (elem) {
              var name = elem.nodeName.toLowerCase();
              return (name === "input" || name === "button") && elem.type === type;
          };
      }
  
      /**
       * Returns a function to use in pseudos for positionals
       * @param {Function} fn
       */
      function createPositionalPseudo(fn) {
          return markFunction(function (argument) {
              argument = +argument;
              return markFunction(function (seed, matches) {
                  var j,
                      matchIndexes = fn([], seed.length, argument),
                      i = matchIndexes.length;
  
                  while (i--) {
                      if (seed[(j = matchIndexes[i])]) {
                          seed[j] = !(matches[j] = seed[j]);
                      }
                  }
              });
          });
      }
  
      /**
       * Checks a node for validity as a Sizzle context
       * @param {Element|Object=} context
       * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
       */
      function testContext(context) {
          return context && typeof context.getElementsByTagName !== strundefined && context;
      }
  
      support = Sizzle.support = {};
  
      /**
       * Detects XML nodes
       * @param {Element|Object} elem An element or a document
       * @returns {Boolean} True iff elem is a non-HTML XML node
       */
      isXML = Sizzle.isXML = function (elem) {
          var documentElement = elem && (elem.ownerDocument || elem).documentElement;
          return documentElement ? documentElement.nodeName !== "HTML" : false;
      };
  
      /**
       * Sets document-related variables once based on the current document
       * @param {Element|Object} [doc] An element or document object to use to set the document
       * @returns {Object} Returns the current document
       */
      setDocument = Sizzle.setDocument = function (node) {
          var hasCompare,
              doc = node ? node.ownerDocument || node : preferredDoc,
              parent = doc.defaultView;
  
          if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
              return document;
          }
  
          document = doc;
          docElem = doc.documentElement;
  
          documentIsHTML = !isXML(doc);
  
          if (parent && parent !== parent.top) {
              if (parent.addEventListener) {
                  parent.addEventListener("unload", function () {
                      setDocument();
                  }, false);
              } else if (parent.attachEvent) {
                  parent.attachEvent("onunload", function () {
                      setDocument();
                  });
              }
          }
  
          /* Attributes
  	---------------------------------------------------------------------- */
  
          support.attributes = assert(function (div) {
              div.className = "i";
              return !div.getAttribute("className");
          });
  
          /* getElement(s)By*
  	---------------------------------------------------------------------- */
  
          support.getElementsByTagName = assert(function (div) {
              div.appendChild(doc.createComment(""));
              return !div.getElementsByTagName("*").length;
          });
  
          support.getElementsByClassName = rnative.test(doc.getElementsByClassName) && assert(function (div) {
              div.innerHTML = "<div class='a'></div><div class='a i'></div>";
  
              div.firstChild.className = "i";
              return div.getElementsByClassName("i").length === 2;
          });
  
          support.getById = assert(function (div) {
              docElem.appendChild(div).id = expando;
              return !doc.getElementsByName || !doc.getElementsByName(expando).length;
          });
  
          if (support.getById) {
              Expr.find["ID"] = function (id, context) {
                  if (typeof context.getElementById !== strundefined && documentIsHTML) {
                      var m = context.getElementById(id);
                      return m && m.parentNode ? [m] : [];
                  }
              };
              Expr.filter["ID"] = function (id) {
                  var attrId = id.replace(runescape, funescape);
                  return function (elem) {
                      return elem.getAttribute("id") === attrId;
                  };
              };
          } else {
              delete Expr.find["ID"];
  
              Expr.filter["ID"] = function (id) {
                  var attrId = id.replace(runescape, funescape);
                  return function (elem) {
                      var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
                      return node && node.value === attrId;
                  };
              };
          }
  
          Expr.find["TAG"] = support.getElementsByTagName ?
              function (tag, context) {
                  if (typeof context.getElementsByTagName !== strundefined) {
                      return context.getElementsByTagName(tag);
                  }
              } :
              function (tag, context) {
                  var elem,
                      tmp = [],
                      i = 0,
                      results = context.getElementsByTagName(tag);
  
                  if (tag === "*") {
                      while ((elem = results[i++])) {
                          if (elem.nodeType === 1) {
                              tmp.push(elem);
                          }
                      }
  
                      return tmp;
                  }
                  return results;
              };
  
          Expr.find["CLASS"] = support.getElementsByClassName && function (className, context) {
              if (typeof context.getElementsByClassName !== strundefined && documentIsHTML) {
                  return context.getElementsByClassName(className);
              }
          };
  
          /* QSA/matchesSelector
  	---------------------------------------------------------------------- */
  
  
          rbuggyMatches = [];
  
          rbuggyQSA = [];
  
          if ((support.qsa = rnative.test(doc.querySelectorAll))) {
              assert(function (div) {
                  div.innerHTML = "<select t=''><option selected=''></option></select>";
  
                  if (div.querySelectorAll("[t^='']").length) {
                      rbuggyQSA.push("[*^$]=" + whitespace + "*(?:''|\"\")");
                  }
  
                  if (!div.querySelectorAll("[selected]").length) {
                      rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
                  }
  
                  if (!div.querySelectorAll(":checked").length) {
                      rbuggyQSA.push(":checked");
                  }
              });
  
              assert(function (div) {
                  var input = doc.createElement("input");
                  input.setAttribute("type", "hidden");
                  div.appendChild(input).setAttribute("name", "D");
  
                  if (div.querySelectorAll("[name=d]").length) {
                      rbuggyQSA.push("name" + whitespace + "*[*^$|!~]?=");
                  }
  
                  if (!div.querySelectorAll(":enabled").length) {
                      rbuggyQSA.push(":enabled", ":disabled");
                  }
  
                  div.querySelectorAll("*,:x");
                  rbuggyQSA.push(",.*:");
              });
          }
  
          if ((support.matchesSelector = rnative.test((matches = docElem.webkitMatchesSelector ||
              docElem.mozMatchesSelector ||
              docElem.oMatchesSelector ||
              docElem.msMatchesSelector)))) {
  
              assert(function (div) {
                  support.disconnectedMatch = matches.call(div, "div");
  
                  matches.call(div, "[s!='']:x");
                  rbuggyMatches.push("!=", pseudos);
              });
          }
  
          rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
          rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));
  
          /* Contains
  	---------------------------------------------------------------------- */
          hasCompare = rnative.test(docElem.compareDocumentPosition);
  
          contains = hasCompare || rnative.test(docElem.contains) ?
              function (a, b) {
                  var adown = a.nodeType === 9 ? a.documentElement : a,
                      bup = b && b.parentNode;
                  return a === bup || !!(bup && bup.nodeType === 1 && (
                      adown.contains ?
                          adown.contains(bup) :
                          a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
                  ));
              } :
              function (a, b) {
                  if (b) {
                      while ((b = b.parentNode)) {
                          if (b === a) {
                              return true;
                          }
                      }
                  }
                  return false;
              };
  
          /* Sorting
  	---------------------------------------------------------------------- */
  
          sortOrder = hasCompare ?
              function (a, b) {
  
                  if (a === b) {
                      hasDuplicate = true;
                      return 0;
                  }
  
                  var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
                  if (compare) {
                      return compare;
                  }
  
                  compare = (a.ownerDocument || a) === (b.ownerDocument || b) ?
                      a.compareDocumentPosition(b) :
  
                      1;
  
                  if (compare & 1 ||
                      (!support.sortDetached && b.compareDocumentPosition(a) === compare)) {
  
                      if (a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a)) {
                          return -1;
                      }
                      if (b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b)) {
                          return 1;
                      }
  
                      return sortInput ?
                          (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) :
                          0;
                  }
  
                  return compare & 4 ? -1 : 1;
              } :
              function (a, b) {
                  if (a === b) {
                      hasDuplicate = true;
                      return 0;
                  }
  
                  var cur,
                      i = 0,
                      aup = a.parentNode,
                      bup = b.parentNode,
                      ap = [a],
                      bp = [b];
  
                  if (!aup || !bup) {
                      return a === doc ? -1 :
                          b === doc ? 1 :
                              aup ? -1 :
                                  bup ? 1 :
                                      sortInput ?
                                          (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) :
                                          0;
  
                  } else if (aup === bup) {
                      return siblingCheck(a, b);
                  }
  
                  cur = a;
                  while ((cur = cur.parentNode)) {
                      ap.unshift(cur);
                  }
                  cur = b;
                  while ((cur = cur.parentNode)) {
                      bp.unshift(cur);
                  }
  
                  while (ap[i] === bp[i]) {
                      i++;
                  }
  
                  return i ?
                      siblingCheck(ap[i], bp[i]) :
  
                      ap[i] === preferredDoc ? -1 :
                          bp[i] === preferredDoc ? 1 :
                              0;
              };
  
          return doc;
      };
  
      Sizzle.matches = function (expr, elements) {
          return Sizzle(expr, null, null, elements);
      };
  
      Sizzle.matchesSelector = function (elem, expr) {
          if ((elem.ownerDocument || elem) !== document) {
              setDocument(elem);
          }
  
          expr = expr.replace(rattributeQuotes, "='$1']");
  
          if (support.matchesSelector && documentIsHTML &&
              (!rbuggyMatches || !rbuggyMatches.test(expr)) &&
              (!rbuggyQSA || !rbuggyQSA.test(expr))) {
  
              try {
                  var ret = matches.call(elem, expr);
  
                  if (ret || support.disconnectedMatch ||
                      elem.document && elem.document.nodeType !== 11) {
                      return ret;
                  }
              } catch (e) {
              }
          }
  
          return Sizzle(expr, document, null, [elem]).length > 0;
      };
  
      Sizzle.contains = function (context, elem) {
          if ((context.ownerDocument || context) !== document) {
              setDocument(context);
          }
          return contains(context, elem);
      };
  
      Sizzle.attr = function (elem, name) {
          if ((elem.ownerDocument || elem) !== document) {
              setDocument(elem);
          }
  
          var fn = Expr.attrHandle[name.toLowerCase()],
              val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ?
                  fn(elem, name, !documentIsHTML) :
                  undefined;
  
          return val !== undefined ?
              val :
              support.attributes || !documentIsHTML ?
                  elem.getAttribute(name) :
                  (val = elem.getAttributeNode(name)) && val.specified ?
                      val.value :
                      null;
      };
  
      Sizzle.error = function (msg) {
          throw new Error("Syntax error, unrecognized expression: " + msg);
      };
  
      /**
       * Document sorting and removing duplicates
       * @param {ArrayLike} results
       */
      Sizzle.uniqueSort = function (results) {
          var elem,
              duplicates = [],
              j = 0,
              i = 0;
  
          hasDuplicate = !support.detectDuplicates;
          sortInput = !support.sortStable && results.slice(0);
          results.sort(sortOrder);
  
          if (hasDuplicate) {
              while ((elem = results[i++])) {
                  if (elem === results[i]) {
                      j = duplicates.push(i);
                  }
              }
              while (j--) {
                  results.splice(duplicates[j], 1);
              }
          }
  
          sortInput = null;
  
          return results;
      };
  
      /**
       * Utility function for retrieving the text value of an array of DOM nodes
       * @param {Array|Element} elem
       */
      getText = Sizzle.getText = function (elem) {
          var node,
              ret = "",
              i = 0,
              nodeType = elem.nodeType;
  
          if (!nodeType) {
              while ((node = elem[i++])) {
                  ret += getText(node);
              }
          } else if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
              if (typeof elem.textContent === "string") {
                  return elem.textContent;
              } else {
                  for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
                      ret += getText(elem);
                  }
              }
          } else if (nodeType === 3 || nodeType === 4) {
              return elem.nodeValue;
          }
  
          return ret;
      };
  
      Expr = Sizzle.selectors = {
  
          cacheLength: 50,
  
          createPseudo: markFunction,
  
          match: matchExpr,
  
          attrHandle: {},
  
          find: {},
  
          relative: {
              ">": {dir: "parentNode", first: true},
              " ": {dir: "parentNode"},
              "+": {dir: "previousSibling", first: true},
              "~": {dir: "previousSibling"}
          },
  
          preFilter: {
              "ATTR": function (match) {
                  match[1] = match[1].replace(runescape, funescape);
  
                  match[3] = (match[4] || match[5] || "").replace(runescape, funescape);
  
                  if (match[2] === "~=") {
                      match[3] = " " + match[3] + " ";
                  }
  
                  return match.slice(0, 4);
              },
  
              "CHILD": function (match) {
                  /* matches from matchExpr["CHILD"]
  				1 type (only|nth|...)
  				2 what (child|of-type)
  				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
  				4 xn-component of xn+y argument ([+-]?\d*n|)
  				5 sign of xn-component
  				6 x of xn-component
  				7 sign of y-component
  				8 y of y-component
  			*/
                  match[1] = match[1].toLowerCase();
  
                  if (match[1].slice(0, 3) === "nth") {
                      if (!match[3]) {
                          Sizzle.error(match[0]);
                      }
  
                      match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
                      match[5] = +((match[7] + match[8]) || match[3] === "odd");
  
                  } else if (match[3]) {
                      Sizzle.error(match[0]);
                  }
  
                  return match;
              },
  
              "PSEUDO": function (match) {
                  var excess,
                      unquoted = !match[5] && match[2];
  
                  if (matchExpr["CHILD"].test(match[0])) {
                      return null;
                  }
  
                  if (match[3] && match[4] !== undefined) {
                      match[2] = match[4];
  
                  } else if (unquoted && rpseudo.test(unquoted) &&
                      (excess = tokenize(unquoted, true)) &&
                      (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
  
                      match[0] = match[0].slice(0, excess);
                      match[2] = unquoted.slice(0, excess);
                  }
  
                  return match.slice(0, 3);
              }
          },
  
          filter: {
  
              "TAG": function (nodeNameSelector) {
                  var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
                  return nodeNameSelector === "*" ?
                      function () {
                          return true;
                      } :
                      function (elem) {
                          return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
                      };
              },
  
              "CLASS": function (className) {
                  var pattern = classCache[className + " "];
  
                  return pattern ||
                      (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) &&
                      classCache(className, function (elem) {
                          return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "");
                      });
              },
  
              "ATTR": function (name, operator, check) {
                  return function (elem) {
                      var result = Sizzle.attr(elem, name);
  
                      if (result == null) {
                          return operator === "!=";
                      }
                      if (!operator) {
                          return true;
                      }
  
                      result += "";
  
                      return operator === "=" ? result === check :
                          operator === "!=" ? result !== check :
                              operator === "^=" ? check && result.indexOf(check) === 0 :
                                  operator === "*=" ? check && result.indexOf(check) > -1 :
                                      operator === "$=" ? check && result.slice(-check.length) === check :
                                          operator === "~=" ? (" " + result + " ").indexOf(check) > -1 :
                                              operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" :
                                                  false;
                  };
              },
  
              "CHILD": function (type, what, argument, first, last) {
                  var simple = type.slice(0, 3) !== "nth",
                      forward = type.slice(-4) !== "last",
                      ofType = what === "of-type";
  
                  return first === 1 && last === 0 ?
  
                      function (elem) {
                          return !!elem.parentNode;
                      } :
  
                      function (elem, context, xml) {
                          var cache, outerCache, node, diff, nodeIndex, start,
                              dir = simple !== forward ? "nextSibling" : "previousSibling",
                              parent = elem.parentNode,
                              name = ofType && elem.nodeName.toLowerCase(),
                              useCache = !xml && !ofType;
  
                          if (parent) {
  
                              if (simple) {
                                  while (dir) {
                                      node = elem;
                                      while ((node = node[dir])) {
                                          if (ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) {
                                              return false;
                                          }
                                      }
                                      start = dir = type === "only" && !start && "nextSibling";
                                  }
                                  return true;
                              }
  
                              start = [forward ? parent.firstChild : parent.lastChild];
  
                              if (forward && useCache) {
                                  outerCache = parent[expando] || (parent[expando] = {});
                                  cache = outerCache[type] || [];
                                  nodeIndex = cache[0] === dirruns && cache[1];
                                  diff = cache[0] === dirruns && cache[2];
                                  node = nodeIndex && parent.childNodes[nodeIndex];
  
                                  while ((node = ++nodeIndex && node && node[dir] ||
  
                                      (diff = nodeIndex = 0) || start.pop())) {
  
                                      if (node.nodeType === 1 && ++diff && node === elem) {
                                          outerCache[type] = [dirruns, nodeIndex, diff];
                                          break;
                                      }
                                  }
  
                              } else if (useCache && (cache = (elem[expando] || (elem[expando] = {}))[type]) && cache[0] === dirruns) {
                                  diff = cache[1];
  
                              } else {
                                  while ((node = ++nodeIndex && node && node[dir] ||
                                      (diff = nodeIndex = 0) || start.pop())) {
  
                                      if ((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff) {
                                          if (useCache) {
                                              (node[expando] || (node[expando] = {}))[type] = [dirruns, diff];
                                          }
  
                                          if (node === elem) {
                                              break;
                                          }
                                      }
                                  }
                              }
  
                              diff -= last;
                              return diff === first || (diff % first === 0 && diff / first >= 0);
                          }
                      };
              },
  
              "PSEUDO": function (pseudo, argument) {
                  var args,
                      fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] ||
                          Sizzle.error("unsupported pseudo: " + pseudo);
  
                  if (fn[expando]) {
                      return fn(argument);
                  }
  
                  if (fn.length > 1) {
                      args = [pseudo, pseudo, "", argument];
                      return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ?
                          markFunction(function (seed, matches) {
                              var idx,
                                  matched = fn(seed, argument),
                                  i = matched.length;
                              while (i--) {
                                  idx = indexOf.call(seed, matched[i]);
                                  seed[idx] = !(matches[idx] = matched[i]);
                              }
                          }) :
                          function (elem) {
                              return fn(elem, 0, args);
                          };
                  }
  
                  return fn;
              }
          },
  
          pseudos: {
              "not": markFunction(function (selector) {
                  var input = [],
                      results = [],
                      matcher = compile(selector.replace(rtrim, "$1"));
  
                  return matcher[expando] ?
                      markFunction(function (seed, matches, context, xml) {
                          var elem,
                              unmatched = matcher(seed, null, xml, []),
                              i = seed.length;
  
                          while (i--) {
                              if ((elem = unmatched[i])) {
                                  seed[i] = !(matches[i] = elem);
                              }
                          }
                      }) :
                      function (elem, context, xml) {
                          input[0] = elem;
                          matcher(input, null, xml, results);
                          return !results.pop();
                      };
              }),
  
              "has": markFunction(function (selector) {
                  return function (elem) {
                      return Sizzle(selector, elem).length > 0;
                  };
              }),
  
              "contains": markFunction(function (text) {
                  return function (elem) {
                      return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1;
                  };
              }),
  
              "lang": markFunction(function (lang) {
                  if (!ridentifier.test(lang || "")) {
                      Sizzle.error("unsupported lang: " + lang);
                  }
                  lang = lang.replace(runescape, funescape).toLowerCase();
                  return function (elem) {
                      var elemLang;
                      do {
                          if ((elemLang = documentIsHTML ?
                              elem.lang :
                              elem.getAttribute("xml:lang") || elem.getAttribute("lang"))) {
  
                              elemLang = elemLang.toLowerCase();
                              return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
                          }
                      } while ((elem = elem.parentNode) && elem.nodeType === 1);
                      return false;
                  };
              }),
  
              "target": function (elem) {
                  var hash = window.location && window.location.hash;
                  return hash && hash.slice(1) === elem.id;
              },
  
              "root": function (elem) {
                  return elem === docElem;
              },
  
              "focus": function (elem) {
                  return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
              },
  
              "enabled": function (elem) {
                  return elem.disabled === false;
              },
  
              "disabled": function (elem) {
                  return elem.disabled === true;
              },
  
              "checked": function (elem) {
                  var nodeName = elem.nodeName.toLowerCase();
                  return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
              },
  
              "selected": function (elem) {
                  if (elem.parentNode) {
                      elem.parentNode.selectedIndex;
                  }
  
                  return elem.selected === true;
              },
  
              "empty": function (elem) {
                  for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
                      if (elem.nodeType < 6) {
                          return false;
                      }
                  }
                  return true;
              },
  
              "parent": function (elem) {
                  return !Expr.pseudos["empty"](elem);
              },
  
              "header": function (elem) {
                  return rheader.test(elem.nodeName);
              },
  
              "input": function (elem) {
                  return rinputs.test(elem.nodeName);
              },
  
              "button": function (elem) {
                  var name = elem.nodeName.toLowerCase();
                  return name === "input" && elem.type === "button" || name === "button";
              },
  
              "text": function (elem) {
                  var attr;
                  return elem.nodeName.toLowerCase() === "input" &&
                      elem.type === "text" &&
  
                      ((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
              },
  
              "first": createPositionalPseudo(function () {
                  return [0];
              }),
  
              "last": createPositionalPseudo(function (matchIndexes, length) {
                  return [length - 1];
              }),
  
              "eq": createPositionalPseudo(function (matchIndexes, length, argument) {
                  return [argument < 0 ? argument + length : argument];
              }),
  
              "even": createPositionalPseudo(function (matchIndexes, length) {
                  var i = 0;
                  for (; i < length; i += 2) {
                      matchIndexes.push(i);
                  }
                  return matchIndexes;
              }),
  
              "odd": createPositionalPseudo(function (matchIndexes, length) {
                  var i = 1;
                  for (; i < length; i += 2) {
                      matchIndexes.push(i);
                  }
                  return matchIndexes;
              }),
  
              "lt": createPositionalPseudo(function (matchIndexes, length, argument) {
                  var i = argument < 0 ? argument + length : argument;
                  for (; --i >= 0;) {
                      matchIndexes.push(i);
                  }
                  return matchIndexes;
              }),
  
              "gt": createPositionalPseudo(function (matchIndexes, length, argument) {
                  var i = argument < 0 ? argument + length : argument;
                  for (; ++i < length;) {
                      matchIndexes.push(i);
                  }
                  return matchIndexes;
              })
          }
      };
  
      Expr.pseudos["nth"] = Expr.pseudos["eq"];
  
      for (i in {radio: true, checkbox: true, file: true, password: true, image: true}) {
          Expr.pseudos[i] = createInputPseudo(i);
      }
      for (i in {submit: true, reset: true}) {
          Expr.pseudos[i] = createButtonPseudo(i);
      }
  
      function setFilters() {
      }
  
      setFilters.prototype = Expr.filters = Expr.pseudos;
      Expr.setFilters = new setFilters();
  
      function tokenize(selector, parseOnly) {
          var matched, match, tokens, type,
              soFar, groups, preFilters,
              cached = tokenCache[selector + " "];
  
          if (cached) {
              return parseOnly ? 0 : cached.slice(0);
          }
  
          soFar = selector;
          groups = [];
          preFilters = Expr.preFilter;
  
          while (soFar) {
  
              if (!matched || (match = rcomma.exec(soFar))) {
                  if (match) {
                      soFar = soFar.slice(match[0].length) || soFar;
                  }
                  groups.push((tokens = []));
              }
  
              matched = false;
  
              if ((match = rcombinators.exec(soFar))) {
                  matched = match.shift();
                  tokens.push({
                      value: matched,
                      type: match[0].replace(rtrim, " ")
                  });
                  soFar = soFar.slice(matched.length);
              }
  
              for (type in Expr.filter) {
                  if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] ||
                      (match = preFilters[type](match)))) {
                      matched = match.shift();
                      tokens.push({
                          value: matched,
                          type: type,
                          matches: match
                      });
                      soFar = soFar.slice(matched.length);
                  }
              }
  
              if (!matched) {
                  break;
              }
          }
  
          return parseOnly ?
              soFar.length :
              soFar ?
                  Sizzle.error(selector) :
                  tokenCache(selector, groups).slice(0);
      }
  
      function toSelector(tokens) {
          var i = 0,
              len = tokens.length,
              selector = "";
          for (; i < len; i++) {
              selector += tokens[i].value;
          }
          return selector;
      }
  
      function addCombinator(matcher, combinator, base) {
          var dir = combinator.dir,
              checkNonElements = base && dir === "parentNode",
              doneName = done++;
  
          return combinator.first ?
              function (elem, context, xml) {
                  while ((elem = elem[dir])) {
                      if (elem.nodeType === 1 || checkNonElements) {
                          return matcher(elem, context, xml);
                      }
                  }
              } :
  
              function (elem, context, xml) {
                  var oldCache, outerCache,
                      newCache = [dirruns, doneName];
  
                  if (xml) {
                      while ((elem = elem[dir])) {
                          if (elem.nodeType === 1 || checkNonElements) {
                              if (matcher(elem, context, xml)) {
                                  return true;
                              }
                          }
                      }
                  } else {
                      while ((elem = elem[dir])) {
                          if (elem.nodeType === 1 || checkNonElements) {
                              outerCache = elem[expando] || (elem[expando] = {});
                              if ((oldCache = outerCache[dir]) &&
                                  oldCache[0] === dirruns && oldCache[1] === doneName) {
  
                                  return (newCache[2] = oldCache[2]);
                              } else {
                                  outerCache[dir] = newCache;
  
                                  if ((newCache[2] = matcher(elem, context, xml))) {
                                      return true;
                                  }
                              }
                          }
                      }
                  }
              };
      }
  
      function elementMatcher(matchers) {
          return matchers.length > 1 ?
              function (elem, context, xml) {
                  var i = matchers.length;
                  while (i--) {
                      if (!matchers[i](elem, context, xml)) {
                          return false;
                      }
                  }
                  return true;
              } :
              matchers[0];
      }
  
      function multipleContexts(selector, contexts, results) {
          var i = 0,
              len = contexts.length;
          for (; i < len; i++) {
              Sizzle(selector, contexts[i], results);
          }
          return results;
      }
  
      function condense(unmatched, map, filter, context, xml) {
          var elem,
              newUnmatched = [],
              i = 0,
              len = unmatched.length,
              mapped = map != null;
  
          for (; i < len; i++) {
              if ((elem = unmatched[i])) {
                  if (!filter || filter(elem, context, xml)) {
                      newUnmatched.push(elem);
                      if (mapped) {
                          map.push(i);
                      }
                  }
              }
          }
  
          return newUnmatched;
      }
  
      function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
          if (postFilter && !postFilter[expando]) {
              postFilter = setMatcher(postFilter);
          }
          if (postFinder && !postFinder[expando]) {
              postFinder = setMatcher(postFinder, postSelector);
          }
          return markFunction(function (seed, results, context, xml) {
              var temp, i, elem,
                  preMap = [],
                  postMap = [],
                  preexisting = results.length,
  
                  elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []),
  
                  matcherIn = preFilter && (seed || !selector) ?
                      condense(elems, preMap, preFilter, context, xml) :
                      elems,
  
                  matcherOut = matcher ?
                      postFinder || (seed ? preFilter : preexisting || postFilter) ?
  
                          [] :
  
                          results :
                      matcherIn;
  
              if (matcher) {
                  matcher(matcherIn, matcherOut, context, xml);
              }
  
              if (postFilter) {
                  temp = condense(matcherOut, postMap);
                  postFilter(temp, [], context, xml);
  
                  i = temp.length;
                  while (i--) {
                      if ((elem = temp[i])) {
                          matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
                      }
                  }
              }
  
              if (seed) {
                  if (postFinder || preFilter) {
                      if (postFinder) {
                          temp = [];
                          i = matcherOut.length;
                          while (i--) {
                              if ((elem = matcherOut[i])) {
                                  temp.push((matcherIn[i] = elem));
                              }
                          }
                          postFinder(null, (matcherOut = []), temp, xml);
                      }
  
                      i = matcherOut.length;
                      while (i--) {
                          if ((elem = matcherOut[i]) &&
                              (temp = postFinder ? indexOf.call(seed, elem) : preMap[i]) > -1) {
  
                              seed[temp] = !(results[temp] = elem);
                          }
                      }
                  }
  
              } else {
                  matcherOut = condense(
                      matcherOut === results ?
                          matcherOut.splice(preexisting, matcherOut.length) :
                          matcherOut
                  );
                  if (postFinder) {
                      postFinder(null, results, matcherOut, xml);
                  } else {
                      push.apply(results, matcherOut);
                  }
              }
          });
      }
  
      function matcherFromTokens(tokens) {
          var checkContext, matcher, j,
              len = tokens.length,
              leadingRelative = Expr.relative[tokens[0].type],
              implicitRelative = leadingRelative || Expr.relative[" "],
              i = leadingRelative ? 1 : 0,
  
              matchContext = addCombinator(function (elem) {
                  return elem === checkContext;
              }, implicitRelative, true),
              matchAnyContext = addCombinator(function (elem) {
                  return indexOf.call(checkContext, elem) > -1;
              }, implicitRelative, true),
              matchers = [function (elem, context, xml) {
                  return (!leadingRelative && (xml || context !== outermostContext)) || (
                      (checkContext = context).nodeType ?
                          matchContext(elem, context, xml) :
                          matchAnyContext(elem, context, xml));
              }];
  
          for (; i < len; i++) {
              if ((matcher = Expr.relative[tokens[i].type])) {
                  matchers = [addCombinator(elementMatcher(matchers), matcher)];
              } else {
                  matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
  
                  if (matcher[expando]) {
                      j = ++i;
                      for (; j < len; j++) {
                          if (Expr.relative[tokens[j].type]) {
                              break;
                          }
                      }
                      return setMatcher(
                          i > 1 && elementMatcher(matchers),
                          i > 1 && toSelector(
                              tokens.slice(0, i - 1).concat({value: tokens[i - 2].type === " " ? "*" : ""})
                          ).replace(rtrim, "$1"),
                          matcher,
                          i < j && matcherFromTokens(tokens.slice(i, j)),
                          j < len && matcherFromTokens((tokens = tokens.slice(j))),
                          j < len && toSelector(tokens)
                      );
                  }
                  matchers.push(matcher);
              }
          }
  
          return elementMatcher(matchers);
      }
  
      function matcherFromGroupMatchers(elementMatchers, setMatchers) {
          var bySet = setMatchers.length > 0,
              byElement = elementMatchers.length > 0,
              superMatcher = function (seed, context, xml, results, outermost) {
                  var elem, j, matcher,
                      matchedCount = 0,
                      i = "0",
                      unmatched = seed && [],
                      setMatched = [],
                      contextBackup = outermostContext,
                      elems = seed || byElement && Expr.find["TAG"]("*", outermost),
                      dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
                      len = elems.length;
  
                  if (outermost) {
                      outermostContext = context !== document && context;
                  }
  
                  for (; i !== len && (elem = elems[i]) != null; i++) {
                      if (byElement && elem) {
                          j = 0;
                          while ((matcher = elementMatchers[j++])) {
                              if (matcher(elem, context, xml)) {
                                  results.push(elem);
                                  break;
                              }
                          }
                          if (outermost) {
                              dirruns = dirrunsUnique;
                          }
                      }
  
                      if (bySet) {
                          if ((elem = !matcher && elem)) {
                              matchedCount--;
                          }
  
                          if (seed) {
                              unmatched.push(elem);
                          }
                      }
                  }
  
                  matchedCount += i;
                  if (bySet && i !== matchedCount) {
                      j = 0;
                      while ((matcher = setMatchers[j++])) {
                          matcher(unmatched, setMatched, context, xml);
                      }
  
                      if (seed) {
                          if (matchedCount > 0) {
                              while (i--) {
                                  if (!(unmatched[i] || setMatched[i])) {
                                      setMatched[i] = pop.call(results);
                                  }
                              }
                          }
  
                          setMatched = condense(setMatched);
                      }
  
                      push.apply(results, setMatched);
  
                      if (outermost && !seed && setMatched.length > 0 &&
                          (matchedCount + setMatchers.length) > 1) {
  
                          Sizzle.uniqueSort(results);
                      }
                  }
  
                  if (outermost) {
                      dirruns = dirrunsUnique;
                      outermostContext = contextBackup;
                  }
  
                  return unmatched;
              };
  
          return bySet ?
              markFunction(superMatcher) :
              superMatcher;
      }
  
      compile = Sizzle.compile = function (selector, match /* Internal Use Only */) {
          var i,
              setMatchers = [],
              elementMatchers = [],
              cached = compilerCache[selector + " "];
  
          if (!cached) {
              if (!match) {
                  match = tokenize(selector);
              }
              i = match.length;
              while (i--) {
                  cached = matcherFromTokens(match[i]);
                  if (cached[expando]) {
                      setMatchers.push(cached);
                  } else {
                      elementMatchers.push(cached);
                  }
              }
  
              cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
  
              cached.selector = selector;
          }
          return cached;
      };
  
      /**
       * A low-level selection function that works with Sizzle's compiled
       *  selector functions
       * @param {String|Function} selector A selector or a pre-compiled
       *  selector function built with Sizzle.compile
       * @param {Element} context
       * @param {Array} [results]
       * @param {Array} [seed] A set of elements to match against
       */
      select = Sizzle.select = function (selector, context, results, seed) {
          var i, tokens, token, type, find,
              compiled = typeof selector === "function" && selector,
              match = !seed && tokenize((selector = compiled.selector || selector));
  
          results = results || [];
  
          if (match.length === 1) {
  
              tokens = match[0] = match[0].slice(0);
              if (tokens.length > 2 && (token = tokens[0]).type === "ID" &&
                  support.getById && context.nodeType === 9 && documentIsHTML &&
                  Expr.relative[tokens[1].type]) {
  
                  context = (Expr.find["ID"](token.matches[0].replace(runescape, funescape), context) || [])[0];
                  if (!context) {
                      return results;
  
                  } else if (compiled) {
                      context = context.parentNode;
                  }
  
                  selector = selector.slice(tokens.shift().value.length);
              }
  
              i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length;
              while (i--) {
                  token = tokens[i];
  
                  if (Expr.relative[(type = token.type)]) {
                      break;
                  }
                  if ((find = Expr.find[type])) {
                      if ((seed = find(
                          token.matches[0].replace(runescape, funescape),
                          rsibling.test(tokens[0].type) && testContext(context.parentNode) || context
                      ))) {
  
                          tokens.splice(i, 1);
                          selector = seed.length && toSelector(tokens);
                          if (!selector) {
                              push.apply(results, seed);
                              return results;
                          }
  
                          break;
                      }
                  }
              }
          }
  
          (compiled || compile(selector, match))(
              seed,
              context,
              !documentIsHTML,
              results,
              rsibling.test(selector) && testContext(context.parentNode) || context
          );
          return results;
      };
  
  
      support.sortStable = expando.split("").sort(sortOrder).join("") === expando;
  
      support.detectDuplicates = !!hasDuplicate;
  
      setDocument();
  
      support.sortDetached = assert(function (div1) {
          return div1.compareDocumentPosition(document.createElement("div")) & 1;
      });
  
      if (!assert(function (div) {
          div.innerHTML = "<a href='#'></a>";
          return div.firstChild.getAttribute("href") === "#";
      })) {
          addHandle("type|href|height|width", function (elem, name, isXML) {
              if (!isXML) {
                  return elem.getAttribute(name, name.toLowerCase() === "type" ? 1 : 2);
              }
          });
      }
  
      if (!support.attributes || !assert(function (div) {
          div.innerHTML = "<input/>";
          div.firstChild.setAttribute("value", "");
          return div.firstChild.getAttribute("value") === "";
      })) {
          addHandle("value", function (elem, name, isXML) {
              if (!isXML && elem.nodeName.toLowerCase() === "input") {
                  return elem.defaultValue;
              }
          });
      }
  
      if (!assert(function (div) {
          return div.getAttribute("disabled") == null;
      })) {
          addHandle(booleans, function (elem, name, isXML) {
              var val;
              if (!isXML) {
                  return elem[name] === true ? name.toLowerCase() :
                      (val = elem.getAttributeNode(name)) && val.specified ?
                          val.value :
                          null;
              }
          });
      }
  
      if (typeof define === "function" && define.amd) {
          define(function () {
              return Sizzle;
          });
      } else if (typeof module !== "undefined" && module.exports) {
          module.exports = Sizzle;
      } else {
          window.Sizzle = Sizzle;
      }
  
  })(window);
  
  ;(function () {
      if (typeof Sizzle !== 'undefined') {
          return;
      }
  
      if (typeof define !== 'undefined' && define.amd) {
          window.Sizzle = Prototype._actual_sizzle;
          window.define = Prototype._original_define;
          delete Prototype._actual_sizzle;
          delete Prototype._original_define;
      } else if (typeof module !== 'undefined' && module.exports) {
          window.Sizzle = module.exports;
          module.exports = {};
      }
  })();
  
  ;(function (engine) {
      var extendElements = Prototype.Selector.extendElements;
  
      function select(selector, scope) {
          return extendElements(engine(selector, scope || document));
      }
  
      function match(element, selector) {
          return engine.matches(selector, [element]).length == 1;
      }
  
      Prototype.Selector.engine = engine;
      Prototype.Selector.select = select;
      Prototype.Selector.match = match;
  })(Sizzle);
  
  window.Sizzle = Prototype._original_property;
  delete Prototype._original_property;
  
  var Form = {
      reset: function (form) {
          form = $(form);
          form.reset();
          return form;
      },
  
      serializeElements: function (elements, options) {
          if (typeof options != 'object') options = {hash: !!options};
          else if (Object.isUndefined(options.hash)) options.hash = true;
          var key, value, submitted = false, submit = options.submit, accumulator, initial;
  
          if (options.hash) {
              initial = {};
              accumulator = function (result, key, value) {
                  if (key in result) {
                      if (!Object.isArray(result[key])) result[key] = [result[key]];
                      result[key] = result[key].concat(value);
                  } else result[key] = value;
                  return result;
              };
          } else {
              initial = '';
              accumulator = function (result, key, values) {
                  if (!Object.isArray(values)) {
                      values = [values];
                  }
                  if (!values.length) {
                      return result;
                  }
                  var encodedKey = encodeURIComponent(key).gsub(/%20/, '+');
                  return result + (result ? "&" : "") + values.map(function (value) {
                      value = value.gsub(/(\r)?\n/, '\r\n');
                      value = encodeURIComponent(value);
                      value = value.gsub(/%20/, '+');
                      return encodedKey + "=" + value;
                  }).join("&");
              };
          }
  
          return elements.inject(initial, function (result, element) {
              if (!element.disabled && element.name) {
                  key = element.name;
                  value = $(element).getValue();
                  if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
                      submit !== false && (!submit || key == submit) && (submitted = true)))) {
                      result = accumulator(result, key, value);
                  }
              }
              return result;
          });
      }
  };
  
  Form.Methods = {
      serialize: function (form, options) {
          return Form.serializeElements(Form.getElements(form), options);
      },
  
  
      getElements: function (form) {
          var elements = $(form).getElementsByTagName('*');
          var element, results = [], serializers = Form.Element.Serializers;
  
          for (var i = 0; element = elements[i]; i++) {
              if (serializers[element.tagName.toLowerCase()])
                  results.push(Element.extend(element));
          }
          return results;
      },
  
      getInputs: function (form, typeName, name) {
          form = $(form);
          var inputs = form.getElementsByTagName('input');
  
          if (!typeName && !name) return $A(inputs).map(Element.extend);
  
          for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
              var input = inputs[i];
              if ((typeName && input.type != typeName) || (name && input.name != name))
                  continue;
              matchingInputs.push(Element.extend(input));
          }
  
          return matchingInputs;
      },
  
      disable: function (form) {
          form = $(form);
          Form.getElements(form).invoke('disable');
          return form;
      },
  
      enable: function (form) {
          form = $(form);
          Form.getElements(form).invoke('enable');
          return form;
      },
  
      findFirstElement: function (form) {
          var elements = $(form).getElements().findAll(function (element) {
              return 'hidden' != element.type && !element.disabled;
          });
          var firstByIndex = elements.findAll(function (element) {
              return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
          }).sortBy(function (element) {
              return element.tabIndex
          }).first();
  
          return firstByIndex ? firstByIndex : elements.find(function (element) {
              return /^(?:input|select|textarea)$/i.test(element.tagName);
          });
      },
  
      focusFirstElement: function (form) {
          form = $(form);
          var element = form.findFirstElement();
          if (element) element.activate();
          return form;
      },
  
      request: function (form, options) {
          form = $(form), options = Object.clone(options || {});
  
          var params = options.parameters, action = form.readAttribute('action') || '';
          if (action.blank()) action = window.location.href;
          options.parameters = form.serialize(true);
  
          if (params) {
              if (Object.isString(params)) params = params.toQueryParams();
              Object.extend(options.parameters, params);
          }
  
          if (form.hasAttribute('method') && !options.method)
              options.method = form.method;
  
          return new Ajax.Request(action, options);
      }
  };
  
  /*--------------------------------------------------------------------------*/
  
  
  Form.Element = {
      focus: function (element) {
          $(element).focus();
          return element;
      },
  
      select: function (element) {
          $(element).select();
          return element;
      }
  };
  
  Form.Element.Methods = {
  
      serialize: function (element) {
          element = $(element);
          if (!element.disabled && element.name) {
              var value = element.getValue();
              if (value != undefined) {
                  var pair = {};
                  pair[element.name] = value;
                  return Object.toQueryString(pair);
              }
          }
          return '';
      },
  
      getValue: function (element) {
          element = $(element);
          var method = element.tagName.toLowerCase();
          return Form.Element.Serializers[method](element);
      },
  
      setValue: function (element, value) {
          element = $(element);
          var method = element.tagName.toLowerCase();
          Form.Element.Serializers[method](element, value);
          return element;
      },
  
      clear: function (element) {
          $(element).value = '';
          return element;
      },
  
      present: function (element) {
          return $(element).value != '';
      },
  
      activate: function (element) {
          element = $(element);
          try {
              element.focus();
              if (element.select && (element.tagName.toLowerCase() != 'input' ||
                  !(/^(?:button|reset|submit)$/i.test(element.type))))
                  element.select();
          } catch (e) {
          }
          return element;
      },
  
      disable: function (element) {
          element = $(element);
          element.disabled = true;
          return element;
      },
  
      enable: function (element) {
          element = $(element);
          element.disabled = false;
          return element;
      }
  };
  
  /*--------------------------------------------------------------------------*/
  
  var Field = Form.Element;
  
  var $F = Form.Element.Methods.getValue;
  
  /*--------------------------------------------------------------------------*/
  
  Form.Element.Serializers = (function () {
      function input(element, value) {
          switch (element.type.toLowerCase()) {
              case 'checkbox':
              case 'radio':
                  return inputSelector(element, value);
              default:
                  return valueSelector(element, value);
          }
      }
  
      function inputSelector(element, value) {
          if (Object.isUndefined(value))
              return element.checked ? element.value : null;
          else element.checked = !!value;
      }
  
      function valueSelector(element, value) {
          if (Object.isUndefined(value)) return element.value;
          else element.value = value;
      }
  
      function select(element, value) {
          if (Object.isUndefined(value))
              return (element.type === 'select-one' ? selectOne : selectMany)(element);
  
          var opt, currentValue, single = !Object.isArray(value);
          for (var i = 0, length = element.length; i < length; i++) {
              opt = element.options[i];
              currentValue = this.optionValue(opt);
              if (single) {
                  if (currentValue == value) {
                      opt.selected = true;
                      return;
                  }
              } else opt.selected = value.include(currentValue);
          }
      }
  
      function selectOne(element) {
          var index = element.selectedIndex;
          return index >= 0 ? optionValue(element.options[index]) : null;
      }
  
      function selectMany(element) {
          var values, length = element.length;
          if (!length) return null;
  
          for (var i = 0, values = []; i < length; i++) {
              var opt = element.options[i];
              if (opt.selected) values.push(optionValue(opt));
          }
          return values;
      }
  
      function optionValue(opt) {
          return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
      }
  
      return {
          input: input,
          inputSelector: inputSelector,
          textarea: valueSelector,
          select: select,
          selectOne: selectOne,
          selectMany: selectMany,
          optionValue: optionValue,
          button: valueSelector
      };
  })();
  
  /*--------------------------------------------------------------------------*/
  
  
  Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
      initialize: function ($super, element, frequency, callback) {
          $super(callback, frequency);
          this.element = $(element);
          this.lastValue = this.getValue();
      },
  
      execute: function () {
          var value = this.getValue();
          if (Object.isString(this.lastValue) && Object.isString(value) ?
              this.lastValue != value : String(this.lastValue) != String(value)) {
              this.callback(this.element, value);
              this.lastValue = value;
          }
      }
  });
  
  Form.Element.Observer = Class.create(Abstract.TimedObserver, {
      getValue: function () {
          return Form.Element.getValue(this.element);
      }
  });
  
  Form.Observer = Class.create(Abstract.TimedObserver, {
      getValue: function () {
          return Form.serialize(this.element);
      }
  });
  
  /*--------------------------------------------------------------------------*/
  
  Abstract.EventObserver = Class.create({
      initialize: function (element, callback) {
          this.element = $(element);
          this.callback = callback;
  
          this.lastValue = this.getValue();
          if (this.element.tagName.toLowerCase() == 'form')
              this.registerFormCallbacks();
          else
              this.registerCallback(this.element);
      },
  
      onElementEvent: function () {
          var value = this.getValue();
          if (this.lastValue != value) {
              this.callback(this.element, value);
              this.lastValue = value;
          }
      },
  
      registerFormCallbacks: function () {
          Form.getElements(this.element).each(this.registerCallback, this);
      },
  
      registerCallback: function (element) {
          if (element.type) {
              switch (element.type.toLowerCase()) {
                  case 'checkbox':
                  case 'radio':
                      Event.observe(element, 'click', this.onElementEvent.bind(this));
                      break;
                  default:
                      Event.observe(element, 'change', this.onElementEvent.bind(this));
                      break;
              }
          }
      }
  });
  
  Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
      getValue: function () {
          return Form.Element.getValue(this.element);
      }
  });
  
  Form.EventObserver = Class.create(Abstract.EventObserver, {
      getValue: function () {
          return Form.serialize(this.element);
      }
  });
  (function (GLOBAL) {
      var DIV = document.createElement('div');
      var docEl = document.documentElement;
      var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
          && 'onmouseleave' in docEl;
  
      var Event = {
          KEY_BACKSPACE: 8,
          KEY_TAB: 9,
          KEY_RETURN: 13,
          KEY_ESC: 27,
          KEY_LEFT: 37,
          KEY_UP: 38,
          KEY_RIGHT: 39,
          KEY_DOWN: 40,
          KEY_DELETE: 46,
          KEY_HOME: 36,
          KEY_END: 35,
          KEY_PAGEUP: 33,
          KEY_PAGEDOWN: 34,
          KEY_INSERT: 45
      };
  
  
      var isIELegacyEvent = function (event) {
          return false;
      };
  
      if (window.attachEvent) {
          if (window.addEventListener) {
              isIELegacyEvent = function (event) {
                  return !(event instanceof window.Event);
              };
          } else {
              isIELegacyEvent = function (event) {
                  return true;
              };
          }
      }
  
      var _isButton;
  
      function _isButtonForDOMEvents(event, code) {
          return event.which ? (event.which === code + 1) : (event.button === code);
      }
  
      var legacyButtonMap = {0: 1, 1: 4, 2: 2};
  
      function _isButtonForLegacyEvents(event, code) {
          return event.button === legacyButtonMap[code];
      }
  
      function _isButtonForWebKit(event, code) {
          switch (code) {
              case 0:
                  return event.which == 1 && !event.metaKey;
              case 1:
                  return event.which == 2 || (event.which == 1 && event.metaKey);
              case 2:
                  return event.which == 3;
              default:
                  return false;
          }
      }
  
      if (window.attachEvent) {
          if (!window.addEventListener) {
              _isButton = _isButtonForLegacyEvents;
          } else {
              _isButton = function (event, code) {
                  return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
                      _isButtonForDOMEvents(event, code);
              }
          }
      } else if (Prototype.Browser.WebKit) {
          _isButton = _isButtonForWebKit;
      } else {
          _isButton = _isButtonForDOMEvents;
      }
  
      function isLeftClick(event) {
          return _isButton(event, 0)
      }
  
      function isMiddleClick(event) {
          return _isButton(event, 1)
      }
  
      function isRightClick(event) {
          return _isButton(event, 2)
      }
  
      function element(event) {
          return Element.extend(_element(event));
      }
  
      function _element(event) {
          event = Event.extend(event);
  
          var node = event.target, type = event.type,
              currentTarget = event.currentTarget;
  
          if (currentTarget && currentTarget.tagName) {
              if (type === 'load' || type === 'error' ||
                  (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
                      && currentTarget.type === 'radio'))
                  node = currentTarget;
          }
  
          return node.nodeType == Node.TEXT_NODE ? node.parentNode : node;
      }
  
      function findElement(event, expression) {
          var element = _element(event), selector = Prototype.Selector;
          if (!expression) return Element.extend(element);
          while (element) {
              if (Object.isElement(element) && selector.match(element, expression))
                  return Element.extend(element);
              element = element.parentNode;
          }
      }
  
      function pointer(event) {
          return {x: pointerX(event), y: pointerY(event)};
      }
  
      function pointerX(event) {
          var docElement = document.documentElement,
              body = document.body || {scrollLeft: 0};
  
          return event.pageX || (event.clientX +
              (docElement.scrollLeft || body.scrollLeft) -
              (docElement.clientLeft || 0));
      }
  
      function pointerY(event) {
          var docElement = document.documentElement,
              body = document.body || {scrollTop: 0};
  
          return event.pageY || (event.clientY +
              (docElement.scrollTop || body.scrollTop) -
              (docElement.clientTop || 0));
      }
  
  
      function stop(event) {
          Event.extend(event);
          event.preventDefault();
          event.stopPropagation();
  
          event.stopped = true;
      }
  
  
      Event.Methods = {
          isLeftClick: isLeftClick,
          isMiddleClick: isMiddleClick,
          isRightClick: isRightClick,
  
          element: element,
          findElement: findElement,
  
          pointer: pointer,
          pointerX: pointerX,
          pointerY: pointerY,
  
          stop: stop
      };
  
      var methods = Object.keys(Event.Methods).inject({}, function (m, name) {
          m[name] = Event.Methods[name].methodize();
          return m;
      });
  
      if (window.attachEvent) {
          function _relatedTarget(event) {
              var element;
              switch (event.type) {
                  case 'mouseover':
                  case 'mouseenter':
                      element = event.fromElement;
                      break;
                  case 'mouseout':
                  case 'mouseleave':
                      element = event.toElement;
                      break;
                  default:
                      return null;
              }
              return Element.extend(element);
          }
  
          var additionalMethods = {
              stopPropagation: function () {
                  this.cancelBubble = true
              },
              preventDefault: function () {
                  this.returnValue = false
              },
              inspect: function () {
                  return '[object Event]'
              }
          };
  
          Event.extend = function (event, element) {
              if (!event) return false;
  
              if (!isIELegacyEvent(event)) return event;
  
              if (event._extendedByPrototype) return event;
              event._extendedByPrototype = Prototype.emptyFunction;
  
              var pointer = Event.pointer(event);
  
              Object.extend(event, {
                  target: event.srcElement || element,
                  relatedTarget: _relatedTarget(event),
                  pageX: pointer.x,
                  pageY: pointer.y
              });
  
              Object.extend(event, methods);
              Object.extend(event, additionalMethods);
  
              return event;
          };
      } else {
          Event.extend = Prototype.K;
      }
  
      if (window.addEventListener) {
          Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
          Object.extend(Event.prototype, methods);
      }
  
      var EVENT_TRANSLATIONS = {
          mouseenter: 'mouseover',
          mouseleave: 'mouseout'
      };
  
      function getDOMEventName(eventName) {
          return EVENT_TRANSLATIONS[eventName] || eventName;
      }
  
      if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED)
          getDOMEventName = Prototype.K;
  
      function getUniqueElementID(element) {
          if (element === window) return 0;
  
          if (typeof element._prototypeUID === 'undefined')
              element._prototypeUID = Element.Storage.UID++;
          return element._prototypeUID;
      }
  
      function getUniqueElementID_IE(element) {
          if (element === window) return 0;
          if (element == document) return 1;
          return element.uniqueID;
      }
  
      if ('uniqueID' in DIV)
          getUniqueElementID = getUniqueElementID_IE;
  
      function isCustomEvent(eventName) {
          return eventName.include(':');
      }
  
      Event._isCustomEvent = isCustomEvent;
  
      function getOrCreateRegistryFor(element, uid) {
          var CACHE = GLOBAL.Event.cache;
          if (Object.isUndefined(uid))
              uid = getUniqueElementID(element);
          if (!CACHE[uid]) CACHE[uid] = {element: element};
          return CACHE[uid];
      }
  
      function destroyRegistryForElement(element, uid) {
          if (Object.isUndefined(uid))
              uid = getUniqueElementID(element);
          delete GLOBAL.Event.cache[uid];
      }
  
  
      function register(element, eventName, handler) {
          var registry = getOrCreateRegistryFor(element);
          if (!registry[eventName]) registry[eventName] = [];
          var entries = registry[eventName];
  
          var i = entries.length;
          while (i--)
              if (entries[i].handler === handler) return null;
  
          var uid = getUniqueElementID(element);
          var responder = GLOBAL.Event._createResponder(uid, eventName, handler);
          var entry = {
              responder: responder,
              handler: handler
          };
  
          entries.push(entry);
          return entry;
      }
  
      function unregister(element, eventName, handler) {
          var registry = getOrCreateRegistryFor(element);
          var entries = registry[eventName] || [];
  
          var i = entries.length, entry;
          while (i--) {
              if (entries[i].handler === handler) {
                  entry = entries[i];
                  break;
              }
          }
  
          if (entry) {
              var index = entries.indexOf(entry);
              entries.splice(index, 1);
          }
  
          if (entries.length === 0) {
              delete registry[eventName];
              if (Object.keys(registry).length === 1 && ('element' in registry))
                  destroyRegistryForElement(element);
          }
  
          return entry;
      }
  
  
      function observe(element, eventName, handler) {
          element = $(element);
          var entry = register(element, eventName, handler);
  
          if (entry === null) return element;
  
          var responder = entry.responder;
          if (isCustomEvent(eventName))
              observeCustomEvent(element, eventName, responder);
          else
              observeStandardEvent(element, eventName, responder);
  
          return element;
      }
  
      function observeStandardEvent(element, eventName, responder) {
          var actualEventName = getDOMEventName(eventName);
          if (element.addEventListener) {
              element.addEventListener(actualEventName, responder, false);
          } else {
              element.attachEvent('on' + actualEventName, responder);
          }
      }
  
      function observeCustomEvent(element, eventName, responder) {
          if (element.addEventListener) {
              element.addEventListener('dataavailable', responder, false);
          } else {
              element.attachEvent('ondataavailable', responder);
              element.attachEvent('onlosecapture', responder);
          }
      }
  
      function stopObserving(element, eventName, handler) {
          element = $(element);
          var handlerGiven = !Object.isUndefined(handler),
              eventNameGiven = !Object.isUndefined(eventName);
  
          if (!eventNameGiven && !handlerGiven) {
              stopObservingElement(element);
              return element;
          }
  
          if (!handlerGiven) {
              stopObservingEventName(element, eventName);
              return element;
          }
  
          var entry = unregister(element, eventName, handler);
  
          if (!entry) return element;
          removeEvent(element, eventName, entry.responder);
          return element;
      }
  
      function stopObservingStandardEvent(element, eventName, responder) {
          var actualEventName = getDOMEventName(eventName);
          if (element.removeEventListener) {
              element.removeEventListener(actualEventName, responder, false);
          } else {
              element.detachEvent('on' + actualEventName, responder);
          }
      }
  
      function stopObservingCustomEvent(element, eventName, responder) {
          if (element.removeEventListener) {
              element.removeEventListener('dataavailable', responder, false);
          } else {
              element.detachEvent('ondataavailable', responder);
              element.detachEvent('onlosecapture', responder);
          }
      }
  
  
      function stopObservingElement(element) {
          var uid = getUniqueElementID(element), registry = GLOBAL.Event.cache[uid];
          if (!registry) return;
  
          destroyRegistryForElement(element, uid);
  
          var entries, i;
          for (var eventName in registry) {
              if (eventName === 'element') continue;
  
              entries = registry[eventName];
              i = entries.length;
              while (i--)
                  removeEvent(element, eventName, entries[i].responder);
          }
      }
  
      function stopObservingEventName(element, eventName) {
          var registry = getOrCreateRegistryFor(element);
          var entries = registry[eventName];
          if (entries) {
              delete registry[eventName];
          }
  
          entries = entries || [];
  
          var i = entries.length;
          while (i--)
              removeEvent(element, eventName, entries[i].responder);
  
          for (var name in registry) {
              if (name === 'element') continue;
              return; // There is another registered event
          }
  
          destroyRegistryForElement(element);
      }
  
  
      function removeEvent(element, eventName, handler) {
          if (isCustomEvent(eventName))
              stopObservingCustomEvent(element, eventName, handler);
          else
              stopObservingStandardEvent(element, eventName, handler);
      }
  
  
      function getFireTarget(element) {
          if (element !== document) return element;
          if (document.createEvent && !element.dispatchEvent)
              return document.documentElement;
          return element;
      }
  
      function fire(element, eventName, memo, bubble) {
          element = getFireTarget($(element));
          if (Object.isUndefined(bubble)) bubble = true;
          memo = memo || {};
  
          var event = fireEvent(element, eventName, memo, bubble);
          return Event.extend(event);
      }
  
      function fireEvent_DOM(element, eventName, memo, bubble) {
          var event = document.createEvent('HTMLEvents');
          event.initEvent('dataavailable', bubble, true);
  
          event.eventName = eventName;
          event.memo = memo;
  
          element.dispatchEvent(event);
          return event;
      }
  
      function fireEvent_IE(element, eventName, memo, bubble) {
          var event = document.createEventObject();
          event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
  
          event.eventName = eventName;
          event.memo = memo;
  
          element.fireEvent(event.eventType, event);
          return event;
      }
  
      var fireEvent = document.createEvent ? fireEvent_DOM : fireEvent_IE;
  
  
      Event.Handler = Class.create({
          initialize: function (element, eventName, selector, callback) {
              this.element = $(element);
              this.eventName = eventName;
              this.selector = selector;
              this.callback = callback;
              this.handler = this.handleEvent.bind(this);
          },
  
  
          start: function () {
              Event.observe(this.element, this.eventName, this.handler);
              return this;
          },
  
          stop: function () {
              Event.stopObserving(this.element, this.eventName, this.handler);
              return this;
          },
  
          handleEvent: function (event) {
              var element = Event.findElement(event, this.selector);
              if (element) this.callback.call(this.element, event, element);
          }
      });
  
      function on(element, eventName, selector, callback) {
          element = $(element);
          if (Object.isFunction(selector) && Object.isUndefined(callback)) {
              callback = selector, selector = null;
          }
  
          return new Event.Handler(element, eventName, selector, callback).start();
      }
  
      Object.extend(Event, Event.Methods);
  
      Object.extend(Event, {
          fire: fire,
          observe: observe,
          stopObserving: stopObserving,
          on: on
      });
  
      Element.addMethods({
          fire: fire,
  
          observe: observe,
  
          stopObserving: stopObserving,
  
          on: on
      });
  
      Object.extend(document, {
          fire: fire.methodize(),
  
          observe: observe.methodize(),
  
          stopObserving: stopObserving.methodize(),
  
          on: on.methodize(),
  
          loaded: false
      });
  
      if (GLOBAL.Event) Object.extend(window.Event, Event);
      else GLOBAL.Event = Event;
  
      GLOBAL.Event.cache = {};
  
      function destroyCache_IE() {
          GLOBAL.Event.cache = null;
      }
  
      if (window.attachEvent)
          window.attachEvent('onunload', destroyCache_IE);
  
      DIV = null;
      docEl = null;
  })(this);
  
  (function (GLOBAL) {
      /* Code for creating leak-free event responders is based on work by
     John-David Dalton. */
  
      var docEl = document.documentElement;
      var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
          && 'onmouseleave' in docEl;
  
      function isSimulatedMouseEnterLeaveEvent(eventName) {
          return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
              (eventName === 'mouseenter' || eventName === 'mouseleave');
      }
  
      function createResponder(uid, eventName, handler) {
          if (Event._isCustomEvent(eventName))
              return createResponderForCustomEvent(uid, eventName, handler);
          if (isSimulatedMouseEnterLeaveEvent(eventName))
              return createMouseEnterLeaveResponder(uid, eventName, handler);
  
          return function (event) {
              if (!Event.cache) return;
  
              var element = Event.cache[uid].element;
              Event.extend(event, element);
              handler.call(element, event);
          };
      }
  
      function createResponderForCustomEvent(uid, eventName, handler) {
          return function (event) {
              var cache = Event.cache[uid];
              var element = cache && cache.element;
  
              if (Object.isUndefined(event.eventName))
                  return false;
  
              if (event.eventName !== eventName)
                  return false;
  
              Event.extend(event, element);
              handler.call(element, event);
          };
      }
  
      function createMouseEnterLeaveResponder(uid, eventName, handler) {
          return function (event) {
              var element = Event.cache[uid].element;
  
              Event.extend(event, element);
              var parent = event.relatedTarget;
  
              while (parent && parent !== element) {
                  try {
                      parent = parent.parentNode;
                  } catch (e) {
                      parent = element;
                  }
              }
  
              if (parent === element) return;
              handler.call(element, event);
          }
      }
  
      GLOBAL.Event._createResponder = createResponder;
      docEl = null;
  })(this);
  
  (function (GLOBAL) {
      /* Support for the DOMContentLoaded event is based on work by Dan Webb,
       Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
  
      var TIMER;
  
      function fireContentLoadedEvent() {
          if (document.loaded) return;
          if (TIMER) window.clearTimeout(TIMER);
          document.loaded = true;
          document.fire('dom:loaded');
      }
  
      function checkReadyState() {
          if (document.readyState === 'complete') {
              document.detachEvent('onreadystatechange', checkReadyState);
              fireContentLoadedEvent();
          }
      }
  
      function pollDoScroll() {
          try {
              document.documentElement.doScroll('left');
          } catch (e) {
              TIMER = pollDoScroll.defer();
              return;
          }
  
          fireContentLoadedEvent();
      }
  
  
      if (document.readyState === 'complete') {
          fireContentLoadedEvent();
          return;
      }
  
      if (document.addEventListener) {
          document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
      } else {
          document.attachEvent('onreadystatechange', checkReadyState);
          if (window == top) TIMER = pollDoScroll.defer();
      }
  
      Event.observe(window, 'load', fireContentLoadedEvent);
  })(this);
  
  
  Element.addMethods();
  /*------------------------------- DEPRECATED -------------------------------*/
  
  Hash.toQueryString = Object.toQueryString;
  
  var Toggle = {display: Element.toggle};
  
  Element.addMethods({
      childOf: Element.Methods.descendantOf
  });
  
  var Insertion = {
      Before: function (element, content) {
          return Element.insert(element, {before: content});
      },
  
      Top: function (element, content) {
          return Element.insert(element, {top: content});
      },
  
      Bottom: function (element, content) {
          return Element.insert(element, {bottom: content});
      },
  
      After: function (element, content) {
          return Element.insert(element, {after: content});
      }
  };
  
  var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
  
  var Position = {
      includeScrollOffsets: false,
  
      prepare: function () {
          this.deltaX = window.pageXOffset
              || document.documentElement.scrollLeft
              || document.body.scrollLeft
              || 0;
          this.deltaY = window.pageYOffset
              || document.documentElement.scrollTop
              || document.body.scrollTop
              || 0;
      },
  
      within: function (element, x, y) {
          if (this.includeScrollOffsets)
              return this.withinIncludingScrolloffsets(element, x, y);
          this.xcomp = x;
          this.ycomp = y;
          this.offset = Element.cumulativeOffset(element);
  
          return (y >= this.offset[1] &&
              y < this.offset[1] + element.offsetHeight &&
              x >= this.offset[0] &&
              x < this.offset[0] + element.offsetWidth);
      },
  
      withinIncludingScrolloffsets: function (element, x, y) {
          var offsetcache = Element.cumulativeScrollOffset(element);
  
          this.xcomp = x + offsetcache[0] - this.deltaX;
          this.ycomp = y + offsetcache[1] - this.deltaY;
          this.offset = Element.cumulativeOffset(element);
  
          return (this.ycomp >= this.offset[1] &&
              this.ycomp < this.offset[1] + element.offsetHeight &&
              this.xcomp >= this.offset[0] &&
              this.xcomp < this.offset[0] + element.offsetWidth);
      },
  
      overlap: function (mode, element) {
          if (!mode) return 0;
          if (mode == 'vertical')
              return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
                  element.offsetHeight;
          if (mode == 'horizontal')
              return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
                  element.offsetWidth;
      },
  
  
      cumulativeOffset: Element.Methods.cumulativeOffset,
  
      positionedOffset: Element.Methods.positionedOffset,
  
      absolutize: function (element) {
          Position.prepare();
          return Element.absolutize(element);
      },
  
      relativize: function (element) {
          Position.prepare();
          return Element.relativize(element);
      },
  
      realOffset: Element.Methods.cumulativeScrollOffset,
  
      offsetParent: Element.Methods.getOffsetParent,
  
      page: Element.Methods.viewportOffset,
  
      clone: function (source, target, options) {
          options = options || {};
          return Element.clonePosition(target, source, options);
      }
  };
  
  /*--------------------------------------------------------------------------*/
  
  if (!document.getElementsByClassName) document.getElementsByClassName = function (instanceMethods) {
      function iter(name) {
          return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
      }
  
      instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
          function (element, className) {
              className = className.toString().strip();
              var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
              return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
          } : function (element, className) {
              className = className.toString().strip();
              var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
              if (!classNames && !className) return elements;
  
              var nodes = $(element).getElementsByTagName('*');
              className = ' ' + className + ' ';
  
              for (var i = 0, child, cn; child = nodes[i]; i++) {
                  if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
                      (classNames && classNames.all(function (name) {
                          return !name.toString().blank() && cn.include(' ' + name + ' ');
                      }))))
                      elements.push(Element.extend(child));
              }
              return elements;
          };
  
      return function (className, parentElement) {
          return $(parentElement || document.body).getElementsByClassName(className);
      };
  }(Element.Methods);
  
  /*--------------------------------------------------------------------------*/
  
  Element.ClassNames = Class.create();
  Element.ClassNames.prototype = {
      initialize: function (element) {
          this.element = $(element);
      },
  
      _each: function (iterator, context) {
          this.element.className.split(/\s+/).select(function (name) {
              return name.length > 0;
          })._each(iterator, context);
      },
  
      set: function (className) {
          this.element.className = className;
      },
  
      add: function (classNameToAdd) {
          if (this.include(classNameToAdd)) return;
          this.set($A(this).concat(classNameToAdd).join(' '));
      },
  
      remove: function (classNameToRemove) {
          if (!this.include(classNameToRemove)) return;
          this.set($A(this).without(classNameToRemove).join(' '));
      },
  
      toString: function () {
          return $A(this).join(' ');
      }
  };
  
  Object.extend(Element.ClassNames.prototype, Enumerable);
  
  /*--------------------------------------------------------------------------*/
  
  (function () {
      window.Selector = Class.create({
          initialize: function (expression) {
              this.expression = expression.strip();
          },
  
          findElements: function (rootElement) {
              return Prototype.Selector.select(this.expression, rootElement);
          },
  
          match: function (element) {
              return Prototype.Selector.match(element, this.expression);
          },
  
          toString: function () {
              return this.expression;
          },
  
          inspect: function () {
              return "#<Selector: " + this.expression + ">";
          }
      });
  
      Object.extend(Selector, {
          matchElements: function (elements, expression) {
              var match = Prototype.Selector.match,
                  results = [];
  
              for (var i = 0, length = elements.length; i < length; i++) {
                  var element = elements[i];
                  if (match(element, expression)) {
                      results.push(Element.extend(element));
                  }
              }
              return results;
          },
  
          findElement: function (elements, expression, index) {
              index = index || 0;
              var matchIndex = 0, element;
              for (var i = 0, length = elements.length; i < length; i++) {
                  element = elements[i];
                  if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
                      return Element.extend(element);
                  }
              }
          },
  
          findChildElements: function (element, expressions) {
              var selector = expressions.toArray().join(', ');
              return Prototype.Selector.select(selector, element || document);
          }
      });
  })();
  