OSDN Git Service

setup spinelz environment
[cloudmanganw/git_repo.git] / war / WEB-INF / classes / jp / sourceforge / manganetwork / page / javascripts / spinelz_lib / prototype.js
index 14edec8..73f5340 100644 (file)
-/*  Prototype JavaScript framework, version 1.5.0_rc1
- *  (c) 2005 Sam Stephenson <sam@conio.net>
- *
- *  Prototype is freely distributable under the terms of an MIT-style license.
- *  For details, see the Prototype web site: http://prototype.conio.net/
- *
-/*--------------------------------------------------------------------------*/
-
-var Prototype = {
-  Version: '1.5.0_rc1',
-  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
-
-  emptyFunction: function() {},
-  K: function(x) {return x}
-}
-
-var Class = {
-  create: function() {
-    return function() {
-      this.initialize.apply(this, arguments);
-    }
-  }
-}
-
-var Abstract = new Object();
-
-Object.extend = function(destination, source) {
-  for (var property in source) {
-    destination[property] = source[property];
-  }
-  return destination;
-}
-
-Object.extend(Object, {
-  inspect: function(object) {
-    try {
-      if (object == undefined) return 'undefined';
-      if (object == null) return 'null';
-      return object.inspect ? object.inspect() : object.toString();
-    } catch (e) {
-      if (e instanceof RangeError) return '...';
-      throw e;
-    }
-  },
-
-  keys: function(object) {
-    var keys = [];
-    for (var property in object)
-      keys.push(property);
-    return keys;
-  },
-
-  values: function(object) {
-    var values = [];
-    for (var property in object)
-      values.push(object[property]);
-    return values;
-  },
-
-  clone: function(object) {
-    return Object.extend({}, object);
-  }
-});
-
-Function.prototype.bind = function() {
-  var __method = this, args = $A(arguments), object = args.shift();
-  return function() {
-    return __method.apply(object, args.concat($A(arguments)));
-  }
-}
-
-Function.prototype.bindAsEventListener = function(object) {
-  var __method = this, args = $A(arguments), object = args.shift();
-  return function(event) {
-    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
-  }
-}
-
-Object.extend(Number.prototype, {
-  toColorPart: function() {
-    var digits = this.toString(16);
-    if (this < 16) return '0' + digits;
-    return digits;
-  },
-
-  succ: function() {
-    return this + 1;
-  },
-
-  times: function(iterator) {
-    $R(0, this, true).each(iterator);
-    return this;
-  }
-});
-
-var Try = {
-  these: function() {
-    var returnValue;
-
-    for (var i = 0; i < arguments.length; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) {}
-    }
-
-    return returnValue;
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var PeriodicalExecuter = Class.create();
-PeriodicalExecuter.prototype = {
-  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);
-  },
-
-  stop: function() {
-    if (!this.timer) return;
-    clearInterval(this.timer);
-    this.timer = null;
-  },
-
-  onTimerEvent: function() {
-    if (!this.currentlyExecuting) {
-      try {
-        this.currentlyExecuting = true;
-        this.callback(this);
-      } finally {
-        this.currentlyExecuting = false;
-      }
-    }
-  }
-}
-Object.extend(String.prototype, {
-  gsub: function(pattern, replacement) {
-    var result = '', source = this, match;
-    replacement = arguments.callee.prepareReplacement(replacement);
-
-    while (source.length > 0) {
-      if (match = source.match(pattern)) {
-        result += source.slice(0, match.index);
-        result += (replacement(match) || '').toString();
-        source  = source.slice(match.index + match[0].length);
-      } else {
-        result += source, source = '';
-      }
-    }
-    return result;
-  },
-
-  sub: function(pattern, replacement, count) {
-    replacement = this.gsub.prepareReplacement(replacement);
-    count = count === undefined ? 1 : count;
-
-    return this.gsub(pattern, function(match) {
-      if (--count < 0) return match[0];
-      return replacement(match);
-    });
-  },
-
-  scan: function(pattern, iterator) {
-    this.gsub(pattern, iterator);
-    return this;
-  },
-
-  truncate: function(length, truncation) {
-    length = length || 30;
-    truncation = truncation === undefined ? '...' : truncation;
-    return this.length > length ?
-      this.slice(0, length - truncation.length) + truncation : this;
-  },
-
-  strip: function() {
-    return this.replace(/^\s+/, '').replace(/\s+$/, '');
-  },
-
-  stripTags: function() {
-    return this.replace(/<\/?[^>]+>/gi, '');
-  },
-
-  stripScripts: function() {
-    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
-  },
-
-  extractScripts: function() {
-    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
-    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
-    return (this.match(matchAll) || []).map(function(scriptTag) {
-      return (scriptTag.match(matchOne) || ['', ''])[1];
-    });
-  },
-
-  evalScripts: function() {
-    return this.extractScripts().map(function(script) { return eval(script) });
-  },
-
-  escapeHTML: function() {
-    var div = document.createElement('div');
-    var text = document.createTextNode(this);
-    div.appendChild(text);
-    return div.innerHTML;
-  },
-
-  unescapeHTML: function() {
-    var div = document.createElement('div');
-    div.innerHTML = this.stripTags();
-    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
-  },
-
-  toQueryParams: function() {
-    var pairs = this.match(/^\??(.*)$/)[1].split('&');
-    return pairs.inject({}, function(params, pairString) {
-      var pair  = pairString.split('=');
-      var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
-      params[decodeURIComponent(pair[0])] = value;
-      return params;
-    });
-  },
-
-  toArray: function() {
-    return this.split('');
-  },
-
-  camelize: function() {
-    var oStringList = this.split('-');
-    if (oStringList.length == 1) return oStringList[0];
-
-    var camelizedString = this.indexOf('-') == 0
-      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
-      : oStringList[0];
-
-    for (var i = 1, len = oStringList.length; i < len; i++) {
-      var s = oStringList[i];
-      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
-    }
-
-    return camelizedString;
-  },
-
-  inspect: function(useDoubleQuotes) {
-    var escapedString = this.replace(/\\/g, '\\\\');
-    if (useDoubleQuotes)
-      return '"' + escapedString.replace(/"/g, '\\"') + '"';
-    else
-      return "'" + escapedString.replace(/'/g, '\\\'') + "'";
-  }
-});
-
-String.prototype.gsub.prepareReplacement = function(replacement) {
-  if (typeof replacement == 'function') return replacement;
-  var template = new Template(replacement);
-  return function(match) { return template.evaluate(match) };
-}
-
-String.prototype.parseQuery = String.prototype.toQueryParams;
-
-var Template = Class.create();
-Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
-Template.prototype = {
-  initialize: function(template, pattern) {
-    this.template = template.toString();
-    this.pattern  = pattern || Template.Pattern;
-  },
-
-  evaluate: function(object) {
-    return this.template.gsub(this.pattern, function(match) {
-      var before = match[1];
-      if (before == '\\') return match[2];
-      return before + (object[match[3]] || '').toString();
-    });
-  }
-}
-
-var $break    = new Object();
-var $continue = new Object();
-
-var Enumerable = {
-  each: function(iterator) {
-    var index = 0;
-    try {
-      this._each(function(value) {
-        try {
-          iterator(value, index++);
-        } catch (e) {
-          if (e != $continue) throw e;
-        }
-      });
-    } catch (e) {
-      if (e != $break) throw e;
-    }
-  },
-
-  all: function(iterator) {
-    var result = true;
-    this.each(function(value, index) {
-      result = result && !!(iterator || Prototype.K)(value, index);
-      if (!result) throw $break;
-    });
-    return result;
-  },
-
-  any: function(iterator) {
-    var result = false;
-    this.each(function(value, index) {
-      if (result = !!(iterator || Prototype.K)(value, index))
-        throw $break;
-    });
-    return result;
-  },
-
-  collect: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      results.push(iterator(value, index));
-    });
-    return results;
-  },
-
-  detect: function (iterator) {
-    var result;
-    this.each(function(value, index) {
-      if (iterator(value, index)) {
-        result = value;
-        throw $break;
-      }
-    });
-    return result;
-  },
-
-  findAll: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      if (iterator(value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  grep: function(pattern, iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      var stringValue = value.toString();
-      if (stringValue.match(pattern))
-        results.push((iterator || Prototype.K)(value, index));
-    })
-    return results;
-  },
-
-  include: function(object) {
-    var found = false;
-    this.each(function(value) {
-      if (value == object) {
-        found = true;
-        throw $break;
-      }
-    });
-    return found;
-  },
-
-  inject: function(memo, iterator) {
-    this.each(function(value, index) {
-      memo = iterator(memo, value, index);
-    });
-    return memo;
-  },
-
-  invoke: function(method) {
-    var args = $A(arguments).slice(1);
-    return this.collect(function(value) {
-      return value[method].apply(value, args);
-    });
-  },
-
-  max: function(iterator) {
-    var result;
-    this.each(function(value, index) {
-      value = (iterator || Prototype.K)(value, index);
-      if (result == undefined || value >= result)
-        result = value;
-    });
-    return result;
-  },
-
-  min: function(iterator) {
-    var result;
-    this.each(function(value, index) {
-      value = (iterator || Prototype.K)(value, index);
-      if (result == undefined || value < result)
-        result = value;
-    });
-    return result;
-  },
-
-  partition: function(iterator) {
-    var trues = [], falses = [];
-    this.each(function(value, index) {
-      ((iterator || Prototype.K)(value, index) ?
-        trues : falses).push(value);
-    });
-    return [trues, falses];
-  },
-
-  pluck: function(property) {
-    var results = [];
-    this.each(function(value, index) {
-      results.push(value[property]);
-    });
-    return results;
-  },
-
-  reject: function(iterator) {
-    var results = [];
-    this.each(function(value, index) {
-      if (!iterator(value, index))
-        results.push(value);
-    });
-    return results;
-  },
-
-  sortBy: function(iterator) {
-    return this.collect(function(value, index) {
-      return {value: value, criteria: iterator(value, index)};
-    }).sort(function(left, right) {
-      var a = left.criteria, b = right.criteria;
-      return a < b ? -1 : a > b ? 1 : 0;
-    }).pluck('value');
-  },
-
-  toArray: function() {
-    return this.collect(Prototype.K);
-  },
-
-  zip: function() {
-    var iterator = Prototype.K, args = $A(arguments);
-    if (typeof args.last() == 'function')
-      iterator = args.pop();
-
-    var collections = [this].concat(args).map($A);
-    return this.map(function(value, index) {
-      return iterator(collections.pluck(index));
-    });
-  },
-
-  inspect: function() {
-    return '#<Enumerable:' + this.toArray().inspect() + '>';
-  }
-}
-
-Object.extend(Enumerable, {
-  map:     Enumerable.collect,
-  find:    Enumerable.detect,
-  select:  Enumerable.findAll,
-  member:  Enumerable.include,
-  entries: Enumerable.toArray
-});
-var $A = Array.from = function(iterable) {
-  if (!iterable) return [];
-  if (iterable.toArray) {
-    return iterable.toArray();
-  } else {
-    var results = [];
-    for (var i = 0; i < iterable.length; i++)
-      results.push(iterable[i]);
-    return results;
-  }
-}
-
-Object.extend(Array.prototype, Enumerable);
-
-if (!Array.prototype._reverse)
-  Array.prototype._reverse = Array.prototype.reverse;
-
-Object.extend(Array.prototype, {
-  _each: function(iterator) {
-    for (var i = 0; i < this.length; i++)
-      iterator(this[i]);
-  },
-
-  clear: function() {
-    this.length = 0;
-    return this;
-  },
-
-  first: function() {
-    return this[0];
-  },
-
-  last: function() {
-    return this[this.length - 1];
-  },
-
-  compact: function() {
-    return this.select(function(value) {
-      return value != undefined || value != null;
-    });
-  },
-
-  flatten: function() {
-    return this.inject([], function(array, value) {
-      return array.concat(value && value.constructor == Array ?
-        value.flatten() : [value]);
-    });
-  },
-
-  without: function() {
-    var values = $A(arguments);
-    return this.select(function(value) {
-      return !values.include(value);
-    });
-  },
-
-  indexOf: function(object) {
-    for (var i = 0; i < this.length; i++)
-      if (this[i] == object) return i;
-    return -1;
-  },
-
-  reverse: function(inline) {
-    return (inline !== false ? this : this.toArray())._reverse();
-  },
-
-  reduce: function() {
-    return this.length > 1 ? this : this[0];
-  },
-
-  uniq: function() {
-    return this.inject([], function(array, value) {
-      return array.include(value) ? array : array.concat([value]);
-    });
-  },
-
-  inspect: function() {
-    return '[' + this.map(Object.inspect).join(', ') + ']';
-  }
-});
-var Hash = {
-  _each: function(iterator) {
-    for (var key in this) {
-      var value = this[key];
-      if (typeof value == 'function') continue;
-
-      var pair = [key, value];
-      pair.key = key;
-      pair.value = value;
-      iterator(pair);
-    }
-  },
-
-  keys: function() {
-    return this.pluck('key');
-  },
-
-  values: function() {
-    return this.pluck('value');
-  },
-
-  merge: function(hash) {
-    return $H(hash).inject($H(this), function(mergedHash, pair) {
-      mergedHash[pair.key] = pair.value;
-      return mergedHash;
-    });
-  },
-
-  toQueryString: function() {
-    return this.map(function(pair) {
-      return pair.map(encodeURIComponent).join('=');
-    }).join('&');
-  },
-
-  inspect: function() {
-    return '#<Hash:{' + this.map(function(pair) {
-      return pair.map(Object.inspect).join(': ');
-    }).join(', ') + '}>';
-  }
-}
-
-function $H(object) {
-  var hash = Object.extend({}, object || {});
-  Object.extend(hash, Enumerable);
-  Object.extend(hash, Hash);
-  return hash;
-}
-ObjectRange = Class.create();
-Object.extend(ObjectRange.prototype, Enumerable);
-Object.extend(ObjectRange.prototype, {
-  initialize: function(start, end, exclusive) {
-    this.start = start;
-    this.end = end;
-    this.exclusive = exclusive;
-  },
-
-  _each: function(iterator) {
-    var value = this.start;
-    while (this.include(value)) {
-      iterator(value);
-      value = value.succ();
-    }
-  },
-
-  include: function(value) {
-    if (value < this.start)
-      return false;
-    if (this.exclusive)
-      return value < this.end;
-    return value <= this.end;
-  }
-});
-
-var $R = function(start, end, exclusive) {
-  return new ObjectRange(start, end, exclusive);
-}
-
-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) {
-    this.responders._each(iterator);
-  },
-
-  register: function(responderToAdd) {
-    if (!this.include(responderToAdd))
-      this.responders.push(responderToAdd);
-  },
-
-  unregister: function(responderToRemove) {
-    this.responders = this.responders.without(responderToRemove);
-  },
-
-  dispatch: function(callback, request, transport, json) {
-    this.each(function(responder) {
-      if (responder[callback] && typeof responder[callback] == 'function') {
-        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 = function() {};
-Ajax.Base.prototype = {
-  setOptions: function(options) {
-    this.options = {
-      method:       'post',
-      asynchronous: true,
-      contentType:  'application/x-www-form-urlencoded',
-      parameters:   ''
-    }
-    Object.extend(this.options, options || {});
-  },
-
-  responseIsSuccess: function() {
-    return this.transport.status == undefined
-        || this.transport.status == 0
-        || (this.transport.status >= 200 && this.transport.status < 300);
-  },
-
-  responseIsFailure: function() {
-    return !this.responseIsSuccess();
-  }
-}
-
-Ajax.Request = Class.create();
-Ajax.Request.Events =
-  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
-  initialize: function(url, options) {
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-    this.request(url);
-  },
-
-  request: function(url) {
-    var parameters = this.options.parameters || '';
-    if (parameters.length > 0) parameters += '&_=';
-
-    /* Simulate other verbs over post */
-    if (this.options.method != 'get' && this.options.method != 'post') {
-      parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
-      this.options.method = 'post';
-    }
-
-    try {
-      this.url = url;
-      if (this.options.method == 'get' && parameters.length > 0)
-        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
-
-      Ajax.Responders.dispatch('onCreate', this, this.transport);
-
-      this.transport.open(this.options.method, this.url,
-        this.options.asynchronous);
-
-      if (this.options.asynchronous)
-        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
-
-      this.transport.onreadystatechange = this.onStateChange.bind(this);
-      this.setRequestHeaders();
-
-      var body = this.options.postBody ? this.options.postBody : parameters;
-      this.transport.send(this.options.method == 'post' ? body : null);
-
-      /* Force Firefox to handle ready state 4 for synchronous requests */
-      if (!this.options.asynchronous && this.transport.overrideMimeType)
-        this.onStateChange();
-
-    } catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  setRequestHeaders: function() {
-    var requestHeaders =
-      ['X-Requested-With', 'XMLHttpRequest',
-       'X-Prototype-Version', Prototype.Version,
-       'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
-
-    if (this.options.method == 'post') {
-      requestHeaders.push('Content-type', this.options.contentType);
-
-      /* Force "Connection: close" for Mozilla browsers to work around
-       * a bug where XMLHttpReqeuest sends an incorrect Content-length
-       * header. See Mozilla Bugzilla #246651.
-       */
-      if (this.transport.overrideMimeType)
-        requestHeaders.push('Connection', 'close');
-    }
-
-    if (this.options.requestHeaders)
-      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
-
-    for (var i = 0; i < requestHeaders.length; i += 2)
-      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
-  },
-
-  onStateChange: function() {
-    var readyState = this.transport.readyState;
-    if (readyState != 1)
-      this.respondToReadyState(this.transport.readyState);
-  },
-
-  header: function(name) {
-    try {
-      return this.transport.getResponseHeader(name);
-    } catch (e) {}
-  },
-
-  evalJSON: function() {
-    try {
-      return eval('(' + this.header('X-JSON') + ')');
-    } catch (e) {}
-  },
-
-  evalResponse: function() {
-    try {
-      return eval(this.transport.responseText);
-    } catch (e) {
-      this.dispatchException(e);
-    }
-  },
-
-  respondToReadyState: function(readyState) {
-    var event = Ajax.Request.Events[readyState];
-    var transport = this.transport, json = this.evalJSON();
-
-    if (event == 'Complete') {
-      try {
-        (this.options['on' + this.transport.status]
-         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
-         || Prototype.emptyFunction)(transport, json);
-      } catch (e) {
-        this.dispatchException(e);
-      }
-
-      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
-        this.evalResponse();
-    }
-
-    try {
-      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
-      Ajax.Responders.dispatch('on' + event, this, transport, json);
-    } catch (e) {
-      this.dispatchException(e);
-    }
-
-    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
-    if (event == 'Complete')
-      this.transport.onreadystatechange = Prototype.emptyFunction;
-  },
-
-  dispatchException: function(exception) {
-    (this.options.onException || Prototype.emptyFunction)(this, exception);
-    Ajax.Responders.dispatch('onException', this, exception);
-  }
-});
-
-Ajax.Updater = Class.create();
-
-Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
-  initialize: function(container, url, options) {
-    this.containers = {
-      success: container.success ? $(container.success) : $(container),
-      failure: container.failure ? $(container.failure) :
-        (container.success ? null : $(container))
-    }
-
-    this.transport = Ajax.getTransport();
-    this.setOptions(options);
-
-    var onComplete = this.options.onComplete || Prototype.emptyFunction;
-    this.options.onComplete = (function(transport, object) {
-      this.updateContent();
-      onComplete(transport, object);
-    }).bind(this);
-
-    this.request(url);
-  },
-
-  updateContent: function() {
-    var receiver = this.responseIsSuccess() ?
-      this.containers.success : this.containers.failure;
-    var response = this.transport.responseText;
-
-    if (!this.options.evalScripts)
-      response = response.stripScripts();
-
-    if (receiver) {
-      if (this.options.insertion) {
-        new this.options.insertion(receiver, response);
-      } else {
-        Element.update(receiver, response);
-      }
-    }
-
-    if (this.responseIsSuccess()) {
-      if (this.onComplete)
-        setTimeout(this.onComplete.bind(this), 10);
-    }
-  }
-});
-
-Ajax.PeriodicalUpdater = Class.create();
-Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
-  initialize: function(container, url, options) {
-    this.setOptions(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(request) {
-    if (this.options.decay) {
-      this.decay = (request.responseText == this.lastText ?
-        this.decay * this.options.decay : 1);
-
-      this.lastText = request.responseText;
-    }
-    this.timer = setTimeout(this.onTimerEvent.bind(this),
-      this.decay * this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    this.updater = new Ajax.Updater(this.container, this.url, this.options);
-  }
-});
-function $() {
-  var results = [], element;
-  for (var i = 0; i < arguments.length; i++) {
-    element = arguments[i];
-    if (typeof element == 'string')
-      element = document.getElementById(element);
-    results.push(Element.extend(element));
-  }
-  return results.reduce();
-}
-
-document.getElementsByClassName = function(className, parentElement) {
-  var children = ($(parentElement) || document.body).getElementsByTagName('*');
-  return $A(children).inject([], function(elements, child) {
-    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
-      elements.push(Element.extend(child));
-    return elements;
-  });
-}
-
-/*--------------------------------------------------------------------------*/
-
-if (!window.Element)
-  var Element = new Object();
-
-Element.extend = function(element) {
-  if (!element) return;
-  if (_nativeExtensions || element.nodeType == 3) return element;
-
-  if (!element._extended && element.tagName && element != window) {
-    var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
-
-    if (element.tagName == 'FORM')
-      Object.extend(methods, Form.Methods);
-    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
-      Object.extend(methods, Form.Element.Methods);
-
-    for (var property in methods) {
-      var value = methods[property];
-      if (typeof value == 'function')
-        element[property] = cache.findOrStore(value);
-    }
-  }
-
-  element._extended = true;
-  return element;
-}
-
-Element.extend.cache = {
-  findOrStore: function(value) {
-    return this[value] = this[value] || function() {
-      return value.apply(null, [this].concat($A(arguments)));
-    }
-  }
-}
-
-Element.Methods = {
-  visible: function(element) {
-    return $(element).style.display != 'none';
-  },
-
-  toggle: function(element) {
-    element = $(element);
-    Element[Element.visible(element) ? 'hide' : 'show'](element);
-    return element;
-  },
-
-  hide: function(element) {
-    $(element).style.display = 'none';
-    return element;
-  },
-
-  show: function(element) {
-    $(element).style.display = '';
-    return element;
-  },
-
-  remove: function(element) {
-    element = $(element);
-    element.parentNode.removeChild(element);
-    return element;
-  },
-
-  update: function(element, html) {
-    $(element).innerHTML = html.stripScripts();
-    setTimeout(function() {html.evalScripts()}, 10);
-    return element;
-  },
-
-  replace: function(element, html) {
-    element = $(element);
-    if (element.outerHTML) {
-      element.outerHTML = html.stripScripts();
-    } else {
-      var range = element.ownerDocument.createRange();
-      range.selectNodeContents(element);
-      element.parentNode.replaceChild(
-        range.createContextualFragment(html.stripScripts()), element);
-    }
-    setTimeout(function() {html.evalScripts()}, 10);
-    return element;
-  },
-
-  inspect: function(element) {
-    element = $(element);
-    var result = '<' + element.tagName.toLowerCase();
-    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
-      var property = pair.first(), attribute = pair.last();
-      var value = (element[property] || '').toString();
-      if (value) result += ' ' + attribute + '=' + value.inspect(true);
-    });
-    return result + '>';
-  },
-
-  recursivelyCollect: function(element, property) {
-    element = $(element);
-    var elements = [];
-    while (element = element[property])
-      if (element.nodeType == 1)
-        elements.push(Element.extend(element));
-    return elements;
-  },
-
-  ancestors: function(element) {
-    return $(element).recursivelyCollect('parentNode');
-  },
-
-  descendants: function(element) {
-    element = $(element);
-    return $A(element.getElementsByTagName('*'));
-  },
-
-  previousSiblings: function(element) {
-    return $(element).recursivelyCollect('previousSibling');
-  },
-
-  nextSiblings: function(element) {
-    return $(element).recursivelyCollect('nextSibling');
-  },
-
-  siblings: function(element) {
-    element = $(element);
-    return element.previousSiblings().reverse().concat(element.nextSiblings());
-  },
-
-  match: function(element, selector) {
-    element = $(element);
-    if (typeof selector == 'string')
-      selector = new Selector(selector);
-    return selector.match(element);
-  },
-
-  up: function(element, expression, index) {
-    return Selector.findElement($(element).ancestors(), expression, index);
-  },
-
-  down: function(element, expression, index) {
-    return Selector.findElement($(element).descendants(), expression, index);
-  },
-
-  previous: function(element, expression, index) {
-    return Selector.findElement($(element).previousSiblings(), expression, index);
-  },
-
-  next: function(element, expression, index) {
-    return Selector.findElement($(element).nextSiblings(), expression, index);
-  },
-
-  getElementsBySelector: function() {
-    var args = $A(arguments), element = $(args.shift());
-    return Selector.findChildElements(element, args);
-  },
-
-  getElementsByClassName: function(element, className) {
-    element = $(element);
-    return document.getElementsByClassName(className, element);
-  },
-
-  getHeight: function(element) {
-    element = $(element);
-    return element.offsetHeight;
-  },
-
-  classNames: function(element) {
-    return new Element.ClassNames(element);
-  },
-
-  hasClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    return Element.classNames(element).include(className);
-  },
-
-  addClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    Element.classNames(element).add(className);
-    return element;
-  },
-
-  removeClassName: function(element, className) {
-    if (!(element = $(element))) return;
-    Element.classNames(element).remove(className);
-    return element;
-  },
-
-  observe: function() {
-    Event.observe.apply(Event, arguments);
-    return $A(arguments).first();
-  },
-
-  stopObserving: function() {
-    Event.stopObserving.apply(Event, arguments);
-    return $A(arguments).first();
-  },
-
-  // removes whitespace-only text node children
-  cleanWhitespace: function(element) {
-    element = $(element);
-    var node = element.firstChild;
-    while (node) {
-      var nextNode = node.nextSibling;
-      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
-        element.removeChild(node);
-      node = nextNode;
-    }
-    return element;
-  },
-
-  empty: function(element) {
-    return $(element).innerHTML.match(/^\s*$/);
-  },
-
-  childOf: function(element, ancestor) {
-    element = $(element), ancestor = $(ancestor);
-    while (element = element.parentNode)
-      if (element == ancestor) return true;
-    return false;
-  },
-
-  scrollTo: function(element) {
-    element = $(element);
-    var x = element.x ? element.x : element.offsetLeft,
-        y = element.y ? element.y : element.offsetTop;
-    window.scrollTo(x, y);
-    return element;
-  },
-
-  getStyle: function(element, style) {
-    element = $(element);
-    var value = element.style[style.camelize()];
-    if (!value) {
-      if (document.defaultView && document.defaultView.getComputedStyle) {
-        var css = document.defaultView.getComputedStyle(element, null);
-        value = css ? css.getPropertyValue(style) : null;
-      } else if (element.currentStyle) {
-        value = element.currentStyle[style.camelize()];
-      }
-    }
-
-    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
-      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
-
-    return value == 'auto' ? null : value;
-  },
-
-  setStyle: function(element, style) {
-    element = $(element);
-    for (var name in style)
-      element.style[name.camelize()] = style[name];
-    return element;
-  },
-
-  getDimensions: function(element) {
-    element = $(element);
-    if (Element.getStyle(element, 'display') != 'none')
-      return {width: element.offsetWidth, height: element.offsetHeight};
-
-    // All *Width and *Height properties give 0 on elements with display none,
-    // so enable the element temporarily
-    var els = element.style;
-    var originalVisibility = els.visibility;
-    var originalPosition = els.position;
-    els.visibility = 'hidden';
-    els.position = 'absolute';
-    els.display = '';
-    var originalWidth = element.clientWidth;
-    var originalHeight = element.clientHeight;
-    els.display = 'none';
-    els.position = originalPosition;
-    els.visibility = originalVisibility;
-    return {width: originalWidth, height: originalHeight};
-  },
-
-  makePositioned: function(element) {
-    element = $(element);
-    var pos = Element.getStyle(element, 'position');
-    if (pos == 'static' || !pos) {
-      element._madePositioned = true;
-      element.style.position = 'relative';
-      // Opera returns the offset relative to the positioning context, when an
-      // element is position relative but top and left have not been defined
-      if (window.opera) {
-        element.style.top = 0;
-        element.style.left = 0;
-      }
-    }
-    return element;
-  },
-
-  undoPositioned: function(element) {
-    element = $(element);
-    if (element._madePositioned) {
-      element._madePositioned = undefined;
-      element.style.position =
-        element.style.top =
-        element.style.left =
-        element.style.bottom =
-        element.style.right = '';
-    }
-    return element;
-  },
-
-  makeClipping: function(element) {
-    element = $(element);
-    if (element._overflow) return;
-    element._overflow = element.style.overflow || 'auto';
-    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
-      element.style.overflow = 'hidden';
-    return element;
-  },
-
-  undoClipping: function(element) {
-    element = $(element);
-    if (!element._overflow) return;
-    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
-    element._overflow = null;
-    return element;
-  }
-}
-
-// IE is missing .innerHTML support for TABLE-related elements
-if(document.all){
-  Element.Methods.update = function(element, html) {
-    element = $(element);
-    var tagName = element.tagName.toUpperCase();
-    if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
-      var div = document.createElement('div');
-      switch (tagName) {
-        case 'THEAD':
-        case 'TBODY':
-          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
-          depth = 2;
-          break;
-        case 'TR':
-          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
-          depth = 3;
-          break;
-        case 'TD':
-          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
-          depth = 4;
-      }
-      $A(element.childNodes).each(function(node){
-        element.removeChild(node)
-      });
-      depth.times(function(){ div = div.firstChild });
-
-      $A(div.childNodes).each(
-        function(node){ element.appendChild(node) });
-    } else {
-      element.innerHTML = html.stripScripts();
-    }
-    setTimeout(function() {html.evalScripts()}, 10);
-    return element;
-  }
-}
-
-Object.extend(Element, Element.Methods);
-
-var _nativeExtensions = false;
-
-if (!window.HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
-  /* Emulate HTMLElement, HTMLFormElement, HTMLInputElement, HTMLTextAreaElement,
-     and HTMLSelectElement in Safari */
-  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
-    var klass = window['HTML' + tag + 'Element'] = {};
-    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
-  });
-}
-
-Element.addMethods = function(methods) {
-  Object.extend(Element.Methods, methods || {});
-
-  function copy(methods, destination) {
-    var cache = Element.extend.cache;
-    for (var property in methods) {
-      var value = methods[property];
-      destination[property] = cache.findOrStore(value);
-    }
-  }
-
-  if (typeof HTMLElement != 'undefined') {
-    copy(Element.Methods, HTMLElement.prototype);
-    copy(Form.Methods, HTMLFormElement.prototype);
-    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
-      copy(Form.Element.Methods, klass.prototype);
-    });
-    _nativeExtensions = true;
-  }
-}
-
-var Toggle = new Object();
-Toggle.display = Element.toggle;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.Insertion = function(adjacency) {
-  this.adjacency = adjacency;
-}
-
-Abstract.Insertion.prototype = {
-  initialize: function(element, content) {
-    this.element = $(element);
-    this.content = content.stripScripts();
-
-    if (this.adjacency && this.element.insertAdjacentHTML) {
-      try {
-        this.element.insertAdjacentHTML(this.adjacency, this.content);
-      } catch (e) {
-        var tagName = this.element.tagName.toLowerCase();
-        if (tagName == 'tbody' || tagName == 'tr') {
-          this.insertContent(this.contentFromAnonymousTable());
-        } else {
-          throw e;
-        }
-      }
-    } else {
-      this.range = this.element.ownerDocument.createRange();
-      if (this.initializeRange) this.initializeRange();
-      this.insertContent([this.range.createContextualFragment(this.content)]);
-    }
-
-    setTimeout(function() {content.evalScripts()}, 10);
-  },
-
-  contentFromAnonymousTable: function() {
-    var div = document.createElement('div');
-    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
-    return $A(div.childNodes[0].childNodes[0].childNodes);
-  }
-}
-
-var Insertion = new Object();
-
-Insertion.Before = Class.create();
-Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
-  initializeRange: function() {
-    this.range.setStartBefore(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.parentNode.insertBefore(fragment, this.element);
-    }).bind(this));
-  }
-});
-
-Insertion.Top = Class.create();
-Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(true);
-  },
-
-  insertContent: function(fragments) {
-    fragments.reverse(false).each((function(fragment) {
-      this.element.insertBefore(fragment, this.element.firstChild);
-    }).bind(this));
-  }
-});
-
-Insertion.Bottom = Class.create();
-Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
-  initializeRange: function() {
-    this.range.selectNodeContents(this.element);
-    this.range.collapse(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.appendChild(fragment);
-    }).bind(this));
-  }
-});
-
-Insertion.After = Class.create();
-Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
-  initializeRange: function() {
-    this.range.setStartAfter(this.element);
-  },
-
-  insertContent: function(fragments) {
-    fragments.each((function(fragment) {
-      this.element.parentNode.insertBefore(fragment,
-        this.element.nextSibling);
-    }).bind(this));
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Element.ClassNames = Class.create();
-Element.ClassNames.prototype = {
-  initialize: function(element) {
-    this.element = $(element);
-  },
-
-  _each: function(iterator) {
-    this.element.className.split(/\s+/).select(function(name) {
-      return name.length > 0;
-    })._each(iterator);
-  },
-
-  set: function(className) {
-    this.element.className = className;
-  },
-
-  add: function(classNameToAdd) {
-    if (this.include(classNameToAdd)) return;
-    this.set(this.toArray().concat(classNameToAdd).join(' '));
-  },
-
-  remove: function(classNameToRemove) {
-    if (!this.include(classNameToRemove)) return;
-    this.set(this.select(function(className) {
-      return className != classNameToRemove;
-    }).join(' '));
-  },
-
-  toString: function() {
-    return this.toArray().join(' ');
-  }
-}
-
-Object.extend(Element.ClassNames.prototype, Enumerable);
-var Selector = Class.create();
-Selector.prototype = {
-  initialize: function(expression) {
-    this.params = {classNames: []};
-    this.expression = expression.toString().strip();
-    this.parseExpression();
-    this.compileMatcher();
-  },
-
-  parseExpression: function() {
-    function abort(message) { throw 'Parse error in selector: ' + message; }
-
-    if (this.expression == '')  abort('empty expression');
-
-    var params = this.params, expr = this.expression, match, modifier, clause, rest;
-    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
-      params.attributes = params.attributes || [];
-      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
-      expr = match[1];
-    }
-
-    if (expr == '*') return this.params.wildcard = true;
-
-    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
-      modifier = match[1], clause = match[2], rest = match[3];
-      switch (modifier) {
-        case '#':       params.id = clause; break;
-        case '.':       params.classNames.push(clause); break;
-        case '':
-        case undefined: params.tagName = clause.toUpperCase(); break;
-        default:        abort(expr.inspect());
-      }
-      expr = rest;
-    }
-
-    if (expr.length > 0) abort(expr.inspect());
-  },
-
-  buildMatchExpression: function() {
-    var params = this.params, conditions = [], clause;
-
-    if (params.wildcard)
-      conditions.push('true');
-    if (clause = params.id)
-      conditions.push('element.id == ' + clause.inspect());
-    if (clause = params.tagName)
-      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
-    if ((clause = params.classNames).length > 0)
-      for (var i = 0; i < clause.length; i++)
-        conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
-    if (clause = params.attributes) {
-      clause.each(function(attribute) {
-        var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
-        var splitValueBy = function(delimiter) {
-          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
-        }
-
-        switch (attribute.operator) {
-          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
-          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
-          case '|=':      conditions.push(
-                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
-                          ); break;
-          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
-          case '':
-          case undefined: conditions.push(value + ' != null'); break;
-          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
-        }
-      });
-    }
-
-    return conditions.join(' && ');
-  },
-
-  compileMatcher: function() {
-    this.match = new Function('element', 'if (!element.tagName) return false; \
-      return ' + this.buildMatchExpression());
-  },
-
-  findElements: function(scope) {
-    var element;
-
-    if (element = $(this.params.id))
-      if (this.match(element))
-        if (!scope || Element.childOf(element, scope))
-          return [element];
-
-    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
-
-    var results = [];
-    for (var i = 0; i < scope.length; i++)
-      if (this.match(element = scope[i]))
-        results.push(Element.extend(element));
-
-    return results;
-  },
-
-  toString: function() {
-    return this.expression;
-  }
-}
-
-Object.extend(Selector, {
-  matchElements: function(elements, expression) {
-    var selector = new Selector(expression);
-    return elements.select(selector.match.bind(selector));
-  },
-
-  findElement: function(elements, expression, index) {
-    if (typeof expression == 'number') index = expression, expression = false;
-    return Selector.matchElements(elements, expression || '*')[index || 0];
-  },
-
-  findChildElements: function(element, expressions) {
-    return expressions.map(function(expression) {
-      return expression.strip().split(/\s+/).inject([null], function(results, expr) {
-        var selector = new Selector(expr);
-        return results.inject([], function(elements, result) {
-          return elements.concat(selector.findElements(result || element));
-        });
-      });
-    }).flatten();
-  }
-});
-
-function $$() {
-  return Selector.findChildElements(document, $A(arguments));
-}
-var Form = {
-  reset: function(form) {
-    $(form).reset();
-    return form;
-  }
-};
-
-Form.Methods = {
-  serialize: function(form) {
-    var elements = Form.getElements($(form));
-    var queryComponents = new Array();
-
-    for (var i = 0; i < elements.length; i++) {
-      var queryComponent = Form.Element.serialize(elements[i]);
-      if (queryComponent)
-        queryComponents.push(queryComponent);
-    }
-
-    return queryComponents.join('&');
-  },
-
-  getElements: function(form) {
-    form = $(form);
-    var elements = new Array();
-
-    for (var tagName in Form.Element.Serializers) {
-      var tagElements = form.getElementsByTagName(tagName);
-      for (var j = 0; j < tagElements.length; j++)
-        elements.push(tagElements[j]);
-    }
-    return elements;
-  },
-
-  getInputs: function(form, typeName, name) {
-    form = $(form);
-    var inputs = form.getElementsByTagName('input');
-
-    if (!typeName && !name)
-      return inputs;
-
-    var matchingInputs = new Array();
-    for (var i = 0; i < inputs.length; i++) {
-      var input = inputs[i];
-      if ((typeName && input.type != typeName) ||
-          (name && input.name != name))
-        continue;
-      matchingInputs.push(input);
-    }
-
-    return matchingInputs;
-  },
-
-  disable: function(form) {
-    form = $(form);
-    var elements = Form.getElements(form);
-    for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
-      element.blur();
-      element.disabled = 'true';
-    }
-    return form;
-  },
-
-  enable: function(form) {
-    form = $(form);
-    var elements = Form.getElements(form);
-    for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
-      element.disabled = '';
-    }
-    return form;
-  },
-
-  findFirstElement: function(form) {
-    return Form.getElements(form).find(function(element) {
-      return element.type != 'hidden' && !element.disabled &&
-        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
-    });
-  },
-
-  focusFirstElement: function(form) {
-    form = $(form);
-    Field.activate(Form.findFirstElement(form));
-    return form;
-  }
-}
-
-Object.extend(Form, Form.Methods);
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element = {
-  focus: function(element) {
-    $(element).focus();
-    return element;
-  },
-
-  select: function(element) {
-    $(element).select();
-    return element;
-  }
-}
-
-Form.Element.Methods = {
-  serialize: function(element) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    var parameter = Form.Element.Serializers[method](element);
-
-    if (parameter) {
-      var key = encodeURIComponent(parameter[0]);
-      if (key.length == 0) return;
-
-      if (parameter[1].constructor != Array)
-        parameter[1] = [parameter[1]];
-
-      return parameter[1].map(function(value) {
-        return key + '=' + encodeURIComponent(value);
-      }).join('&');
-    }
-  },
-
-  getValue: function(element) {
-    element = $(element);
-    var method = element.tagName.toLowerCase();
-    var parameter = Form.Element.Serializers[method](element);
-
-    if (parameter)
-      return parameter[1];
-  },
-
-  clear: function(element) {
-    $(element).value = '';
-    return element;
-  },
-
-  present: function(element) {
-    return $(element).value != '';
-  },
-
-  activate: function(element) {
-    element = $(element);
-    element.focus();
-    if (element.select)
-      element.select();
-    return element;
-  },
-
-  disable: function(element) {
-    element = $(element);
-    element.disabled = '';
-    return element;
-  },
-
-  enable: function(element) {
-    element = $(element);
-    element.blur();
-    element.disabled = 'true';
-    return element;
-  }
-}
-
-Object.extend(Form.Element, Form.Element.Methods);
-var Field = Form.Element;
-
-/*--------------------------------------------------------------------------*/
-
-Form.Element.Serializers = {
-  input: function(element) {
-    switch (element.type.toLowerCase()) {
-      case 'checkbox':
-      case 'radio':
-        return Form.Element.Serializers.inputSelector(element);
-      default:
-        return Form.Element.Serializers.textarea(element);
-    }
-    return false;
-  },
-
-  inputSelector: function(element) {
-    if (element.checked)
-      return [element.name, element.value];
-  },
-
-  textarea: function(element) {
-    return [element.name, element.value];
-  },
-
-  select: function(element) {
-    return Form.Element.Serializers[element.type == 'select-one' ?
-      'selectOne' : 'selectMany'](element);
-  },
-
-  selectOne: function(element) {
-    var value = '', opt, index = element.selectedIndex;
-    if (index >= 0) {
-      opt = element.options[index];
-      value = opt.value || opt.text;
-    }
-    return [element.name, value];
-  },
-
-  selectMany: function(element) {
-    var value = [];
-    for (var i = 0; i < element.length; i++) {
-      var opt = element.options[i];
-      if (opt.selected)
-        value.push(opt.value || opt.text);
-    }
-    return [element.name, value];
-  }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var $F = Form.Element.getValue;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.TimedObserver = function() {}
-Abstract.TimedObserver.prototype = {
-  initialize: function(element, frequency, callback) {
-    this.frequency = frequency;
-    this.element   = $(element);
-    this.callback  = callback;
-
-    this.lastValue = this.getValue();
-    this.registerCallback();
-  },
-
-  registerCallback: function() {
-    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
-  },
-
-  onTimerEvent: function() {
-    var value = this.getValue();
-    if (this.lastValue != value) {
-      this.callback(this.element, value);
-      this.lastValue = value;
-    }
-  }
-}
-
-Form.Element.Observer = Class.create();
-Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.Observer = Class.create();
-Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.EventObserver = function() {}
-Abstract.EventObserver.prototype = {
-  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() {
-    var elements = Form.getElements(this.element);
-    for (var i = 0; i < elements.length; i++)
-      this.registerCallback(elements[i]);
-  },
-
-  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();
-Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.Element.getValue(this.element);
-  }
-});
-
-Form.EventObserver = Class.create();
-Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
-  getValue: function() {
-    return Form.serialize(this.element);
-  }
-});
-if (!window.Event) {
-  var Event = new Object();
-}
-
-Object.extend(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,
-
-  element: function(event) {
-    return event.target || event.srcElement;
-  },
-
-  isLeftClick: function(event) {
-    return (((event.which) && (event.which == 1)) ||
-            ((event.button) && (event.button == 1)));
-  },
-
-  pointerX: function(event) {
-    return event.pageX || (event.clientX +
-      (document.documentElement.scrollLeft || document.body.scrollLeft));
-  },
-
-  pointerY: function(event) {
-    return event.pageY || (event.clientY +
-      (document.documentElement.scrollTop || document.body.scrollTop));
-  },
-
-  stop: function(event) {
-    if (event.preventDefault) {
-      event.preventDefault();
-      event.stopPropagation();
-    } else {
-      event.returnValue = false;
-      event.cancelBubble = true;
-    }
-  },
-
-  // find the first node with the given tagName, starting from the
-  // node the event was triggered on; traverses the DOM upwards
-  findElement: function(event, tagName) {
-    var element = Event.element(event);
-    while (element.parentNode && (!element.tagName ||
-        (element.tagName.toUpperCase() != tagName.toUpperCase())))
-      element = element.parentNode;
-    return element;
-  },
-
-  observers: false,
-
-  _observeAndCache: function(element, name, observer, useCapture) {
-    if (!this.observers) this.observers = [];
-    if (element.addEventListener) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.addEventListener(name, observer, useCapture);
-    } else if (element.attachEvent) {
-      this.observers.push([element, name, observer, useCapture]);
-      element.attachEvent('on' + name, observer);
-    }
-  },
-
-  unloadCache: function() {
-    if (!Event.observers) return;
-    for (var i = 0; i < Event.observers.length; i++) {
-      Event.stopObserving.apply(this, Event.observers[i]);
-      Event.observers[i][0] = null;
-    }
-    Event.observers = false;
-  },
-
-  observe: function(element, name, observer, useCapture) {
-    element = $(element);
-    useCapture = useCapture || false;
-
-    if (name == 'keypress' &&
-        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-        || element.attachEvent))
-      name = 'keydown';
-
-    Event._observeAndCache(element, name, observer, useCapture);
-  },
-
-  stopObserving: function(element, name, observer, useCapture) {
-    element = $(element);
-    useCapture = useCapture || false;
-
-    if (name == 'keypress' &&
-        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
-        || element.detachEvent))
-      name = 'keydown';
-
-    if (element.removeEventListener) {
-      element.removeEventListener(name, observer, useCapture);
-    } else if (element.detachEvent) {
-      try {
-        element.detachEvent('on' + name, observer);
-      } catch (e) {}
-    }
-  }
-});
-
-/* prevent memory leaks in IE */
-if (navigator.appVersion.match(/\bMSIE\b/))
-  Event.observe(window, 'unload', Event.unloadCache, false);
-var Position = {
-  // set to true if needed, warning: firefox performance problems
-  // NOT neeeded for page scrolling, only if draggable contained in
-  // scrollable elements
-  includeScrollOffsets: false,
-
-  // must be called before calling withinIncludingScrolloffset, every time the
-  // page is scrolled
-  prepare: function() {
-    this.deltaX =  window.pageXOffset
-                || document.documentElement.scrollLeft
-                || document.body.scrollLeft
-                || 0;
-    this.deltaY =  window.pageYOffset
-                || document.documentElement.scrollTop
-                || document.body.scrollTop
-                || 0;
-  },
-
-  realOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.scrollTop  || 0;
-      valueL += element.scrollLeft || 0;
-      element = element.parentNode;
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  cumulativeOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  positionedOffset: function(element) {
-    var valueT = 0, valueL = 0;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-      element = element.offsetParent;
-      if (element) {
-        p = Element.getStyle(element, 'position');
-        if (p == 'relative' || p == 'absolute') break;
-      }
-    } while (element);
-    return [valueL, valueT];
-  },
-
-  offsetParent: function(element) {
-    if (element.offsetParent) return element.offsetParent;
-    if (element == document.body) return element;
-
-    while ((element = element.parentNode) && element != document.body)
-      if (Element.getStyle(element, 'position') != 'static')
-        return element;
-
-    return document.body;
-  },
-
-  // caches x/y coordinate pair to use with overlap
-  within: function(element, x, y) {
-    if (this.includeScrollOffsets)
-      return this.withinIncludingScrolloffsets(element, x, y);
-    this.xcomp = x;
-    this.ycomp = y;
-    this.offset = this.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 = this.realOffset(element);
-
-    this.xcomp = x + offsetcache[0] - this.deltaX;
-    this.ycomp = y + offsetcache[1] - this.deltaY;
-    this.offset = this.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);
-  },
-
-  // within must be called directly before
-  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;
-  },
-
-  page: function(forElement) {
-    var valueT = 0, valueL = 0;
-
-    var element = forElement;
-    do {
-      valueT += element.offsetTop  || 0;
-      valueL += element.offsetLeft || 0;
-
-      // Safari fix
-      if (element.offsetParent==document.body)
-        if (Element.getStyle(element,'position')=='absolute') break;
-
-    } while (element = element.offsetParent);
-
-    element = forElement;
-    do {
-      if (!window.opera || element.tagName=='BODY') {
-        valueT -= element.scrollTop  || 0;
-        valueL -= element.scrollLeft || 0;
-      }
-    } while (element = element.parentNode);
-
-    return [valueL, valueT];
-  },
-
-  clone: function(source, target) {
-    var options = Object.extend({
-      setLeft:    true,
-      setTop:     true,
-      setWidth:   true,
-      setHeight:  true,
-      offsetTop:  0,
-      offsetLeft: 0
-    }, arguments[2] || {})
-
-    // find page position of source
-    source = $(source);
-    var p = Position.page(source);
-
-    // find coordinate system to use
-    target = $(target);
-    var delta = [0, 0];
-    var parent = null;
-    // delta [0,0] will do fine with position: fixed elements,
-    // position:absolute needs offsetParent deltas
-    if (Element.getStyle(target,'position') == 'absolute') {
-      parent = Position.offsetParent(target);
-      delta = Position.page(parent);
-    }
-
-    // correct by body offsets (fixes Safari)
-    if (parent == document.body) {
-      delta[0] -= document.body.offsetLeft;
-      delta[1] -= document.body.offsetTop;
-    }
-
-    // set position
-    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
-    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
-    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
-    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
-  },
-
-  absolutize: function(element) {
-    element = $(element);
-    if (element.style.position == 'absolute') return;
-    Position.prepare();
-
-    var offsets = Position.positionedOffset(element);
-    var top     = offsets[1];
-    var left    = offsets[0];
-    var width   = element.clientWidth;
-    var height  = element.clientHeight;
-
-    element._originalLeft   = left - parseFloat(element.style.left  || 0);
-    element._originalTop    = top  - parseFloat(element.style.top || 0);
-    element._originalWidth  = element.style.width;
-    element._originalHeight = element.style.height;
-
-    element.style.position = 'absolute';
-    element.style.top    = top + 'px';;
-    element.style.left   = left + 'px';;
-    element.style.width  = width + 'px';;
-    element.style.height = height + 'px';;
-  },
-
-  relativize: function(element) {
-    element = $(element);
-    if (element.style.position == 'relative') return;
-    Position.prepare();
-
-    element.style.position = 'relative';
-    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
-    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
-
-    element.style.top    = top + 'px';
-    element.style.left   = left + 'px';
-    element.style.height = element._originalHeight;
-    element.style.width  = element._originalWidth;
-  }
-}
-
-// Safari returns margins on body which is incorrect if the child is absolutely
-// positioned.  For performance reasons, redefine Position.cumulativeOffset for
-// KHTML/WebKit only.
-if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
-  Position.cumulativeOffset = function(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 [valueL, valueT];
-  }
-}
-
+/*  Prototype JavaScript framework, version 1.5.0_rc1\r
+ *  (c) 2005 Sam Stephenson <sam@conio.net>\r
+ *\r
+ *  Prototype is freely distributable under the terms of an MIT-style license.\r
+ *  For details, see the Prototype web site: http://prototype.conio.net/\r
+ *\r
+/*--------------------------------------------------------------------------*/\r
+\r
+var Prototype = {\r
+  Version: '1.5.0_rc1',\r
+  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',\r
+\r
+  emptyFunction: function() {},\r
+  K: function(x) {return x}\r
+}\r
+\r
+var Class = {\r
+  create: function() {\r
+    return function() {\r
+      this.initialize.apply(this, arguments);\r
+    }\r
+  }\r
+}\r
+\r
+var Abstract = new Object();\r
+\r
+Object.extend = function(destination, source) {\r
+  for (var property in source) {\r
+    destination[property] = source[property];\r
+  }\r
+  return destination;\r
+}\r
+\r
+Object.extend(Object, {\r
+  inspect: function(object) {\r
+    try {\r
+      if (object == undefined) return 'undefined';\r
+      if (object == null) return 'null';\r
+      return object.inspect ? object.inspect() : object.toString();\r
+    } catch (e) {\r
+      if (e instanceof RangeError) return '...';\r
+      throw e;\r
+    }\r
+  },\r
+\r
+  keys: function(object) {\r
+    var keys = [];\r
+    for (var property in object)\r
+      keys.push(property);\r
+    return keys;\r
+  },\r
+\r
+  values: function(object) {\r
+    var values = [];\r
+    for (var property in object)\r
+      values.push(object[property]);\r
+    return values;\r
+  },\r
+\r
+  clone: function(object) {\r
+    return Object.extend({}, object);\r
+  }\r
+});\r
+\r
+Function.prototype.bind = function() {\r
+  var __method = this, args = $A(arguments), object = args.shift();\r
+  return function() {\r
+    return __method.apply(object, args.concat($A(arguments)));\r
+  }\r
+}\r
+\r
+Function.prototype.bindAsEventListener = function(object) {\r
+  var __method = this, args = $A(arguments), object = args.shift();\r
+  return function(event) {\r
+    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));\r
+  }\r
+}\r
+\r
+Object.extend(Number.prototype, {\r
+  toColorPart: function() {\r
+    var digits = this.toString(16);\r
+    if (this < 16) return '0' + digits;\r
+    return digits;\r
+  },\r
+\r
+  succ: function() {\r
+    return this + 1;\r
+  },\r
+\r
+  times: function(iterator) {\r
+    $R(0, this, true).each(iterator);\r
+    return this;\r
+  }\r
+});\r
+\r
+var Try = {\r
+  these: function() {\r
+    var returnValue;\r
+\r
+    for (var i = 0; i < arguments.length; i++) {\r
+      var lambda = arguments[i];\r
+      try {\r
+        returnValue = lambda();\r
+        break;\r
+      } catch (e) {}\r
+    }\r
+\r
+    return returnValue;\r
+  }\r
+}\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+var PeriodicalExecuter = Class.create();\r
+PeriodicalExecuter.prototype = {\r
+  initialize: function(callback, frequency) {\r
+    this.callback = callback;\r
+    this.frequency = frequency;\r
+    this.currentlyExecuting = false;\r
+\r
+    this.registerCallback();\r
+  },\r
+\r
+  registerCallback: function() {\r
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\r
+  },\r
+\r
+  stop: function() {\r
+    if (!this.timer) return;\r
+    clearInterval(this.timer);\r
+    this.timer = null;\r
+  },\r
+\r
+  onTimerEvent: function() {\r
+    if (!this.currentlyExecuting) {\r
+      try {\r
+        this.currentlyExecuting = true;\r
+        this.callback(this);\r
+      } finally {\r
+        this.currentlyExecuting = false;\r
+      }\r
+    }\r
+  }\r
+}\r
+Object.extend(String.prototype, {\r
+  gsub: function(pattern, replacement) {\r
+    var result = '', source = this, match;\r
+    replacement = arguments.callee.prepareReplacement(replacement);\r
+\r
+    while (source.length > 0) {\r
+      if (match = source.match(pattern)) {\r
+        result += source.slice(0, match.index);\r
+        result += (replacement(match) || '').toString();\r
+        source  = source.slice(match.index + match[0].length);\r
+      } else {\r
+        result += source, source = '';\r
+      }\r
+    }\r
+    return result;\r
+  },\r
+\r
+  sub: function(pattern, replacement, count) {\r
+    replacement = this.gsub.prepareReplacement(replacement);\r
+    count = count === undefined ? 1 : count;\r
+\r
+    return this.gsub(pattern, function(match) {\r
+      if (--count < 0) return match[0];\r
+      return replacement(match);\r
+    });\r
+  },\r
+\r
+  scan: function(pattern, iterator) {\r
+    this.gsub(pattern, iterator);\r
+    return this;\r
+  },\r
+\r
+  truncate: function(length, truncation) {\r
+    length = length || 30;\r
+    truncation = truncation === undefined ? '...' : truncation;\r
+    return this.length > length ?\r
+      this.slice(0, length - truncation.length) + truncation : this;\r
+  },\r
+\r
+  strip: function() {\r
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');\r
+  },\r
+\r
+  stripTags: function() {\r
+    return this.replace(/<\/?[^>]+>/gi, '');\r
+  },\r
+\r
+  stripScripts: function() {\r
+    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');\r
+  },\r
+\r
+  extractScripts: function() {\r
+    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');\r
+    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');\r
+    return (this.match(matchAll) || []).map(function(scriptTag) {\r
+      return (scriptTag.match(matchOne) || ['', ''])[1];\r
+    });\r
+  },\r
+\r
+  evalScripts: function() {\r
+    return this.extractScripts().map(function(script) { return eval(script) });\r
+  },\r
+\r
+  escapeHTML: function() {\r
+    var div = document.createElement('div');\r
+    var text = document.createTextNode(this);\r
+    div.appendChild(text);\r
+    return div.innerHTML;\r
+  },\r
+\r
+  unescapeHTML: function() {\r
+    var div = document.createElement('div');\r
+    div.innerHTML = this.stripTags();\r
+    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';\r
+  },\r
+\r
+  toQueryParams: function() {\r
+    var pairs = this.match(/^\??(.*)$/)[1].split('&');\r
+    return pairs.inject({}, function(params, pairString) {\r
+      var pair  = pairString.split('=');\r
+      var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;\r
+      params[decodeURIComponent(pair[0])] = value;\r
+      return params;\r
+    });\r
+  },\r
+\r
+  toArray: function() {\r
+    return this.split('');\r
+  },\r
+\r
+  camelize: function() {\r
+    var oStringList = this.split('-');\r
+    if (oStringList.length == 1) return oStringList[0];\r
+\r
+    var camelizedString = this.indexOf('-') == 0\r
+      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)\r
+      : oStringList[0];\r
+\r
+    for (var i = 1, len = oStringList.length; i < len; i++) {\r
+      var s = oStringList[i];\r
+      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);\r
+    }\r
+\r
+    return camelizedString;\r
+  },\r
+\r
+  inspect: function(useDoubleQuotes) {\r
+    var escapedString = this.replace(/\\/g, '\\\\');\r
+    if (useDoubleQuotes)\r
+      return '"' + escapedString.replace(/"/g, '\\"') + '"';\r
+    else\r
+      return "'" + escapedString.replace(/'/g, '\\\'') + "'";\r
+  }\r
+});\r
+\r
+String.prototype.gsub.prepareReplacement = function(replacement) {\r
+  if (typeof replacement == 'function') return replacement;\r
+  var template = new Template(replacement);\r
+  return function(match) { return template.evaluate(match) };\r
+}\r
+\r
+String.prototype.parseQuery = String.prototype.toQueryParams;\r
+\r
+var Template = Class.create();\r
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;\r
+Template.prototype = {\r
+  initialize: function(template, pattern) {\r
+    this.template = template.toString();\r
+    this.pattern  = pattern || Template.Pattern;\r
+  },\r
+\r
+  evaluate: function(object) {\r
+    return this.template.gsub(this.pattern, function(match) {\r
+      var before = match[1];\r
+      if (before == '\\') return match[2];\r
+      return before + (object[match[3]] || '').toString();\r
+    });\r
+  }\r
+}\r
+\r
+var $break    = new Object();\r
+var $continue = new Object();\r
+\r
+var Enumerable = {\r
+  each: function(iterator) {\r
+    var index = 0;\r
+    try {\r
+      this._each(function(value) {\r
+        try {\r
+          iterator(value, index++);\r
+        } catch (e) {\r
+          if (e != $continue) throw e;\r
+        }\r
+      });\r
+    } catch (e) {\r
+      if (e != $break) throw e;\r
+    }\r
+  },\r
+\r
+  all: function(iterator) {\r
+    var result = true;\r
+    this.each(function(value, index) {\r
+      result = result && !!(iterator || Prototype.K)(value, index);\r
+      if (!result) throw $break;\r
+    });\r
+    return result;\r
+  },\r
+\r
+  any: function(iterator) {\r
+    var result = false;\r
+    this.each(function(value, index) {\r
+      if (result = !!(iterator || Prototype.K)(value, index))\r
+        throw $break;\r
+    });\r
+    return result;\r
+  },\r
+\r
+  collect: function(iterator) {\r
+    var results = [];\r
+    this.each(function(value, index) {\r
+      results.push(iterator(value, index));\r
+    });\r
+    return results;\r
+  },\r
+\r
+  detect: function (iterator) {\r
+    var result;\r
+    this.each(function(value, index) {\r
+      if (iterator(value, index)) {\r
+        result = value;\r
+        throw $break;\r
+      }\r
+    });\r
+    return result;\r
+  },\r
+\r
+  findAll: function(iterator) {\r
+    var results = [];\r
+    this.each(function(value, index) {\r
+      if (iterator(value, index))\r
+        results.push(value);\r
+    });\r
+    return results;\r
+  },\r
+\r
+  grep: function(pattern, iterator) {\r
+    var results = [];\r
+    this.each(function(value, index) {\r
+      var stringValue = value.toString();\r
+      if (stringValue.match(pattern))\r
+        results.push((iterator || Prototype.K)(value, index));\r
+    })\r
+    return results;\r
+  },\r
+\r
+  include: function(object) {\r
+    var found = false;\r
+    this.each(function(value) {\r
+      if (value == object) {\r
+        found = true;\r
+        throw $break;\r
+      }\r
+    });\r
+    return found;\r
+  },\r
+\r
+  inject: function(memo, iterator) {\r
+    this.each(function(value, index) {\r
+      memo = iterator(memo, value, index);\r
+    });\r
+    return memo;\r
+  },\r
+\r
+  invoke: function(method) {\r
+    var args = $A(arguments).slice(1);\r
+    return this.collect(function(value) {\r
+      return value[method].apply(value, args);\r
+    });\r
+  },\r
+\r
+  max: function(iterator) {\r
+    var result;\r
+    this.each(function(value, index) {\r
+      value = (iterator || Prototype.K)(value, index);\r
+      if (result == undefined || value >= result)\r
+        result = value;\r
+    });\r
+    return result;\r
+  },\r
+\r
+  min: function(iterator) {\r
+    var result;\r
+    this.each(function(value, index) {\r
+      value = (iterator || Prototype.K)(value, index);\r
+      if (result == undefined || value < result)\r
+        result = value;\r
+    });\r
+    return result;\r
+  },\r
+\r
+  partition: function(iterator) {\r
+    var trues = [], falses = [];\r
+    this.each(function(value, index) {\r
+      ((iterator || Prototype.K)(value, index) ?\r
+        trues : falses).push(value);\r
+    });\r
+    return [trues, falses];\r
+  },\r
+\r
+  pluck: function(property) {\r
+    var results = [];\r
+    this.each(function(value, index) {\r
+      results.push(value[property]);\r
+    });\r
+    return results;\r
+  },\r
+\r
+  reject: function(iterator) {\r
+    var results = [];\r
+    this.each(function(value, index) {\r
+      if (!iterator(value, index))\r
+        results.push(value);\r
+    });\r
+    return results;\r
+  },\r
+\r
+  sortBy: function(iterator) {\r
+    return this.collect(function(value, index) {\r
+      return {value: value, criteria: iterator(value, index)};\r
+    }).sort(function(left, right) {\r
+      var a = left.criteria, b = right.criteria;\r
+      return a < b ? -1 : a > b ? 1 : 0;\r
+    }).pluck('value');\r
+  },\r
+\r
+  toArray: function() {\r
+    return this.collect(Prototype.K);\r
+  },\r
+\r
+  zip: function() {\r
+    var iterator = Prototype.K, args = $A(arguments);\r
+    if (typeof args.last() == 'function')\r
+      iterator = args.pop();\r
+\r
+    var collections = [this].concat(args).map($A);\r
+    return this.map(function(value, index) {\r
+      return iterator(collections.pluck(index));\r
+    });\r
+  },\r
+\r
+  inspect: function() {\r
+    return '#<Enumerable:' + this.toArray().inspect() + '>';\r
+  }\r
+}\r
+\r
+Object.extend(Enumerable, {\r
+  map:     Enumerable.collect,\r
+  find:    Enumerable.detect,\r
+  select:  Enumerable.findAll,\r
+  member:  Enumerable.include,\r
+  entries: Enumerable.toArray\r
+});\r
+var $A = Array.from = function(iterable) {\r
+  if (!iterable) return [];\r
+  if (iterable.toArray) {\r
+    return iterable.toArray();\r
+  } else {\r
+    var results = [];\r
+    for (var i = 0; i < iterable.length; i++)\r
+      results.push(iterable[i]);\r
+    return results;\r
+  }\r
+}\r
+\r
+Object.extend(Array.prototype, Enumerable);\r
+\r
+if (!Array.prototype._reverse)\r
+  Array.prototype._reverse = Array.prototype.reverse;\r
+\r
+Object.extend(Array.prototype, {\r
+  _each: function(iterator) {\r
+    for (var i = 0; i < this.length; i++)\r
+      iterator(this[i]);\r
+  },\r
+\r
+  clear: function() {\r
+    this.length = 0;\r
+    return this;\r
+  },\r
+\r
+  first: function() {\r
+    return this[0];\r
+  },\r
+\r
+  last: function() {\r
+    return this[this.length - 1];\r
+  },\r
+\r
+  compact: function() {\r
+    return this.select(function(value) {\r
+      return value != undefined || value != null;\r
+    });\r
+  },\r
+\r
+  flatten: function() {\r
+    return this.inject([], function(array, value) {\r
+      return array.concat(value && value.constructor == Array ?\r
+        value.flatten() : [value]);\r
+    });\r
+  },\r
+\r
+  without: function() {\r
+    var values = $A(arguments);\r
+    return this.select(function(value) {\r
+      return !values.include(value);\r
+    });\r
+  },\r
+\r
+  indexOf: function(object) {\r
+    for (var i = 0; i < this.length; i++)\r
+      if (this[i] == object) return i;\r
+    return -1;\r
+  },\r
+\r
+  reverse: function(inline) {\r
+    return (inline !== false ? this : this.toArray())._reverse();\r
+  },\r
+\r
+  reduce: function() {\r
+    return this.length > 1 ? this : this[0];\r
+  },\r
+\r
+  uniq: function() {\r
+    return this.inject([], function(array, value) {\r
+      return array.include(value) ? array : array.concat([value]);\r
+    });\r
+  },\r
+\r
+  inspect: function() {\r
+    return '[' + this.map(Object.inspect).join(', ') + ']';\r
+  }\r
+});\r
+var Hash = {\r
+  _each: function(iterator) {\r
+    for (var key in this) {\r
+      var value = this[key];\r
+      if (typeof value == 'function') continue;\r
+\r
+      var pair = [key, value];\r
+      pair.key = key;\r
+      pair.value = value;\r
+      iterator(pair);\r
+    }\r
+  },\r
+\r
+  keys: function() {\r
+    return this.pluck('key');\r
+  },\r
+\r
+  values: function() {\r
+    return this.pluck('value');\r
+  },\r
+\r
+  merge: function(hash) {\r
+    return $H(hash).inject($H(this), function(mergedHash, pair) {\r
+      mergedHash[pair.key] = pair.value;\r
+      return mergedHash;\r
+    });\r
+  },\r
+\r
+  toQueryString: function() {\r
+    return this.map(function(pair) {\r
+      return pair.map(encodeURIComponent).join('=');\r
+    }).join('&');\r
+  },\r
+\r
+  inspect: function() {\r
+    return '#<Hash:{' + this.map(function(pair) {\r
+      return pair.map(Object.inspect).join(': ');\r
+    }).join(', ') + '}>';\r
+  }\r
+}\r
+\r
+function $H(object) {\r
+  var hash = Object.extend({}, object || {});\r
+  Object.extend(hash, Enumerable);\r
+  Object.extend(hash, Hash);\r
+  return hash;\r
+}\r
+ObjectRange = Class.create();\r
+Object.extend(ObjectRange.prototype, Enumerable);\r
+Object.extend(ObjectRange.prototype, {\r
+  initialize: function(start, end, exclusive) {\r
+    this.start = start;\r
+    this.end = end;\r
+    this.exclusive = exclusive;\r
+  },\r
+\r
+  _each: function(iterator) {\r
+    var value = this.start;\r
+    while (this.include(value)) {\r
+      iterator(value);\r
+      value = value.succ();\r
+    }\r
+  },\r
+\r
+  include: function(value) {\r
+    if (value < this.start)\r
+      return false;\r
+    if (this.exclusive)\r
+      return value < this.end;\r
+    return value <= this.end;\r
+  }\r
+});\r
+\r
+var $R = function(start, end, exclusive) {\r
+  return new ObjectRange(start, end, exclusive);\r
+}\r
+\r
+var Ajax = {\r
+  getTransport: function() {\r
+    return Try.these(\r
+      function() {return new XMLHttpRequest()},\r
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},\r
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}\r
+    ) || false;\r
+  },\r
+\r
+  activeRequestCount: 0\r
+}\r
+\r
+Ajax.Responders = {\r
+  responders: [],\r
+\r
+  _each: function(iterator) {\r
+    this.responders._each(iterator);\r
+  },\r
+\r
+  register: function(responderToAdd) {\r
+    if (!this.include(responderToAdd))\r
+      this.responders.push(responderToAdd);\r
+  },\r
+\r
+  unregister: function(responderToRemove) {\r
+    this.responders = this.responders.without(responderToRemove);\r
+  },\r
+\r
+  dispatch: function(callback, request, transport, json) {\r
+    this.each(function(responder) {\r
+      if (responder[callback] && typeof responder[callback] == 'function') {\r
+        try {\r
+          responder[callback].apply(responder, [request, transport, json]);\r
+        } catch (e) {}\r
+      }\r
+    });\r
+  }\r
+};\r
+\r
+Object.extend(Ajax.Responders, Enumerable);\r
+\r
+Ajax.Responders.register({\r
+  onCreate: function() {\r
+    Ajax.activeRequestCount++;\r
+  },\r
+\r
+  onComplete: function() {\r
+    Ajax.activeRequestCount--;\r
+  }\r
+});\r
+\r
+Ajax.Base = function() {};\r
+Ajax.Base.prototype = {\r
+  setOptions: function(options) {\r
+    this.options = {\r
+      method:       'post',\r
+      asynchronous: true,\r
+      contentType:  'application/x-www-form-urlencoded',\r
+      parameters:   ''\r
+    }\r
+    Object.extend(this.options, options || {});\r
+  },\r
+\r
+  responseIsSuccess: function() {\r
+    return this.transport.status == undefined\r
+        || this.transport.status == 0\r
+        || (this.transport.status >= 200 && this.transport.status < 300);\r
+  },\r
+\r
+  responseIsFailure: function() {\r
+    return !this.responseIsSuccess();\r
+  }\r
+}\r
+\r
+Ajax.Request = Class.create();\r
+Ajax.Request.Events =\r
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\r
+\r
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {\r
+  initialize: function(url, options) {\r
+    this.transport = Ajax.getTransport();\r
+    this.setOptions(options);\r
+    this.request(url);\r
+  },\r
+\r
+  request: function(url) {\r
+    var parameters = this.options.parameters || '';\r
+    if (parameters.length > 0) parameters += '&_=';\r
+\r
+    /* Simulate other verbs over post */\r
+    if (this.options.method != 'get' && this.options.method != 'post') {\r
+      parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;\r
+      this.options.method = 'post';\r
+    }\r
+\r
+    try {\r
+      this.url = url;\r
+      if (this.options.method == 'get' && parameters.length > 0)\r
+        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;\r
+\r
+      Ajax.Responders.dispatch('onCreate', this, this.transport);\r
+\r
+      this.transport.open(this.options.method, this.url,\r
+        this.options.asynchronous);\r
+\r
+      if (this.options.asynchronous)\r
+        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);\r
+\r
+      this.transport.onreadystatechange = this.onStateChange.bind(this);\r
+      this.setRequestHeaders();\r
+\r
+      var body = this.options.postBody ? this.options.postBody : parameters;\r
+      this.transport.send(this.options.method == 'post' ? body : null);\r
+\r
+      /* Force Firefox to handle ready state 4 for synchronous requests */\r
+      if (!this.options.asynchronous && this.transport.overrideMimeType)\r
+        this.onStateChange();\r
+\r
+    } catch (e) {\r
+      this.dispatchException(e);\r
+    }\r
+  },\r
+\r
+  setRequestHeaders: function() {\r
+    var requestHeaders =\r
+      ['X-Requested-With', 'XMLHttpRequest',\r
+       'X-Prototype-Version', Prototype.Version,\r
+       'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];\r
+\r
+    if (this.options.method == 'post') {\r
+      requestHeaders.push('Content-type', this.options.contentType);\r
+\r
+      /* Force "Connection: close" for Mozilla browsers to work around\r
+       * a bug where XMLHttpReqeuest sends an incorrect Content-length\r
+       * header. See Mozilla Bugzilla #246651.\r
+       */\r
+      if (this.transport.overrideMimeType)\r
+        requestHeaders.push('Connection', 'close');\r
+    }\r
+\r
+    if (this.options.requestHeaders)\r
+      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);\r
+\r
+    for (var i = 0; i < requestHeaders.length; i += 2)\r
+      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);\r
+  },\r
+\r
+  onStateChange: function() {\r
+    var readyState = this.transport.readyState;\r
+    if (readyState != 1)\r
+      this.respondToReadyState(this.transport.readyState);\r
+  },\r
+\r
+  header: function(name) {\r
+    try {\r
+      return this.transport.getResponseHeader(name);\r
+    } catch (e) {}\r
+  },\r
+\r
+  evalJSON: function() {\r
+    try {\r
+      return eval('(' + this.header('X-JSON') + ')');\r
+    } catch (e) {}\r
+  },\r
+\r
+  evalResponse: function() {\r
+    try {\r
+      return eval(this.transport.responseText);\r
+    } catch (e) {\r
+      this.dispatchException(e);\r
+    }\r
+  },\r
+\r
+  respondToReadyState: function(readyState) {\r
+    var event = Ajax.Request.Events[readyState];\r
+    var transport = this.transport, json = this.evalJSON();\r
+\r
+    if (event == 'Complete') {\r
+      try {\r
+        (this.options['on' + this.transport.status]\r
+         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]\r
+         || Prototype.emptyFunction)(transport, json);\r
+      } catch (e) {\r
+        this.dispatchException(e);\r
+      }\r
+\r
+      if ((this.header('Content-type') || '').match(/^text\/javascript/i))\r
+        this.evalResponse();\r
+    }\r
+\r
+    try {\r
+      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);\r
+      Ajax.Responders.dispatch('on' + event, this, transport, json);\r
+    } catch (e) {\r
+      this.dispatchException(e);\r
+    }\r
+\r
+    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */\r
+    if (event == 'Complete')\r
+      this.transport.onreadystatechange = Prototype.emptyFunction;\r
+  },\r
+\r
+  dispatchException: function(exception) {\r
+    (this.options.onException || Prototype.emptyFunction)(this, exception);\r
+    Ajax.Responders.dispatch('onException', this, exception);\r
+  }\r
+});\r
+\r
+Ajax.Updater = Class.create();\r
+\r
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {\r
+  initialize: function(container, url, options) {\r
+    this.containers = {\r
+      success: container.success ? $(container.success) : $(container),\r
+      failure: container.failure ? $(container.failure) :\r
+        (container.success ? null : $(container))\r
+    }\r
+\r
+    this.transport = Ajax.getTransport();\r
+    this.setOptions(options);\r
+\r
+    var onComplete = this.options.onComplete || Prototype.emptyFunction;\r
+    this.options.onComplete = (function(transport, object) {\r
+      this.updateContent();\r
+      onComplete(transport, object);\r
+    }).bind(this);\r
+\r
+    this.request(url);\r
+  },\r
+\r
+  updateContent: function() {\r
+    var receiver = this.responseIsSuccess() ?\r
+      this.containers.success : this.containers.failure;\r
+    var response = this.transport.responseText;\r
+\r
+    if (!this.options.evalScripts)\r
+      response = response.stripScripts();\r
+\r
+    if (receiver) {\r
+      if (this.options.insertion) {\r
+        new this.options.insertion(receiver, response);\r
+      } else {\r
+        Element.update(receiver, response);\r
+      }\r
+    }\r
+\r
+    if (this.responseIsSuccess()) {\r
+      if (this.onComplete)\r
+        setTimeout(this.onComplete.bind(this), 10);\r
+    }\r
+  }\r
+});\r
+\r
+Ajax.PeriodicalUpdater = Class.create();\r
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {\r
+  initialize: function(container, url, options) {\r
+    this.setOptions(options);\r
+    this.onComplete = this.options.onComplete;\r
+\r
+    this.frequency = (this.options.frequency || 2);\r
+    this.decay = (this.options.decay || 1);\r
+\r
+    this.updater = {};\r
+    this.container = container;\r
+    this.url = url;\r
+\r
+    this.start();\r
+  },\r
+\r
+  start: function() {\r
+    this.options.onComplete = this.updateComplete.bind(this);\r
+    this.onTimerEvent();\r
+  },\r
+\r
+  stop: function() {\r
+    this.updater.options.onComplete = undefined;\r
+    clearTimeout(this.timer);\r
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);\r
+  },\r
+\r
+  updateComplete: function(request) {\r
+    if (this.options.decay) {\r
+      this.decay = (request.responseText == this.lastText ?\r
+        this.decay * this.options.decay : 1);\r
+\r
+      this.lastText = request.responseText;\r
+    }\r
+    this.timer = setTimeout(this.onTimerEvent.bind(this),\r
+      this.decay * this.frequency * 1000);\r
+  },\r
+\r
+  onTimerEvent: function() {\r
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);\r
+  }\r
+});\r
+function $() {\r
+  var results = [], element;\r
+  for (var i = 0; i < arguments.length; i++) {\r
+    element = arguments[i];\r
+    if (typeof element == 'string')\r
+      element = document.getElementById(element);\r
+    results.push(Element.extend(element));\r
+  }\r
+  return results.reduce();\r
+}\r
+\r
+document.getElementsByClassName = function(className, parentElement) {\r
+  var children = ($(parentElement) || document.body).getElementsByTagName('*');\r
+  return $A(children).inject([], function(elements, child) {\r
+    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))\r
+      elements.push(Element.extend(child));\r
+    return elements;\r
+  });\r
+}\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+if (!window.Element)\r
+  var Element = new Object();\r
+\r
+Element.extend = function(element) {\r
+  if (!element) return;\r
+  if (_nativeExtensions || element.nodeType == 3) return element;\r
+\r
+  if (!element._extended && element.tagName && element != window) {\r
+    var methods = Object.clone(Element.Methods), cache = Element.extend.cache;\r
+\r
+    if (element.tagName == 'FORM')\r
+      Object.extend(methods, Form.Methods);\r
+    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))\r
+      Object.extend(methods, Form.Element.Methods);\r
+\r
+    for (var property in methods) {\r
+      var value = methods[property];\r
+      if (typeof value == 'function')\r
+        element[property] = cache.findOrStore(value);\r
+    }\r
+  }\r
+\r
+  element._extended = true;\r
+  return element;\r
+}\r
+\r
+Element.extend.cache = {\r
+  findOrStore: function(value) {\r
+    return this[value] = this[value] || function() {\r
+      return value.apply(null, [this].concat($A(arguments)));\r
+    }\r
+  }\r
+}\r
+\r
+Element.Methods = {\r
+  visible: function(element) {\r
+    return $(element).style.display != 'none';\r
+  },\r
+\r
+  toggle: function(element) {\r
+    element = $(element);\r
+    Element[Element.visible(element) ? 'hide' : 'show'](element);\r
+    return element;\r
+  },\r
+\r
+  hide: function(element) {\r
+    $(element).style.display = 'none';\r
+    return element;\r
+  },\r
+\r
+  show: function(element) {\r
+    $(element).style.display = '';\r
+    return element;\r
+  },\r
+\r
+  remove: function(element) {\r
+    element = $(element);\r
+    element.parentNode.removeChild(element);\r
+    return element;\r
+  },\r
+\r
+  update: function(element, html) {\r
+    $(element).innerHTML = html.stripScripts();\r
+    setTimeout(function() {html.evalScripts()}, 10);\r
+    return element;\r
+  },\r
+\r
+  replace: function(element, html) {\r
+    element = $(element);\r
+    if (element.outerHTML) {\r
+      element.outerHTML = html.stripScripts();\r
+    } else {\r
+      var range = element.ownerDocument.createRange();\r
+      range.selectNodeContents(element);\r
+      element.parentNode.replaceChild(\r
+        range.createContextualFragment(html.stripScripts()), element);\r
+    }\r
+    setTimeout(function() {html.evalScripts()}, 10);\r
+    return element;\r
+  },\r
+\r
+  inspect: function(element) {\r
+    element = $(element);\r
+    var result = '<' + element.tagName.toLowerCase();\r
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {\r
+      var property = pair.first(), attribute = pair.last();\r
+      var value = (element[property] || '').toString();\r
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);\r
+    });\r
+    return result + '>';\r
+  },\r
+\r
+  recursivelyCollect: function(element, property) {\r
+    element = $(element);\r
+    var elements = [];\r
+    while (element = element[property])\r
+      if (element.nodeType == 1)\r
+        elements.push(Element.extend(element));\r
+    return elements;\r
+  },\r
+\r
+  ancestors: function(element) {\r
+    return $(element).recursivelyCollect('parentNode');\r
+  },\r
+\r
+  descendants: function(element) {\r
+    element = $(element);\r
+    return $A(element.getElementsByTagName('*'));\r
+  },\r
+\r
+  previousSiblings: function(element) {\r
+    return $(element).recursivelyCollect('previousSibling');\r
+  },\r
+\r
+  nextSiblings: function(element) {\r
+    return $(element).recursivelyCollect('nextSibling');\r
+  },\r
+\r
+  siblings: function(element) {\r
+    element = $(element);\r
+    return element.previousSiblings().reverse().concat(element.nextSiblings());\r
+  },\r
+\r
+  match: function(element, selector) {\r
+    element = $(element);\r
+    if (typeof selector == 'string')\r
+      selector = new Selector(selector);\r
+    return selector.match(element);\r
+  },\r
+\r
+  up: function(element, expression, index) {\r
+    return Selector.findElement($(element).ancestors(), expression, index);\r
+  },\r
+\r
+  down: function(element, expression, index) {\r
+    return Selector.findElement($(element).descendants(), expression, index);\r
+  },\r
+\r
+  previous: function(element, expression, index) {\r
+    return Selector.findElement($(element).previousSiblings(), expression, index);\r
+  },\r
+\r
+  next: function(element, expression, index) {\r
+    return Selector.findElement($(element).nextSiblings(), expression, index);\r
+  },\r
+\r
+  getElementsBySelector: function() {\r
+    var args = $A(arguments), element = $(args.shift());\r
+    return Selector.findChildElements(element, args);\r
+  },\r
+\r
+  getElementsByClassName: function(element, className) {\r
+    element = $(element);\r
+    return document.getElementsByClassName(className, element);\r
+  },\r
+\r
+  getHeight: function(element) {\r
+    element = $(element);\r
+    return element.offsetHeight;\r
+  },\r
+\r
+  classNames: function(element) {\r
+    return new Element.ClassNames(element);\r
+  },\r
+\r
+  hasClassName: function(element, className) {\r
+    if (!(element = $(element))) return;\r
+    return Element.classNames(element).include(className);\r
+  },\r
+\r
+  addClassName: function(element, className) {\r
+    if (!(element = $(element))) return;\r
+    Element.classNames(element).add(className);\r
+    return element;\r
+  },\r
+\r
+  removeClassName: function(element, className) {\r
+    if (!(element = $(element))) return;\r
+    Element.classNames(element).remove(className);\r
+    return element;\r
+  },\r
+\r
+  observe: function() {\r
+    Event.observe.apply(Event, arguments);\r
+    return $A(arguments).first();\r
+  },\r
+\r
+  stopObserving: function() {\r
+    Event.stopObserving.apply(Event, arguments);\r
+    return $A(arguments).first();\r
+  },\r
+\r
+  // removes whitespace-only text node children\r
+  cleanWhitespace: function(element) {\r
+    element = $(element);\r
+    var node = element.firstChild;\r
+    while (node) {\r
+      var nextNode = node.nextSibling;\r
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))\r
+        element.removeChild(node);\r
+      node = nextNode;\r
+    }\r
+    return element;\r
+  },\r
+\r
+  empty: function(element) {\r
+    return $(element).innerHTML.match(/^\s*$/);\r
+  },\r
+\r
+  childOf: function(element, ancestor) {\r
+    element = $(element), ancestor = $(ancestor);\r
+    while (element = element.parentNode)\r
+      if (element == ancestor) return true;\r
+    return false;\r
+  },\r
+\r
+  scrollTo: function(element) {\r
+    element = $(element);\r
+    var x = element.x ? element.x : element.offsetLeft,\r
+        y = element.y ? element.y : element.offsetTop;\r
+    window.scrollTo(x, y);\r
+    return element;\r
+  },\r
+\r
+  getStyle: function(element, style) {\r
+    element = $(element);\r
+    var value = element.style[style.camelize()];\r
+    if (!value) {\r
+      if (document.defaultView && document.defaultView.getComputedStyle) {\r
+        var css = document.defaultView.getComputedStyle(element, null);\r
+        value = css ? css.getPropertyValue(style) : null;\r
+      } else if (element.currentStyle) {\r
+        value = element.currentStyle[style.camelize()];\r
+      }\r
+    }\r
+\r
+    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))\r
+      if (Element.getStyle(element, 'position') == 'static') value = 'auto';\r
+\r
+    return value == 'auto' ? null : value;\r
+  },\r
+\r
+  setStyle: function(element, style) {\r
+    element = $(element);\r
+    for (var name in style)\r
+      element.style[name.camelize()] = style[name];\r
+    return element;\r
+  },\r
+\r
+  getDimensions: function(element) {\r
+    element = $(element);\r
+    if (Element.getStyle(element, 'display') != 'none')\r
+      return {width: element.offsetWidth, height: element.offsetHeight};\r
+\r
+    // All *Width and *Height properties give 0 on elements with display none,\r
+    // so enable the element temporarily\r
+    var els = element.style;\r
+    var originalVisibility = els.visibility;\r
+    var originalPosition = els.position;\r
+    els.visibility = 'hidden';\r
+    els.position = 'absolute';\r
+    els.display = '';\r
+    var originalWidth = element.clientWidth;\r
+    var originalHeight = element.clientHeight;\r
+    els.display = 'none';\r
+    els.position = originalPosition;\r
+    els.visibility = originalVisibility;\r
+    return {width: originalWidth, height: originalHeight};\r
+  },\r
+\r
+  makePositioned: function(element) {\r
+    element = $(element);\r
+    var pos = Element.getStyle(element, 'position');\r
+    if (pos == 'static' || !pos) {\r
+      element._madePositioned = true;\r
+      element.style.position = 'relative';\r
+      // Opera returns the offset relative to the positioning context, when an\r
+      // element is position relative but top and left have not been defined\r
+      if (window.opera) {\r
+        element.style.top = 0;\r
+        element.style.left = 0;\r
+      }\r
+    }\r
+    return element;\r
+  },\r
+\r
+  undoPositioned: function(element) {\r
+    element = $(element);\r
+    if (element._madePositioned) {\r
+      element._madePositioned = undefined;\r
+      element.style.position =\r
+        element.style.top =\r
+        element.style.left =\r
+        element.style.bottom =\r
+        element.style.right = '';\r
+    }\r
+    return element;\r
+  },\r
+\r
+  makeClipping: function(element) {\r
+    element = $(element);\r
+    if (element._overflow) return;\r
+    element._overflow = element.style.overflow || 'auto';\r
+    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')\r
+      element.style.overflow = 'hidden';\r
+    return element;\r
+  },\r
+\r
+  undoClipping: function(element) {\r
+    element = $(element);\r
+    if (!element._overflow) return;\r
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;\r
+    element._overflow = null;\r
+    return element;\r
+  }\r
+}\r
+\r
+// IE is missing .innerHTML support for TABLE-related elements\r
+if(document.all){\r
+  Element.Methods.update = function(element, html) {\r
+    element = $(element);\r
+    var tagName = element.tagName.toUpperCase();\r
+    if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {\r
+      var div = document.createElement('div');\r
+      switch (tagName) {\r
+        case 'THEAD':\r
+        case 'TBODY':\r
+          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';\r
+          depth = 2;\r
+          break;\r
+        case 'TR':\r
+          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';\r
+          depth = 3;\r
+          break;\r
+        case 'TD':\r
+          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';\r
+          depth = 4;\r
+      }\r
+      $A(element.childNodes).each(function(node){\r
+        element.removeChild(node)\r
+      });\r
+      depth.times(function(){ div = div.firstChild });\r
+\r
+      $A(div.childNodes).each(\r
+        function(node){ element.appendChild(node) });\r
+    } else {\r
+      element.innerHTML = html.stripScripts();\r
+    }\r
+    setTimeout(function() {html.evalScripts()}, 10);\r
+    return element;\r
+  }\r
+}\r
+\r
+Object.extend(Element, Element.Methods);\r
+\r
+var _nativeExtensions = false;\r
+\r
+if (!window.HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {\r
+  /* Emulate HTMLElement, HTMLFormElement, HTMLInputElement, HTMLTextAreaElement,\r
+     and HTMLSelectElement in Safari */\r
+  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {\r
+    var klass = window['HTML' + tag + 'Element'] = {};\r
+    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;\r
+  });\r
+}\r
+\r
+Element.addMethods = function(methods) {\r
+  Object.extend(Element.Methods, methods || {});\r
+\r
+  function copy(methods, destination) {\r
+    var cache = Element.extend.cache;\r
+    for (var property in methods) {\r
+      var value = methods[property];\r
+      destination[property] = cache.findOrStore(value);\r
+    }\r
+  }\r
+\r
+  if (typeof HTMLElement != 'undefined') {\r
+    copy(Element.Methods, HTMLElement.prototype);\r
+    copy(Form.Methods, HTMLFormElement.prototype);\r
+    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {\r
+      copy(Form.Element.Methods, klass.prototype);\r
+    });\r
+    _nativeExtensions = true;\r
+  }\r
+}\r
+\r
+var Toggle = new Object();\r
+Toggle.display = Element.toggle;\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+Abstract.Insertion = function(adjacency) {\r
+  this.adjacency = adjacency;\r
+}\r
+\r
+Abstract.Insertion.prototype = {\r
+  initialize: function(element, content) {\r
+    this.element = $(element);\r
+    this.content = content.stripScripts();\r
+\r
+    if (this.adjacency && this.element.insertAdjacentHTML) {\r
+      try {\r
+        this.element.insertAdjacentHTML(this.adjacency, this.content);\r
+      } catch (e) {\r
+        var tagName = this.element.tagName.toLowerCase();\r
+        if (tagName == 'tbody' || tagName == 'tr') {\r
+          this.insertContent(this.contentFromAnonymousTable());\r
+        } else {\r
+          throw e;\r
+        }\r
+      }\r
+    } else {\r
+      this.range = this.element.ownerDocument.createRange();\r
+      if (this.initializeRange) this.initializeRange();\r
+      this.insertContent([this.range.createContextualFragment(this.content)]);\r
+    }\r
+\r
+    setTimeout(function() {content.evalScripts()}, 10);\r
+  },\r
+\r
+  contentFromAnonymousTable: function() {\r
+    var div = document.createElement('div');\r
+    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';\r
+    return $A(div.childNodes[0].childNodes[0].childNodes);\r
+  }\r
+}\r
+\r
+var Insertion = new Object();\r
+\r
+Insertion.Before = Class.create();\r
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {\r
+  initializeRange: function() {\r
+    this.range.setStartBefore(this.element);\r
+  },\r
+\r
+  insertContent: function(fragments) {\r
+    fragments.each((function(fragment) {\r
+      this.element.parentNode.insertBefore(fragment, this.element);\r
+    }).bind(this));\r
+  }\r
+});\r
+\r
+Insertion.Top = Class.create();\r
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {\r
+  initializeRange: function() {\r
+    this.range.selectNodeContents(this.element);\r
+    this.range.collapse(true);\r
+  },\r
+\r
+  insertContent: function(fragments) {\r
+    fragments.reverse(false).each((function(fragment) {\r
+      this.element.insertBefore(fragment, this.element.firstChild);\r
+    }).bind(this));\r
+  }\r
+});\r
+\r
+Insertion.Bottom = Class.create();\r
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {\r
+  initializeRange: function() {\r
+    this.range.selectNodeContents(this.element);\r
+    this.range.collapse(this.element);\r
+  },\r
+\r
+  insertContent: function(fragments) {\r
+    fragments.each((function(fragment) {\r
+      this.element.appendChild(fragment);\r
+    }).bind(this));\r
+  }\r
+});\r
+\r
+Insertion.After = Class.create();\r
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {\r
+  initializeRange: function() {\r
+    this.range.setStartAfter(this.element);\r
+  },\r
+\r
+  insertContent: function(fragments) {\r
+    fragments.each((function(fragment) {\r
+      this.element.parentNode.insertBefore(fragment,\r
+        this.element.nextSibling);\r
+    }).bind(this));\r
+  }\r
+});\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+Element.ClassNames = Class.create();\r
+Element.ClassNames.prototype = {\r
+  initialize: function(element) {\r
+    this.element = $(element);\r
+  },\r
+\r
+  _each: function(iterator) {\r
+    this.element.className.split(/\s+/).select(function(name) {\r
+      return name.length > 0;\r
+    })._each(iterator);\r
+  },\r
+\r
+  set: function(className) {\r
+    this.element.className = className;\r
+  },\r
+\r
+  add: function(classNameToAdd) {\r
+    if (this.include(classNameToAdd)) return;\r
+    this.set(this.toArray().concat(classNameToAdd).join(' '));\r
+  },\r
+\r
+  remove: function(classNameToRemove) {\r
+    if (!this.include(classNameToRemove)) return;\r
+    this.set(this.select(function(className) {\r
+      return className != classNameToRemove;\r
+    }).join(' '));\r
+  },\r
+\r
+  toString: function() {\r
+    return this.toArray().join(' ');\r
+  }\r
+}\r
+\r
+Object.extend(Element.ClassNames.prototype, Enumerable);\r
+var Selector = Class.create();\r
+Selector.prototype = {\r
+  initialize: function(expression) {\r
+    this.params = {classNames: []};\r
+    this.expression = expression.toString().strip();\r
+    this.parseExpression();\r
+    this.compileMatcher();\r
+  },\r
+\r
+  parseExpression: function() {\r
+    function abort(message) { throw 'Parse error in selector: ' + message; }\r
+\r
+    if (this.expression == '')  abort('empty expression');\r
+\r
+    var params = this.params, expr = this.expression, match, modifier, clause, rest;\r
+    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {\r
+      params.attributes = params.attributes || [];\r
+      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});\r
+      expr = match[1];\r
+    }\r
+\r
+    if (expr == '*') return this.params.wildcard = true;\r
+\r
+    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {\r
+      modifier = match[1], clause = match[2], rest = match[3];\r
+      switch (modifier) {\r
+        case '#':       params.id = clause; break;\r
+        case '.':       params.classNames.push(clause); break;\r
+        case '':\r
+        case undefined: params.tagName = clause.toUpperCase(); break;\r
+        default:        abort(expr.inspect());\r
+      }\r
+      expr = rest;\r
+    }\r
+\r
+    if (expr.length > 0) abort(expr.inspect());\r
+  },\r
+\r
+  buildMatchExpression: function() {\r
+    var params = this.params, conditions = [], clause;\r
+\r
+    if (params.wildcard)\r
+      conditions.push('true');\r
+    if (clause = params.id)\r
+      conditions.push('element.id == ' + clause.inspect());\r
+    if (clause = params.tagName)\r
+      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());\r
+    if ((clause = params.classNames).length > 0)\r
+      for (var i = 0; i < clause.length; i++)\r
+        conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');\r
+    if (clause = params.attributes) {\r
+      clause.each(function(attribute) {\r
+        var value = 'element.getAttribute(' + attribute.name.inspect() + ')';\r
+        var splitValueBy = function(delimiter) {\r
+          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';\r
+        }\r
+\r
+        switch (attribute.operator) {\r
+          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;\r
+          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;\r
+          case '|=':      conditions.push(\r
+                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()\r
+                          ); break;\r
+          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;\r
+          case '':\r
+          case undefined: conditions.push(value + ' != null'); break;\r
+          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';\r
+        }\r
+      });\r
+    }\r
+\r
+    return conditions.join(' && ');\r
+  },\r
+\r
+  compileMatcher: function() {\r
+    this.match = new Function('element', 'if (!element.tagName) return false; \\r
+      return ' + this.buildMatchExpression());\r
+  },\r
+\r
+  findElements: function(scope) {\r
+    var element;\r
+\r
+    if (element = $(this.params.id))\r
+      if (this.match(element))\r
+        if (!scope || Element.childOf(element, scope))\r
+          return [element];\r
+\r
+    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');\r
+\r
+    var results = [];\r
+    for (var i = 0; i < scope.length; i++)\r
+      if (this.match(element = scope[i]))\r
+        results.push(Element.extend(element));\r
+\r
+    return results;\r
+  },\r
+\r
+  toString: function() {\r
+    return this.expression;\r
+  }\r
+}\r
+\r
+Object.extend(Selector, {\r
+  matchElements: function(elements, expression) {\r
+    var selector = new Selector(expression);\r
+    return elements.select(selector.match.bind(selector));\r
+  },\r
+\r
+  findElement: function(elements, expression, index) {\r
+    if (typeof expression == 'number') index = expression, expression = false;\r
+    return Selector.matchElements(elements, expression || '*')[index || 0];\r
+  },\r
+\r
+  findChildElements: function(element, expressions) {\r
+    return expressions.map(function(expression) {\r
+      return expression.strip().split(/\s+/).inject([null], function(results, expr) {\r
+        var selector = new Selector(expr);\r
+        return results.inject([], function(elements, result) {\r
+          return elements.concat(selector.findElements(result || element));\r
+        });\r
+      });\r
+    }).flatten();\r
+  }\r
+});\r
+\r
+function $$() {\r
+  return Selector.findChildElements(document, $A(arguments));\r
+}\r
+var Form = {\r
+  reset: function(form) {\r
+    $(form).reset();\r
+    return form;\r
+  }\r
+};\r
+\r
+Form.Methods = {\r
+  serialize: function(form) {\r
+    var elements = Form.getElements($(form));\r
+    var queryComponents = new Array();\r
+\r
+    for (var i = 0; i < elements.length; i++) {\r
+      var queryComponent = Form.Element.serialize(elements[i]);\r
+      if (queryComponent)\r
+        queryComponents.push(queryComponent);\r
+    }\r
+\r
+    return queryComponents.join('&');\r
+  },\r
+\r
+  getElements: function(form) {\r
+    form = $(form);\r
+    var elements = new Array();\r
+\r
+    for (var tagName in Form.Element.Serializers) {\r
+      var tagElements = form.getElementsByTagName(tagName);\r
+      for (var j = 0; j < tagElements.length; j++)\r
+        elements.push(tagElements[j]);\r
+    }\r
+    return elements;\r
+  },\r
+\r
+  getInputs: function(form, typeName, name) {\r
+    form = $(form);\r
+    var inputs = form.getElementsByTagName('input');\r
+\r
+    if (!typeName && !name)\r
+      return inputs;\r
+\r
+    var matchingInputs = new Array();\r
+    for (var i = 0; i < inputs.length; i++) {\r
+      var input = inputs[i];\r
+      if ((typeName && input.type != typeName) ||\r
+          (name && input.name != name))\r
+        continue;\r
+      matchingInputs.push(input);\r
+    }\r
+\r
+    return matchingInputs;\r
+  },\r
+\r
+  disable: function(form) {\r
+    form = $(form);\r
+    var elements = Form.getElements(form);\r
+    for (var i = 0; i < elements.length; i++) {\r
+      var element = elements[i];\r
+      element.blur();\r
+      element.disabled = 'true';\r
+    }\r
+    return form;\r
+  },\r
+\r
+  enable: function(form) {\r
+    form = $(form);\r
+    var elements = Form.getElements(form);\r
+    for (var i = 0; i < elements.length; i++) {\r
+      var element = elements[i];\r
+      element.disabled = '';\r
+    }\r
+    return form;\r
+  },\r
+\r
+  findFirstElement: function(form) {\r
+    return Form.getElements(form).find(function(element) {\r
+      return element.type != 'hidden' && !element.disabled &&\r
+        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());\r
+    });\r
+  },\r
+\r
+  focusFirstElement: function(form) {\r
+    form = $(form);\r
+    Field.activate(Form.findFirstElement(form));\r
+    return form;\r
+  }\r
+}\r
+\r
+Object.extend(Form, Form.Methods);\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+Form.Element = {\r
+  focus: function(element) {\r
+    $(element).focus();\r
+    return element;\r
+  },\r
+\r
+  select: function(element) {\r
+    $(element).select();\r
+    return element;\r
+  }\r
+}\r
+\r
+Form.Element.Methods = {\r
+  serialize: function(element) {\r
+    element = $(element);\r
+    var method = element.tagName.toLowerCase();\r
+    var parameter = Form.Element.Serializers[method](element);\r
+\r
+    if (parameter) {\r
+      var key = encodeURIComponent(parameter[0]);\r
+      if (key.length == 0) return;\r
+\r
+      if (parameter[1].constructor != Array)\r
+        parameter[1] = [parameter[1]];\r
+\r
+      return parameter[1].map(function(value) {\r
+        return key + '=' + encodeURIComponent(value);\r
+      }).join('&');\r
+    }\r
+  },\r
+\r
+  getValue: function(element) {\r
+    element = $(element);\r
+    var method = element.tagName.toLowerCase();\r
+    var parameter = Form.Element.Serializers[method](element);\r
+\r
+    if (parameter)\r
+      return parameter[1];\r
+  },\r
+\r
+  clear: function(element) {\r
+    $(element).value = '';\r
+    return element;\r
+  },\r
+\r
+  present: function(element) {\r
+    return $(element).value != '';\r
+  },\r
+\r
+  activate: function(element) {\r
+    element = $(element);\r
+    element.focus();\r
+    if (element.select)\r
+      element.select();\r
+    return element;\r
+  },\r
+\r
+  disable: function(element) {\r
+    element = $(element);\r
+    element.disabled = '';\r
+    return element;\r
+  },\r
+\r
+  enable: function(element) {\r
+    element = $(element);\r
+    element.blur();\r
+    element.disabled = 'true';\r
+    return element;\r
+  }\r
+}\r
+\r
+Object.extend(Form.Element, Form.Element.Methods);\r
+var Field = Form.Element;\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+Form.Element.Serializers = {\r
+  input: function(element) {\r
+    switch (element.type.toLowerCase()) {\r
+      case 'checkbox':\r
+      case 'radio':\r
+        return Form.Element.Serializers.inputSelector(element);\r
+      default:\r
+        return Form.Element.Serializers.textarea(element);\r
+    }\r
+    return false;\r
+  },\r
+\r
+  inputSelector: function(element) {\r
+    if (element.checked)\r
+      return [element.name, element.value];\r
+  },\r
+\r
+  textarea: function(element) {\r
+    return [element.name, element.value];\r
+  },\r
+\r
+  select: function(element) {\r
+    return Form.Element.Serializers[element.type == 'select-one' ?\r
+      'selectOne' : 'selectMany'](element);\r
+  },\r
+\r
+  selectOne: function(element) {\r
+    var value = '', opt, index = element.selectedIndex;\r
+    if (index >= 0) {\r
+      opt = element.options[index];\r
+      value = opt.value || opt.text;\r
+    }\r
+    return [element.name, value];\r
+  },\r
+\r
+  selectMany: function(element) {\r
+    var value = [];\r
+    for (var i = 0; i < element.length; i++) {\r
+      var opt = element.options[i];\r
+      if (opt.selected)\r
+        value.push(opt.value || opt.text);\r
+    }\r
+    return [element.name, value];\r
+  }\r
+}\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+var $F = Form.Element.getValue;\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+Abstract.TimedObserver = function() {}\r
+Abstract.TimedObserver.prototype = {\r
+  initialize: function(element, frequency, callback) {\r
+    this.frequency = frequency;\r
+    this.element   = $(element);\r
+    this.callback  = callback;\r
+\r
+    this.lastValue = this.getValue();\r
+    this.registerCallback();\r
+  },\r
+\r
+  registerCallback: function() {\r
+    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\r
+  },\r
+\r
+  onTimerEvent: function() {\r
+    var value = this.getValue();\r
+    if (this.lastValue != value) {\r
+      this.callback(this.element, value);\r
+      this.lastValue = value;\r
+    }\r
+  }\r
+}\r
+\r
+Form.Element.Observer = Class.create();\r
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {\r
+  getValue: function() {\r
+    return Form.Element.getValue(this.element);\r
+  }\r
+});\r
+\r
+Form.Observer = Class.create();\r
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {\r
+  getValue: function() {\r
+    return Form.serialize(this.element);\r
+  }\r
+});\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+Abstract.EventObserver = function() {}\r
+Abstract.EventObserver.prototype = {\r
+  initialize: function(element, callback) {\r
+    this.element  = $(element);\r
+    this.callback = callback;\r
+\r
+    this.lastValue = this.getValue();\r
+    if (this.element.tagName.toLowerCase() == 'form')\r
+      this.registerFormCallbacks();\r
+    else\r
+      this.registerCallback(this.element);\r
+  },\r
+\r
+  onElementEvent: function() {\r
+    var value = this.getValue();\r
+    if (this.lastValue != value) {\r
+      this.callback(this.element, value);\r
+      this.lastValue = value;\r
+    }\r
+  },\r
+\r
+  registerFormCallbacks: function() {\r
+    var elements = Form.getElements(this.element);\r
+    for (var i = 0; i < elements.length; i++)\r
+      this.registerCallback(elements[i]);\r
+  },\r
+\r
+  registerCallback: function(element) {\r
+    if (element.type) {\r
+      switch (element.type.toLowerCase()) {\r
+        case 'checkbox':\r
+        case 'radio':\r
+          Event.observe(element, 'click', this.onElementEvent.bind(this));\r
+          break;\r
+        default:\r
+          Event.observe(element, 'change', this.onElementEvent.bind(this));\r
+          break;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+Form.Element.EventObserver = Class.create();\r
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {\r
+  getValue: function() {\r
+    return Form.Element.getValue(this.element);\r
+  }\r
+});\r
+\r
+Form.EventObserver = Class.create();\r
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {\r
+  getValue: function() {\r
+    return Form.serialize(this.element);\r
+  }\r
+});\r
+if (!window.Event) {\r
+  var Event = new Object();\r
+}\r
+\r
+Object.extend(Event, {\r
+  KEY_BACKSPACE: 8,\r
+  KEY_TAB:       9,\r
+  KEY_RETURN:   13,\r
+  KEY_ESC:      27,\r
+  KEY_LEFT:     37,\r
+  KEY_UP:       38,\r
+  KEY_RIGHT:    39,\r
+  KEY_DOWN:     40,\r
+  KEY_DELETE:   46,\r
+  KEY_HOME:     36,\r
+  KEY_END:      35,\r
+  KEY_PAGEUP:   33,\r
+  KEY_PAGEDOWN: 34,\r
+\r
+  element: function(event) {\r
+    return event.target || event.srcElement;\r
+  },\r
+\r
+  isLeftClick: function(event) {\r
+    return (((event.which) && (event.which == 1)) ||\r
+            ((event.button) && (event.button == 1)));\r
+  },\r
+\r
+  pointerX: function(event) {\r
+    return event.pageX || (event.clientX +\r
+      (document.documentElement.scrollLeft || document.body.scrollLeft));\r
+  },\r
+\r
+  pointerY: function(event) {\r
+    return event.pageY || (event.clientY +\r
+      (document.documentElement.scrollTop || document.body.scrollTop));\r
+  },\r
+\r
+  stop: function(event) {\r
+    if (event.preventDefault) {\r
+      event.preventDefault();\r
+      event.stopPropagation();\r
+    } else {\r
+      event.returnValue = false;\r
+      event.cancelBubble = true;\r
+    }\r
+  },\r
+\r
+  // find the first node with the given tagName, starting from the\r
+  // node the event was triggered on; traverses the DOM upwards\r
+  findElement: function(event, tagName) {\r
+    var element = Event.element(event);\r
+    while (element.parentNode && (!element.tagName ||\r
+        (element.tagName.toUpperCase() != tagName.toUpperCase())))\r
+      element = element.parentNode;\r
+    return element;\r
+  },\r
+\r
+  observers: false,\r
+\r
+  _observeAndCache: function(element, name, observer, useCapture) {\r
+    if (!this.observers) this.observers = [];\r
+    if (element.addEventListener) {\r
+      this.observers.push([element, name, observer, useCapture]);\r
+      element.addEventListener(name, observer, useCapture);\r
+    } else if (element.attachEvent) {\r
+      this.observers.push([element, name, observer, useCapture]);\r
+      element.attachEvent('on' + name, observer);\r
+    }\r
+  },\r
+\r
+  unloadCache: function() {\r
+    if (!Event.observers) return;\r
+    for (var i = 0; i < Event.observers.length; i++) {\r
+      Event.stopObserving.apply(this, Event.observers[i]);\r
+      Event.observers[i][0] = null;\r
+    }\r
+    Event.observers = false;\r
+  },\r
+\r
+  observe: function(element, name, observer, useCapture) {\r
+    element = $(element);\r
+    useCapture = useCapture || false;\r
+\r
+    if (name == 'keypress' &&\r
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)\r
+        || element.attachEvent))\r
+      name = 'keydown';\r
+\r
+    Event._observeAndCache(element, name, observer, useCapture);\r
+  },\r
+\r
+  stopObserving: function(element, name, observer, useCapture) {\r
+    element = $(element);\r
+    useCapture = useCapture || false;\r
+\r
+    if (name == 'keypress' &&\r
+        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)\r
+        || element.detachEvent))\r
+      name = 'keydown';\r
+\r
+    if (element.removeEventListener) {\r
+      element.removeEventListener(name, observer, useCapture);\r
+    } else if (element.detachEvent) {\r
+      try {\r
+        element.detachEvent('on' + name, observer);\r
+      } catch (e) {}\r
+    }\r
+  }\r
+});\r
+\r
+/* prevent memory leaks in IE */\r
+if (navigator.appVersion.match(/\bMSIE\b/))\r
+  Event.observe(window, 'unload', Event.unloadCache, false);\r
+var Position = {\r
+  // set to true if needed, warning: firefox performance problems\r
+  // NOT neeeded for page scrolling, only if draggable contained in\r
+  // scrollable elements\r
+  includeScrollOffsets: false,\r
+\r
+  // must be called before calling withinIncludingScrolloffset, every time the\r
+  // page is scrolled\r
+  prepare: function() {\r
+    this.deltaX =  window.pageXOffset\r
+                || document.documentElement.scrollLeft\r
+                || document.body.scrollLeft\r
+                || 0;\r
+    this.deltaY =  window.pageYOffset\r
+                || document.documentElement.scrollTop\r
+                || document.body.scrollTop\r
+                || 0;\r
+  },\r
+\r
+  realOffset: function(element) {\r
+    var valueT = 0, valueL = 0;\r
+    do {\r
+      valueT += element.scrollTop  || 0;\r
+      valueL += element.scrollLeft || 0;\r
+      element = element.parentNode;\r
+    } while (element);\r
+    return [valueL, valueT];\r
+  },\r
+\r
+  cumulativeOffset: function(element) {\r
+    var valueT = 0, valueL = 0;\r
+    do {\r
+      valueT += element.offsetTop  || 0;\r
+      valueL += element.offsetLeft || 0;\r
+      element = element.offsetParent;\r
+    } while (element);\r
+    return [valueL, valueT];\r
+  },\r
+\r
+  positionedOffset: function(element) {\r
+    var valueT = 0, valueL = 0;\r
+    do {\r
+      valueT += element.offsetTop  || 0;\r
+      valueL += element.offsetLeft || 0;\r
+      element = element.offsetParent;\r
+      if (element) {\r
+        p = Element.getStyle(element, 'position');\r
+        if (p == 'relative' || p == 'absolute') break;\r
+      }\r
+    } while (element);\r
+    return [valueL, valueT];\r
+  },\r
+\r
+  offsetParent: function(element) {\r
+    if (element.offsetParent) return element.offsetParent;\r
+    if (element == document.body) return element;\r
+\r
+    while ((element = element.parentNode) && element != document.body)\r
+      if (Element.getStyle(element, 'position') != 'static')\r
+        return element;\r
+\r
+    return document.body;\r
+  },\r
+\r
+  // caches x/y coordinate pair to use with overlap\r
+  within: function(element, x, y) {\r
+    if (this.includeScrollOffsets)\r
+      return this.withinIncludingScrolloffsets(element, x, y);\r
+    this.xcomp = x;\r
+    this.ycomp = y;\r
+    this.offset = this.cumulativeOffset(element);\r
+\r
+    return (y >= this.offset[1] &&\r
+            y <  this.offset[1] + element.offsetHeight &&\r
+            x >= this.offset[0] &&\r
+            x <  this.offset[0] + element.offsetWidth);\r
+  },\r
+\r
+  withinIncludingScrolloffsets: function(element, x, y) {\r
+    var offsetcache = this.realOffset(element);\r
+\r
+    this.xcomp = x + offsetcache[0] - this.deltaX;\r
+    this.ycomp = y + offsetcache[1] - this.deltaY;\r
+    this.offset = this.cumulativeOffset(element);\r
+\r
+    return (this.ycomp >= this.offset[1] &&\r
+            this.ycomp <  this.offset[1] + element.offsetHeight &&\r
+            this.xcomp >= this.offset[0] &&\r
+            this.xcomp <  this.offset[0] + element.offsetWidth);\r
+  },\r
+\r
+  // within must be called directly before\r
+  overlap: function(mode, element) {\r
+    if (!mode) return 0;\r
+    if (mode == 'vertical')\r
+      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /\r
+        element.offsetHeight;\r
+    if (mode == 'horizontal')\r
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /\r
+        element.offsetWidth;\r
+  },\r
+\r
+  page: function(forElement) {\r
+    var valueT = 0, valueL = 0;\r
+\r
+    var element = forElement;\r
+    do {\r
+      valueT += element.offsetTop  || 0;\r
+      valueL += element.offsetLeft || 0;\r
+\r
+      // Safari fix\r
+      if (element.offsetParent==document.body)\r
+        if (Element.getStyle(element,'position')=='absolute') break;\r
+\r
+    } while (element = element.offsetParent);\r
+\r
+    element = forElement;\r
+    do {\r
+      if (!window.opera || element.tagName=='BODY') {\r
+        valueT -= element.scrollTop  || 0;\r
+        valueL -= element.scrollLeft || 0;\r
+      }\r
+    } while (element = element.parentNode);\r
+\r
+    return [valueL, valueT];\r
+  },\r
+\r
+  clone: function(source, target) {\r
+    var options = Object.extend({\r
+      setLeft:    true,\r
+      setTop:     true,\r
+      setWidth:   true,\r
+      setHeight:  true,\r
+      offsetTop:  0,\r
+      offsetLeft: 0\r
+    }, arguments[2] || {})\r
+\r
+    // find page position of source\r
+    source = $(source);\r
+    var p = Position.page(source);\r
+\r
+    // find coordinate system to use\r
+    target = $(target);\r
+    var delta = [0, 0];\r
+    var parent = null;\r
+    // delta [0,0] will do fine with position: fixed elements,\r
+    // position:absolute needs offsetParent deltas\r
+    if (Element.getStyle(target,'position') == 'absolute') {\r
+      parent = Position.offsetParent(target);\r
+      delta = Position.page(parent);\r
+    }\r
+\r
+    // correct by body offsets (fixes Safari)\r
+    if (parent == document.body) {\r
+      delta[0] -= document.body.offsetLeft;\r
+      delta[1] -= document.body.offsetTop;\r
+    }\r
+\r
+    // set position\r
+    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';\r
+    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';\r
+    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';\r
+    if(options.setHeight) target.style.height = source.offsetHeight + 'px';\r
+  },\r
+\r
+  absolutize: function(element) {\r
+    element = $(element);\r
+    if (element.style.position == 'absolute') return;\r
+    Position.prepare();\r
+\r
+    var offsets = Position.positionedOffset(element);\r
+    var top     = offsets[1];\r
+    var left    = offsets[0];\r
+    var width   = element.clientWidth;\r
+    var height  = element.clientHeight;\r
+\r
+    element._originalLeft   = left - parseFloat(element.style.left  || 0);\r
+    element._originalTop    = top  - parseFloat(element.style.top || 0);\r
+    element._originalWidth  = element.style.width;\r
+    element._originalHeight = element.style.height;\r
+\r
+    element.style.position = 'absolute';\r
+    element.style.top    = top + 'px';;\r
+    element.style.left   = left + 'px';;\r
+    element.style.width  = width + 'px';;\r
+    element.style.height = height + 'px';;\r
+  },\r
+\r
+  relativize: function(element) {\r
+    element = $(element);\r
+    if (element.style.position == 'relative') return;\r
+    Position.prepare();\r
+\r
+    element.style.position = 'relative';\r
+    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);\r
+    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);\r
+\r
+    element.style.top    = top + 'px';\r
+    element.style.left   = left + 'px';\r
+    element.style.height = element._originalHeight;\r
+    element.style.width  = element._originalWidth;\r
+  }\r
+}\r
+\r
+// Safari returns margins on body which is incorrect if the child is absolutely\r
+// positioned.  For performance reasons, redefine Position.cumulativeOffset for\r
+// KHTML/WebKit only.\r
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {\r
+  Position.cumulativeOffset = function(element) {\r
+    var valueT = 0, valueL = 0;\r
+    do {\r
+      valueT += element.offsetTop  || 0;\r
+      valueL += element.offsetLeft || 0;\r
+      if (element.offsetParent == document.body)\r
+        if (Element.getStyle(element, 'position') == 'absolute') break;\r
+\r
+      element = element.offsetParent;\r
+    } while (element);\r
+\r
+    return [valueL, valueT];\r
+  }\r
+}\r
+\r
 Element.addMethods();
\ No newline at end of file