{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf430
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11900\paperh16840\margl1440\margr1440\vieww9000\viewh8400\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural

\f0\fs24 \cf0 /*  Prototype JavaScript framework, version 1.6.0\
 *  (c) 2005-2007 Sam Stephenson\
 *\
 *  Prototype is freely distributable under the terms of an MIT-style license.\
 *  For details, see the Prototype web site: http://www.prototypejs.org/\
 *\
 *--------------------------------------------------------------------------*/\
\
var Prototype = \{\
  Version: '1.6.0',\
\
  Browser: \{\
    IE:     !!(window.attachEvent && !window.opera),\
    Opera:  !!window.opera,\
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,\
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,\
    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)\
  \},\
\
  BrowserFeatures: \{\
    XPath: !!document.evaluate,\
    ElementExtensions: !!window.HTMLElement,\
    SpecificElementExtensions:\
      document.createElement('div').__proto__ &&\
      document.createElement('div').__proto__ !==\
        document.createElement('form').__proto__\
  \},\
\
  ScriptFragment: '<script[^>]*>([\\\\S\\\\s]*?)<\\/script>',\
  JSONFilter: /^\\/\\*-secure-([\\s\\S]*)\\*\\/\\s*$/,\
\
  emptyFunction: function() \{ \},\
  K: function(x) \{ return x \}\
\};\
\
if (Prototype.Browser.MobileSafari)\
  Prototype.BrowserFeatures.SpecificElementExtensions = false;\
\
if (Prototype.Browser.WebKit)\
  Prototype.BrowserFeatures.XPath = false;\
\
/* Based on Alex Arnell's inheritance implementation. */\
var Class = \{\
  create: function() \{\
    var parent = null, properties = $A(arguments);\
    if (Object.isFunction(properties[0]))\
      parent = properties.shift();\
\
    function klass() \{\
      this.initialize.apply(this, arguments);\
    \}\
\
    Object.extend(klass, Class.Methods);\
    klass.superclass = parent;\
    klass.subclasses = [];\
\
    if (parent) \{\
      var subclass = function() \{ \};\
      subclass.prototype = parent.prototype;\
      klass.prototype = new subclass;\
      parent.subclasses.push(klass);\
    \}\
\
    for (var i = 0; i < properties.length; i++)\
      klass.addMethods(properties[i]);\
\
    if (!klass.prototype.initialize)\
      klass.prototype.initialize = Prototype.emptyFunction;\
\
    klass.prototype.constructor = klass;\
\
    return klass;\
  \}\
\};\
\
Class.Methods = \{\
  addMethods: function(source) \{\
    var ancestor   = this.superclass && this.superclass.prototype;\
    var properties = Object.keys(source);\
\
    if (!Object.keys(\{ toString: true \}).length)\
      properties.push("toString", "valueOf");\
\
    for (var i = 0, length = properties.length; i < length; i++) \{\
      var property = properties[i], value = source[property];\
      if (ancestor && Object.isFunction(value) &&\
          value.argumentNames().first() == "$super") \{\
        var method = value, value = Object.extend((function(m) \{\
          return function() \{ return ancestor[m].apply(this, arguments) \};\
        \})(property).wrap(method), \{\
          valueOf:  function() \{ return method \},\
          toString: function() \{ return method.toString() \}\
        \});\
      \}\
      this.prototype[property] = value;\
    \}\
\
    return this;\
  \}\
\};\
\
var Abstract = \{ \};\
\
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;\
    \}\
  \},\
\
  toJSON: function(object) \{\
    var type = typeof object;\
    switch (type) \{\
      case 'undefined':\
      case 'function':\
      case 'unknown': return;\
      case 'boolean': return object.toString();\
    \}\
\
    if (object === null) return 'null';\
    if (object.toJSON) return object.toJSON();\
    if (Object.isElement(object)) return;\
\
    var results = [];\
    for (var property in object) \{\
      var value = Object.toJSON(object[property]);\
      if (value !== undefined)\
        results.push(property.toJSON() + ': ' + value);\
    \}\
\
    return '\{' + results.join(', ') + '\}';\
  \},\
\
  toQueryString: function(object) \{\
    return $H(object).toQueryString();\
  \},\
\
  toHTML: function(object) \{\
    return object && object.toHTML ? object.toHTML() : String.interpret(object);\
  \},\
\
  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);\
  \},\
\
  isElement: function(object) \{\
    return object && object.nodeType == 1;\
  \},\
\
  isArray: function(object) \{\
    return object && object.constructor === Array;\
  \},\
\
  isHash: function(object) \{\
    return object instanceof Hash;\
  \},\
\
  isFunction: function(object) \{\
    return typeof object == "function";\
  \},\
\
  isString: function(object) \{\
    return typeof object == "string";\
  \},\
\
  isNumber: function(object) \{\
    return typeof object == "number";\
  \},\
\
  isUndefined: function(object) \{\
    return typeof object == "undefined";\
  \}\
\});\
\
Object.extend(Function.prototype, \{\
  argumentNames: function() \{\
    var names = this.toString().match(/^[\\s\\(]*function[^(]*\\((.*?)\\)/)[1].split(",").invoke("strip");\
    return names.length == 1 && !names[0] ? [] : names;\
  \},\
\
  bind: function() \{\
    if (arguments.length < 2 && arguments[0] === undefined) return this;\
    var __method = this, args = $A(arguments), object = args.shift();\
    return function() \{\
      return __method.apply(object, args.concat($A(arguments)));\
    \}\
  \},\
\
  bindAsEventListener: function() \{\
    var __method = this, args = $A(arguments), object = args.shift();\
    return function(event) \{\
      return __method.apply(object, [event || window.event].concat(args));\
    \}\
  \},\
\
  curry: function() \{\
    if (!arguments.length) return this;\
    var __method = this, args = $A(arguments);\
    return function() \{\
      return __method.apply(this, args.concat($A(arguments)));\
    \}\
  \},\
\
  delay: function() \{\
    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;\
    return window.setTimeout(function() \{\
      return __method.apply(__method, args);\
    \}, timeout);\
  \},\
\
  wrap: function(wrapper) \{\
    var __method = this;\
    return function() \{\
      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));\
    \}\
  \},\
\
  methodize: function() \{\
    if (this._methodized) return this._methodized;\
    var __method = this;\
    return this._methodized = function() \{\
      return __method.apply(null, [this].concat($A(arguments)));\
    \};\
  \}\
\});\
\
Function.prototype.defer = Function.prototype.delay.curry(0.01);\
\
Date.prototype.toJSON = function() \{\
  return '"' + this.getUTCFullYear() + '-' +\
    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +\
    this.getUTCDate().toPaddedString(2) + 'T' +\
    this.getUTCHours().toPaddedString(2) + ':' +\
    this.getUTCMinutes().toPaddedString(2) + ':' +\
    this.getUTCSeconds().toPaddedString(2) + 'Z"';\
\};\
\
var Try = \{\
  these: function() \{\
    var returnValue;\
\
    for (var i = 0, length = arguments.length; i < length; i++) \{\
      var lambda = arguments[i];\
      try \{\
        returnValue = lambda();\
        break;\
      \} catch (e) \{ \}\
    \}\
\
    return returnValue;\
  \}\
\};\
\
RegExp.prototype.match = RegExp.prototype.test;\
\
RegExp.escape = function(str) \{\
  return String(str).replace(/([.*+?^=!:$\{\}()|[\\]\\/\\\\])/g, '\\\\$1');\
\};\
\
/*--------------------------------------------------------------------------*/\
\
var PeriodicalExecuter = Class.create(\{\
  initialize: function(callback, frequency) \{\
    this.callback = callback;\
    this.frequency = frequency;\
    this.currentlyExecuting = false;\
\
    this.registerCallback();\
  \},\
\
  registerCallback: function() \{\
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\
  \},\
\
  execute: function() \{\
    this.callback(this);\
  \},\
\
  stop: function() \{\
    if (!this.timer) return;\
    clearInterval(this.timer);\
    this.timer = null;\
  \},\
\
  onTimerEvent: function() \{\
    if (!this.currentlyExecuting) \{\
      try \{\
        this.currentlyExecuting = true;\
        this.execute();\
      \} finally \{\
        this.currentlyExecuting = false;\
      \}\
    \}\
  \}\
\});\
Object.extend(String, \{\
  interpret: function(value) \{\
    return value == null ? '' : String(value);\
  \},\
  specialChar: \{\
    '\\b': '\\\\b',\
    '\\t': '\\\\t',\
    '\\n': '\\\\n',\
    '\\f': '\\\\f',\
    '\\r': '\\\\r',\
    '\\\\': '\\\\\\\\'\
  \}\
\});\
\
Object.extend(String.prototype, \{\
  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 += String.interpret(replacement(match));\
        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 String(this);\
  \},\
\
  truncate: function(length, truncation) \{\
    length = length || 30;\
    truncation = truncation === undefined ? '...' : truncation;\
    return this.length > length ?\
      this.slice(0, length - truncation.length) + truncation : String(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 self = arguments.callee;\
    self.text.data = this;\
    return self.div.innerHTML;\
  \},\
\
  unescapeHTML: function() \{\
    var div = new Element('div');\
    div.innerHTML = this.stripTags();\
    return div.childNodes[0] ? (div.childNodes.length > 1 ?\
      $A(div.childNodes).inject('', function(memo, node) \{ return memo+node.nodeValue \}) :\
      div.childNodes[0].nodeValue) : '';\
  \},\
\
  toQueryParams: function(separator) \{\
    var match = this.strip().match(/([^?#]*)(#.*)?$/);\
    if (!match) return \{ \};\
\
    return match[1].split(separator || '&').inject(\{ \}, function(hash, pair) \{\
      if ((pair = pair.split('='))[0]) \{\
        var key = decodeURIComponent(pair.shift());\
        var value = pair.length > 1 ? pair.join('=') : pair[0];\
        if (value != undefined) value = decodeURIComponent(value);\
\
        if (key in hash) \{\
          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];\
          hash[key].push(value);\
        \}\
        else hash[key] = value;\
      \}\
      return hash;\
    \});\
  \},\
\
  toArray: function() \{\
    return this.split('');\
  \},\
\
  succ: function() \{\
    return this.slice(0, this.length - 1) +\
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);\
  \},\
\
  times: function(count) \{\
    return count < 1 ? '' : new Array(count + 1).join(this);\
  \},\
\
  camelize: function() \{\
    var parts = this.split('-'), len = parts.length;\
    if (len == 1) return parts[0];\
\
    var camelized = this.charAt(0) == '-'\
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)\
      : parts[0];\
\
    for (var i = 1; i < len; i++)\
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);\
\
    return camelized;\
  \},\
\
  capitalize: function() \{\
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();\
  \},\
\
  underscore: function() \{\
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#\{1\}_#\{2\}').gsub(/([a-z\\d])([A-Z])/,'#\{1\}_#\{2\}').gsub(/-/,'_').toLowerCase();\
  \},\
\
  dasherize: function() \{\
    return this.gsub(/_/,'-');\
  \},\
\
  inspect: function(useDoubleQuotes) \{\
    var escapedString = this.gsub(/[\\x00-\\x1f\\\\]/, function(match) \{\
      var character = String.specialChar[match[0]];\
      return character ? character : '\\\\u00' + match[0].charCodeAt().toPaddedString(2, 16);\
    \});\
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\\\"') + '"';\
    return "'" + escapedString.replace(/'/g, '\\\\\\'') + "'";\
  \},\
\
  toJSON: function() \{\
    return this.inspect(true);\
  \},\
\
  unfilterJSON: function(filter) \{\
    return this.sub(filter || Prototype.JSONFilter, '#\{1\}');\
  \},\
\
  isJSON: function() \{\
    var str = this.replace(/\\\\./g, '@').replace(/"[^"\\\\\\n\\r]*"/g, '');\
    return (/^[,:\{\}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]*$/).test(str);\
  \},\
\
  evalJSON: function(sanitize) \{\
    var json = this.unfilterJSON();\
    try \{\
      if (!sanitize || json.isJSON()) return eval('(' + json + ')');\
    \} catch (e) \{ \}\
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());\
  \},\
\
  include: function(pattern) \{\
    return this.indexOf(pattern) > -1;\
  \},\
\
  startsWith: function(pattern) \{\
    return this.indexOf(pattern) === 0;\
  \},\
\
  endsWith: function(pattern) \{\
    var d = this.length - pattern.length;\
    return d >= 0 && this.lastIndexOf(pattern) === d;\
  \},\
\
  empty: function() \{\
    return this == '';\
  \},\
\
  blank: function() \{\
    return /^\\s*$/.test(this);\
  \},\
\
  interpolate: function(object, pattern) \{\
    return new Template(this, pattern).evaluate(object);\
  \}\
\});\
\
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, \{\
  escapeHTML: function() \{\
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\
  \},\
  unescapeHTML: function() \{\
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');\
  \}\
\});\
\
String.prototype.gsub.prepareReplacement = function(replacement) \{\
  if (Object.isFunction(replacement)) return replacement;\
  var template = new Template(replacement);\
  return function(match) \{ return template.evaluate(match) \};\
\};\
\
String.prototype.parseQuery = String.prototype.toQueryParams;\
\
Object.extend(String.prototype.escapeHTML, \{\
  div:  document.createElement('div'),\
  text: document.createTextNode('')\
\});\
\
with (String.prototype.escapeHTML) div.appendChild(text);\
\
var Template = Class.create(\{\
  initialize: function(template, pattern) \{\
    this.template = template.toString();\
    this.pattern = pattern || Template.Pattern;\
  \},\
\
  evaluate: function(object) \{\
    if (Object.isFunction(object.toTemplateReplacements))\
      object = object.toTemplateReplacements();\
\
    return this.template.gsub(this.pattern, function(match) \{\
      if (object == null) return '';\
\
      var before = match[1] || '';\
      if (before == '\\\\') return match[2];\
\
      var ctx = object, expr = match[3];\
      var pattern = /^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/, match = pattern.exec(expr);\
      if (match == null) return before;\
\
      while (match != null) \{\
        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\\\\\]', ']') : match[1];\
        ctx = ctx[comp];\
        if (null == ctx || '' == match[3]) break;\
        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);\
        match = pattern.exec(expr);\
      \}\
\
      return before + String.interpret(ctx);\
    \}.bind(this));\
  \}\
\});\
Template.Pattern = /(^|.|\\r|\\n)(#\\\{(.*?)\\\})/;\
\
var $break = \{ \};\
\
var Enumerable = \{\
  each: function(iterator, context) \{\
    var index = 0;\
    iterator = iterator.bind(context);\
    try \{\
      this._each(function(value) \{\
        iterator(value, index++);\
      \});\
    \} catch (e) \{\
      if (e != $break) throw e;\
    \}\
    return this;\
  \},\
\
  eachSlice: function(number, iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var index = -number, slices = [], array = this.toArray();\
    while ((index += number) < array.length)\
      slices.push(array.slice(index, index+number));\
    return slices.collect(iterator, context);\
  \},\
\
  all: function(iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var result = true;\
    this.each(function(value, index) \{\
      result = result && !!iterator(value, index);\
      if (!result) throw $break;\
    \});\
    return result;\
  \},\
\
  any: function(iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var result = false;\
    this.each(function(value, index) \{\
      if (result = !!iterator(value, index))\
        throw $break;\
    \});\
    return result;\
  \},\
\
  collect: function(iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var results = [];\
    this.each(function(value, index) \{\
      results.push(iterator(value, index));\
    \});\
    return results;\
  \},\
\
  detect: function(iterator, context) \{\
    iterator = iterator.bind(context);\
    var result;\
    this.each(function(value, index) \{\
      if (iterator(value, index)) \{\
        result = value;\
        throw $break;\
      \}\
    \});\
    return result;\
  \},\
\
  findAll: function(iterator, context) \{\
    iterator = iterator.bind(context);\
    var results = [];\
    this.each(function(value, index) \{\
      if (iterator(value, index))\
        results.push(value);\
    \});\
    return results;\
  \},\
\
  grep: function(filter, iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var results = [];\
\
    if (Object.isString(filter))\
      filter = new RegExp(filter);\
\
    this.each(function(value, index) \{\
      if (filter.match(value))\
        results.push(iterator(value, index));\
    \});\
    return results;\
  \},\
\
  include: function(object) \{\
    if (Object.isFunction(this.indexOf))\
      if (this.indexOf(object) != -1) return true;\
\
    var found = false;\
    this.each(function(value) \{\
      if (value == object) \{\
        found = true;\
        throw $break;\
      \}\
    \});\
    return found;\
  \},\
\
  inGroupsOf: function(number, fillWith) \{\
    fillWith = fillWith === undefined ? null : fillWith;\
    return this.eachSlice(number, function(slice) \{\
      while(slice.length < number) slice.push(fillWith);\
      return slice;\
    \});\
  \},\
\
  inject: function(memo, iterator, context) \{\
    iterator = iterator.bind(context);\
    this.each(function(value, index) \{\
      memo = iterator(memo, value, index);\
    \});\
    return memo;\
  \},\
\
  invoke: function(method) \{\
    var args = $A(arguments).slice(1);\
    return this.map(function(value) \{\
      return value[method].apply(value, args);\
    \});\
  \},\
\
  max: function(iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var result;\
    this.each(function(value, index) \{\
      value = iterator(value, index);\
      if (result == undefined || value >= result)\
        result = value;\
    \});\
    return result;\
  \},\
\
  min: function(iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var result;\
    this.each(function(value, index) \{\
      value = iterator(value, index);\
      if (result == undefined || value < result)\
        result = value;\
    \});\
    return result;\
  \},\
\
  partition: function(iterator, context) \{\
    iterator = iterator ? iterator.bind(context) : Prototype.K;\
    var trues = [], falses = [];\
    this.each(function(value, index) \{\
      (iterator(value, index) ?\
        trues : falses).push(value);\
    \});\
    return [trues, falses];\
  \},\
\
  pluck: function(property) \{\
    var results = [];\
    this.each(function(value) \{\
      results.push(value[property]);\
    \});\
    return results;\
  \},\
\
  reject: function(iterator, context) \{\
    iterator = iterator.bind(context);\
    var results = [];\
    this.each(function(value, index) \{\
      if (!iterator(value, index))\
        results.push(value);\
    \});\
    return results;\
  \},\
\
  sortBy: function(iterator, context) \{\
    iterator = iterator.bind(context);\
    return this.map(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.map();\
  \},\
\
  zip: function() \{\
    var iterator = Prototype.K, args = $A(arguments);\
    if (Object.isFunction(args.last()))\
      iterator = args.pop();\
\
    var collections = [this].concat(args).map($A);\
    return this.map(function(value, index) \{\
      return iterator(collections.pluck(index));\
    \});\
  \},\
\
  size: function() \{\
    return this.toArray().length;\
  \},\
\
  inspect: function() \{\
    return '#<Enumerable:' + this.toArray().inspect() + '>';\
  \}\
\};\
\
Object.extend(Enumerable, \{\
  map:     Enumerable.collect,\
  find:    Enumerable.detect,\
  select:  Enumerable.findAll,\
  filter:  Enumerable.findAll,\
  member:  Enumerable.include,\
  entries: Enumerable.toArray,\
  every:   Enumerable.all,\
  some:    Enumerable.any\
\});\
function $A(iterable) \{\
  if (!iterable) return [];\
  if (iterable.toArray) return iterable.toArray();\
  var length = iterable.length, results = new Array(length);\
  while (length--) results[length] = iterable[length];\
  return results;\
\}\
\
if (Prototype.Browser.WebKit) \{\
  function $A(iterable) \{\
    if (!iterable) return [];\
    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&\
        iterable.toArray) return iterable.toArray();\
    var length = iterable.length, results = new Array(length);\
    while (length--) results[length] = iterable[length];\
    return results;\
  \}\
\}\
\
Array.from = $A;\
\
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, length = this.length; i < 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 != null;\
    \});\
  \},\
\
  flatten: function() \{\
    return this.inject([], function(array, value) \{\
      return array.concat(Object.isArray(value) ?\
        value.flatten() : [value]);\
    \});\
  \},\
\
  without: function() \{\
    var values = $A(arguments);\
    return this.select(function(value) \{\
      return !values.include(value);\
    \});\
  \},\
\
  reverse: function(inline) \{\
    return (inline !== false ? this : this.toArray())._reverse();\
  \},\
\
  reduce: function() \{\
    return this.length > 1 ? this : this[0];\
  \},\
\
  uniq: function(sorted) \{\
    return this.inject([], function(array, value, index) \{\
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))\
        array.push(value);\
      return array;\
    \});\
  \},\
\
  intersect: function(array) \{\
    return this.uniq().findAll(function(item) \{\
      return array.detect(function(value) \{ return item === value \});\
    \});\
  \},\
\
  clone: function() \{\
    return [].concat(this);\
  \},\
\
  size: function() \{\
    return this.length;\
  \},\
\
  inspect: function() \{\
    return '[' + this.map(Object.inspect).join(', ') + ']';\
  \},\
\
  toJSON: function() \{\
    var results = [];\
    this.each(function(object) \{\
      var value = Object.toJSON(object);\
      if (value !== undefined) results.push(value);\
    \});\
    return '[' + results.join(', ') + ']';\
  \}\
\});\
\
// use native browser JS 1.6 implementation if available\
if (Object.isFunction(Array.prototype.forEach))\
  Array.prototype._each = Array.prototype.forEach;\
\
if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) \{\
  i || (i = 0);\
  var length = this.length;\
  if (i < 0) i = length + i;\
  for (; i < length; i++)\
    if (this[i] === item) return i;\
  return -1;\
\};\
\
if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) \{\
  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;\
  var n = this.slice(0, i).reverse().indexOf(item);\
  return (n < 0) ? n : i - n - 1;\
\};\
\
Array.prototype.toArray = Array.prototype.clone;\
\
function $w(string) \{\
  if (!Object.isString(string)) return [];\
  string = string.strip();\
  return string ? string.split(/\\s+/) : [];\
\}\
\
if (Prototype.Browser.Opera)\{\
  Array.prototype.concat = function() \{\
    var array = [];\
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);\
    for (var i = 0, length = arguments.length; i < length; i++) \{\
      if (Object.isArray(arguments[i])) \{\
        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)\
          array.push(arguments[i][j]);\
      \} else \{\
        array.push(arguments[i]);\
      \}\
    \}\
    return array;\
  \};\
\}\
Object.extend(Number.prototype, \{\
  toColorPart: function() \{\
    return this.toPaddedString(2, 16);\
  \},\
\
  succ: function() \{\
    return this + 1;\
  \},\
\
  times: function(iterator) \{\
    $R(0, this, true).each(iterator);\
    return this;\
  \},\
\
  toPaddedString: function(length, radix) \{\
    var string = this.toString(radix || 10);\
    return '0'.times(length - string.length) + string;\
  \},\
\
  toJSON: function() \{\
    return isFinite(this) ? this.toString() : 'null';\
  \}\
\});\
\
$w('abs round ceil floor').each(function(method)\{\
  Number.prototype[method] = Math[method].methodize();\
\});\
function $H(object) \{\
  return new Hash(object);\
\};\
\
var Hash = Class.create(Enumerable, (function() \{\
  if (function() \{\
    var i = 0, Test = function(value) \{ this.key = value \};\
    Test.prototype.key = 'foo';\
    for (var property in new Test('bar')) i++;\
    return i > 1;\
  \}()) \{\
    function each(iterator) \{\
      var cache = [];\
      for (var key in this._object) \{\
        var value = this._object[key];\
        if (cache.include(key)) continue;\
        cache.push(key);\
        var pair = [key, value];\
        pair.key = key;\
        pair.value = value;\
        iterator(pair);\
      \}\
    \}\
  \} else \{\
    function each(iterator) \{\
      for (var key in this._object) \{\
        var value = this._object[key], pair = [key, value];\
        pair.key = key;\
        pair.value = value;\
        iterator(pair);\
      \}\
    \}\
  \}\
\
  function toQueryPair(key, value) \{\
    if (Object.isUndefined(value)) return key;\
    return key + '=' + encodeURIComponent(String.interpret(value));\
  \}\
\
  return \{\
    initialize: function(object) \{\
      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);\
    \},\
\
    _each: each,\
\
    set: function(key, value) \{\
      return this._object[key] = value;\
    \},\
\
    get: function(key) \{\
      return this._object[key];\
    \},\
\
    unset: function(key) \{\
      var value = this._object[key];\
      delete this._object[key];\
      return value;\
    \},\
\
    toObject: function() \{\
      return Object.clone(this._object);\
    \},\
\
    keys: function() \{\
      return this.pluck('key');\
    \},\
\
    values: function() \{\
      return this.pluck('value');\
    \},\
\
    index: function(value) \{\
      var match = this.detect(function(pair) \{\
        return pair.value === value;\
      \});\
      return match && match.key;\
    \},\
\
    merge: function(object) \{\
      return this.clone().update(object);\
    \},\
\
    update: function(object) \{\
      return new Hash(object).inject(this, function(result, pair) \{\
        result.set(pair.key, pair.value);\
        return result;\
      \});\
    \},\
\
    toQueryString: function() \{\
      return this.map(function(pair) \{\
        var key = encodeURIComponent(pair.key), values = pair.value;\
\
        if (values && typeof values == 'object') \{\
          if (Object.isArray(values))\
            return values.map(toQueryPair.curry(key)).join('&');\
        \}\
        return toQueryPair(key, values);\
      \}).join('&');\
    \},\
\
    inspect: function() \{\
      return '#<Hash:\{' + this.map(function(pair) \{\
        return pair.map(Object.inspect).join(': ');\
      \}).join(', ') + '\}>';\
    \},\
\
    toJSON: function() \{\
      return Object.toJSON(this.toObject());\
    \},\
\
    clone: function() \{\
      return new Hash(this);\
    \}\
  \}\
\})());\
\
Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;\
Hash.from = $H;\
var ObjectRange = Class.create(Enumerable, \{\
  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(responder) \{\
    if (!this.include(responder))\
      this.responders.push(responder);\
  \},\
\
  unregister: function(responder) \{\
    this.responders = this.responders.without(responder);\
  \},\
\
  dispatch: function(callback, request, transport, json) \{\
    this.each(function(responder) \{\
      if (Object.isFunction(responder[callback])) \{\
        try \{\
          responder[callback].apply(responder, [request, transport, json]);\
        \} catch (e) \{ \}\
      \}\
    \});\
  \}\
\};\
\
Object.extend(Ajax.Responders, Enumerable);\
\
Ajax.Responders.register(\{\
  onCreate:   function() \{ Ajax.activeRequestCount++ \},\
  onComplete: function() \{ Ajax.activeRequestCount-- \}\
\});\
\
Ajax.Base = Class.create(\{\
  initialize: function(options) \{\
    this.options = \{\
      method:       'post',\
      asynchronous: true,\
      contentType:  'application/x-www-form-urlencoded',\
      encoding:     'UTF-8',\
      parameters:   '',\
      evalJSON:     true,\
      evalJS:       true\
    \};\
    Object.extend(this.options, options || \{ \});\
\
    this.options.method = this.options.method.toLowerCase();\
    if (Object.isString(this.options.parameters))\
      this.options.parameters = this.options.parameters.toQueryParams();\
  \}\
\});\
\
Ajax.Request = Class.create(Ajax.Base, \{\
  _complete: false,\
\
  initialize: function($super, url, options) \{\
    $super(options);\
    this.transport = Ajax.getTransport();\
    this.request(url);\
  \},\
\
  request: function(url) \{\
    this.url = url;\
    this.method = this.options.method;\
    var params = Object.clone(this.options.parameters);\
\
    if (!['get', 'post'].include(this.method)) \{\
      // simulate other verbs over post\
      params['_method'] = this.method;\
      this.method = 'post';\
    \}\
\
    this.parameters = params;\
\
    if (params = Object.toQueryString(params)) \{\
      // when GET, append parameters to URL\
      if (this.method == 'get')\
        this.url += (this.url.include('?') ? '&' : '?') + params;\
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))\
        params += '&_=';\
    \}\
\
    try \{\
      var response = new Ajax.Response(this);\
      if (this.options.onCreate) this.options.onCreate(response);\
      Ajax.Responders.dispatch('onCreate', this, response);\
\
      this.transport.open(this.method.toUpperCase(), this.url,\
        this.options.asynchronous);\
\
      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);\
\
      this.transport.onreadystatechange = this.onStateChange.bind(this);\
      this.setRequestHeaders();\
\
      this.body = this.method == 'post' ? (this.options.postBody || params) : null;\
      this.transport.send(this.body);\
\
      /* Force Firefox to handle ready state 4 for synchronous requests */\
      if (!this.options.asynchronous && this.transport.overrideMimeType)\
        this.onStateChange();\
\
    \}\
    catch (e) \{\
      this.dispatchException(e);\
    \}\
  \},\
\
  onStateChange: function() \{\
    var readyState = this.transport.readyState;\
    if (readyState > 1 && !((readyState == 4) && this._complete))\
      this.respondToReadyState(this.transport.readyState);\
  \},\
\
  setRequestHeaders: function() \{\
    var headers = \{\
      'X-Requested-With': 'XMLHttpRequest',\
      'X-Prototype-Version': Prototype.Version,\
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'\
    \};\
\
    if (this.method == 'post') \{\
      headers['Content-type'] = this.options.contentType +\
        (this.options.encoding ? '; charset=' + this.options.encoding : '');\
\
      /* Force "Connection: close" for older Mozilla browsers to work\
       * around a bug where XMLHttpRequest sends an incorrect\
       * Content-length header. See Mozilla Bugzilla #246651.\
       */\
      if (this.transport.overrideMimeType &&\
          (navigator.userAgent.match(/Gecko\\/(\\d\{4\})/) || [0,2005])[1] < 2005)\
            headers['Connection'] = 'close';\
    \}\
\
    // user-defined headers\
    if (typeof this.options.requestHeaders == 'object') \{\
      var extras = this.options.requestHeaders;\
\
      if (Object.isFunction(extras.push))\
        for (var i = 0, length = extras.length; i < length; i += 2)\
          headers[extras[i]] = extras[i+1];\
      else\
        $H(extras).each(function(pair) \{ headers[pair.key] = pair.value \});\
    \}\
\
    for (var name in headers)\
      this.transport.setRequestHeader(name, headers[name]);\
  \},\
\
  success: function() \{\
    var status = this.getStatus();\
    return !status || (status >= 200 && status < 300);\
  \},\
\
  getStatus: function() \{\
    try \{\
      return this.transport.status || 0;\
    \} catch (e) \{ return 0 \}\
  \},\
\
  respondToReadyState: function(readyState) \{\
    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);\
\
    if (state == 'Complete') \{\
      try \{\
        this._complete = true;\
        (this.options['on' + response.status]\
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]\
         || Prototype.emptyFunction)(response, response.headerJSON);\
      \} catch (e) \{\
        this.dispatchException(e);\
      \}\
\
      var contentType = response.getHeader('Content-type');\
      if (this.options.evalJS == 'force'\
          || (this.options.evalJS && contentType\
          && contentType.match(/^\\s*(text|application)\\/(x-)?(java|ecma)script(;.*)?\\s*$/i)))\
        this.evalResponse();\
    \}\
\
    try \{\
      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);\
      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);\
    \} catch (e) \{\
      this.dispatchException(e);\
    \}\
\
    if (state == 'Complete') \{\
      // avoid memory leak in MSIE: clean up\
      this.transport.onreadystatechange = Prototype.emptyFunction;\
    \}\
  \},\
\
  getHeader: function(name) \{\
    try \{\
      return this.transport.getResponseHeader(name);\
    \} catch (e) \{ return null \}\
  \},\
\
  evalResponse: function() \{\
    try \{\
      return eval((this.transport.responseText || '').unfilterJSON());\
    \} catch (e) \{\
      this.dispatchException(e);\
    \}\
  \},\
\
  dispatchException: function(exception) \{\
    (this.options.onException || Prototype.emptyFunction)(this, exception);\
    Ajax.Responders.dispatch('onException', this, exception);\
  \}\
\});\
\
Ajax.Request.Events =\
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\
\
Ajax.Response = Class.create(\{\
  initialize: function(request)\{\
    this.request = request;\
    var transport  = this.transport  = request.transport,\
        readyState = this.readyState = transport.readyState;\
\
    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) \{\
      this.status       = this.getStatus();\
      this.statusText   = this.getStatusText();\
      this.responseText = String.interpret(transport.responseText);\
      this.headerJSON   = this._getHeaderJSON();\
    \}\
\
    if(readyState == 4) \{\
      var xml = transport.responseXML;\
      this.responseXML  = xml === undefined ? null : xml;\
      this.responseJSON = this._getResponseJSON();\
    \}\
  \},\
\
  status:      0,\
  statusText: '',\
\
  getStatus: Ajax.Request.prototype.getStatus,\
\
  getStatusText: function() \{\
    try \{\
      return this.transport.statusText || '';\
    \} catch (e) \{ return '' \}\
  \},\
\
  getHeader: Ajax.Request.prototype.getHeader,\
\
  getAllHeaders: function() \{\
    try \{\
      return this.getAllResponseHeaders();\
    \} catch (e) \{ return null \}\
  \},\
\
  getResponseHeader: function(name) \{\
    return this.transport.getResponseHeader(name);\
  \},\
\
  getAllResponseHeaders: function() \{\
    return this.transport.getAllResponseHeaders();\
  \},\
\
  _getHeaderJSON: function() \{\
    var json = this.getHeader('X-JSON');\
    if (!json) return null;\
    json = decodeURIComponent(escape(json));\
    try \{\
      return json.evalJSON(this.request.options.sanitizeJSON);\
    \} catch (e) \{\
      this.request.dispatchException(e);\
    \}\
  \},\
\
  _getResponseJSON: function() \{\
    var options = this.request.options;\
    if (!options.evalJSON || (options.evalJSON != 'force' &&\
      !(this.getHeader('Content-type') || '').include('application/json')))\
        return null;\
    try \{\
      return this.transport.responseText.evalJSON(options.sanitizeJSON);\
    \} catch (e) \{\
      this.request.dispatchException(e);\
    \}\
  \}\
\});\
\
Ajax.Updater = Class.create(Ajax.Request, \{\
  initialize: function($super, container, url, options) \{\
    this.container = \{\
      success: (container.success || container),\
      failure: (container.failure || (container.success ? null : container))\
    \};\
\
    options = options || \{ \};\
    var onComplete = options.onComplete;\
    options.onComplete = (function(response, param) \{\
      this.updateContent(response.responseText);\
      if (Object.isFunction(onComplete)) onComplete(response, param);\
    \}).bind(this);\
\
    $super(url, options);\
  \},\
\
  updateContent: function(responseText) \{\
    var receiver = this.container[this.success() ? 'success' : 'failure'],\
        options = this.options;\
\
    if (!options.evalScripts) responseText = responseText.stripScripts();\
\
    if (receiver = $(receiver)) \{\
      if (options.insertion) \{\
        if (Object.isString(options.insertion)) \{\
          var insertion = \{ \}; insertion[options.insertion] = responseText;\
          receiver.insert(insertion);\
        \}\
        else options.insertion(receiver, responseText);\
      \}\
      else receiver.update(responseText);\
    \}\
\
    if (this.success()) \{\
      if (this.onComplete) this.onComplete.bind(this).defer();\
    \}\
  \}\
\});\
\
Ajax.PeriodicalUpdater = Class.create(Ajax.Base, \{\
  initialize: function($super, container, url, options) \{\
    $super(options);\
    this.onComplete = this.options.onComplete;\
\
    this.frequency = (this.options.frequency || 2);\
    this.decay = (this.options.decay || 1);\
\
    this.updater = \{ \};\
    this.container = container;\
    this.url = url;\
\
    this.start();\
  \},\
\
  start: function() \{\
    this.options.onComplete = this.updateComplete.bind(this);\
    this.onTimerEvent();\
  \},\
\
  stop: function() \{\
    this.updater.options.onComplete = undefined;\
    clearTimeout(this.timer);\
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);\
  \},\
\
  updateComplete: function(response) \{\
    if (this.options.decay) \{\
      this.decay = (response.responseText == this.lastText ?\
        this.decay * this.options.decay : 1);\
\
      this.lastText = response.responseText;\
    \}\
    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);\
  \},\
\
  onTimerEvent: function() \{\
    this.updater = new Ajax.Updater(this.container, this.url, this.options);\
  \}\
\});\
function $(element) \{\
  if (arguments.length > 1) \{\
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)\
      elements.push($(arguments[i]));\
    return elements;\
  \}\
  if (Object.isString(element))\
    element = document.getElementById(element);\
  return Element.extend(element);\
\}\
\
if (Prototype.BrowserFeatures.XPath) \{\
  document._getElementsByXPath = function(expression, parentElement) \{\
    var results = [];\
    var query = document.evaluate(expression, $(parentElement) || document,\
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\
    for (var i = 0, length = query.snapshotLength; i < length; i++)\
      results.push(Element.extend(query.snapshotItem(i)));\
    return results;\
  \};\
\}\
\
/*--------------------------------------------------------------------------*/\
\
if (!window.Node) var Node = \{ \};\
\
if (!Node.ELEMENT_NODE) \{\
  // DOM level 2 ECMAScript Language Binding\
  Object.extend(Node, \{\
    ELEMENT_NODE: 1,\
    ATTRIBUTE_NODE: 2,\
    TEXT_NODE: 3,\
    CDATA_SECTION_NODE: 4,\
    ENTITY_REFERENCE_NODE: 5,\
    ENTITY_NODE: 6,\
    PROCESSING_INSTRUCTION_NODE: 7,\
    COMMENT_NODE: 8,\
    DOCUMENT_NODE: 9,\
    DOCUMENT_TYPE_NODE: 10,\
    DOCUMENT_FRAGMENT_NODE: 11,\
    NOTATION_NODE: 12\
  \});\
\}\
\
(function() \{\
  var element = this.Element;\
  this.Element = function(tagName, attributes) \{\
    attributes = attributes || \{ \};\
    tagName = tagName.toLowerCase();\
    var cache = Element.cache;\
    if (Prototype.Browser.IE && attributes.name) \{\
      tagName = '<' + tagName + ' name="' + attributes.name + '">';\
      delete attributes.name;\
      return Element.writeAttribute(document.createElement(tagName), attributes);\
    \}\
    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));\
    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);\
  \};\
  Object.extend(this.Element, element || \{ \});\
\}).call(window);\
\
Element.cache = \{ \};\
\
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, content) \{\
    element = $(element);\
    if (content && content.toElement) content = content.toElement();\
    if (Object.isElement(content)) return element.update().insert(content);\
    content = Object.toHTML(content);\
    element.innerHTML = content.stripScripts();\
    content.evalScripts.bind(content).defer();\
    return element;\
  \},\
\
  replace: function(element, content) \{\
    element = $(element);\
    if (content && content.toElement) content = content.toElement();\
    else if (!Object.isElement(content)) \{\
      content = Object.toHTML(content);\
      var range = element.ownerDocument.createRange();\
      range.selectNode(element);\
      content.evalScripts.bind(content).defer();\
      content = range.createContextualFragment(content.stripScripts());\
    \}\
    element.parentNode.replaceChild(content, element);\
    return element;\
  \},\
\
  insert: function(element, insertions) \{\
    element = $(element);\
\
    if (Object.isString(insertions) || Object.isNumber(insertions) ||\
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))\
          insertions = \{bottom:insertions\};\
\
    var content, t, range;\
\
    for (position in insertions) \{\
      content  = insertions[position];\
      position = position.toLowerCase();\
      t = Element._insertionTranslations[position];\
\
      if (content && content.toElement) content = content.toElement();\
      if (Object.isElement(content)) \{\
        t.insert(element, content);\
        continue;\
      \}\
\
      content = Object.toHTML(content);\
\
      range = element.ownerDocument.createRange();\
      t.initializeRange(element, range);\
      t.insert(element, range.createContextualFragment(content.stripScripts()));\
\
      content.evalScripts.bind(content).defer();\
    \}\
\
    return element;\
  \},\
\
  wrap: function(element, wrapper, attributes) \{\
    element = $(element);\
    if (Object.isElement(wrapper))\
      $(wrapper).writeAttribute(attributes || \{ \});\
    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);\
    else wrapper = new Element('div', wrapper);\
    if (element.parentNode)\
      element.parentNode.replaceChild(wrapper, element);\
    wrapper.appendChild(element);\
    return wrapper;\
  \},\
\
  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) \{\
    return $A($(element).getElementsByTagName('*')).each(Element.extend);\
  \},\
\
  firstDescendant: function(element) \{\
    element = $(element).firstChild;\
    while (element && element.nodeType != 1) element = element.nextSibling;\
    return $(element);\
  \},\
\
  immediateDescendants: function(element) \{\
    if (!(element = $(element).firstChild)) return [];\
    while (element && element.nodeType != 1) element = element.nextSibling;\
    if (element) return [element].concat($(element).nextSiblings());\
    return [];\
  \},\
\
  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) \{\
    if (Object.isString(selector))\
      selector = new Selector(selector);\
    return selector.match($(element));\
  \},\
\
  up: function(element, expression, index) \{\
    element = $(element);\
    if (arguments.length == 1) return $(element.parentNode);\
    var ancestors = element.ancestors();\
    return expression ? Selector.findElement(ancestors, expression, index) :\
      ancestors[index || 0];\
  \},\
\
  down: function(element, expression, index) \{\
    element = $(element);\
    if (arguments.length == 1) return element.firstDescendant();\
    var descendants = element.descendants();\
    return expression ? Selector.findElement(descendants, expression, index) :\
      descendants[index || 0];\
  \},\
\
  previous: function(element, expression, index) \{\
    element = $(element);\
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));\
    var previousSiblings = element.previousSiblings();\
    return expression ? Selector.findElement(previousSiblings, expression, index) :\
      previousSiblings[index || 0];\
  \},\
\
  next: function(element, expression, index) \{\
    element = $(element);\
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));\
    var nextSiblings = element.nextSiblings();\
    return expression ? Selector.findElement(nextSiblings, expression, index) :\
      nextSiblings[index || 0];\
  \},\
\
  select: function() \{\
    var args = $A(arguments), element = $(args.shift());\
    return Selector.findChildElements(element, args);\
  \},\
\
  adjacent: function() \{\
    var args = $A(arguments), element = $(args.shift());\
    return Selector.findChildElements(element.parentNode, args).without(element);\
  \},\
\
  identify: function(element) \{\
    element = $(element);\
    var id = element.readAttribute('id'), self = arguments.callee;\
    if (id) return id;\
    do \{ id = 'anonymous_element_' + self.counter++ \} while ($(id));\
    element.writeAttribute('id', id);\
    return id;\
  \},\
\
  readAttribute: function(element, name) \{\
    element = $(element);\
    if (Prototype.Browser.IE) \{\
      var t = Element._attributeTranslations.read;\
      if (t.values[name]) return t.values[name](element, name);\
      if (t.names[name]) name = t.names[name];\
      if (name.include(':')) \{\
        return (!element.attributes || !element.attributes[name]) ? null :\
         element.attributes[name].value;\
      \}\
    \}\
    return element.getAttribute(name);\
  \},\
\
  writeAttribute: function(element, name, value) \{\
    element = $(element);\
    var attributes = \{ \}, t = Element._attributeTranslations.write;\
\
    if (typeof name == 'object') attributes = name;\
    else attributes[name] = value === undefined ? true : value;\
\
    for (var attr in attributes) \{\
      var name = t.names[attr] || attr, value = attributes[attr];\
      if (t.values[attr]) name = t.values[attr](element, value);\
      if (value === false || value === null)\
        element.removeAttribute(name);\
      else if (value === true)\
        element.setAttribute(name, name);\
      else element.setAttribute(name, value);\
    \}\
    return element;\
  \},\
\
  getHeight: function(element) \{\
    return $(element).getDimensions().height;\
  \},\
\
  getWidth: function(element) \{\
    return $(element).getDimensions().width;\
  \},\
\
  classNames: function(element) \{\
    return new Element.ClassNames(element);\
  \},\
\
  hasClassName: function(element, className) \{\
    if (!(element = $(element))) return;\
    var elementClassName = element.className;\
    return (elementClassName.length > 0 && (elementClassName == className ||\
      new RegExp("(^|\\\\s)" + className + "(\\\\s|$)").test(elementClassName)));\
  \},\
\
  addClassName: function(element, className) \{\
    if (!(element = $(element))) return;\
    if (!element.hasClassName(className))\
      element.className += (element.className ? ' ' : '') + className;\
    return element;\
  \},\
\
  removeClassName: function(element, className) \{\
    if (!(element = $(element))) return;\
    element.className = element.className.replace(\
      new RegExp("(^|\\\\s+)" + className + "(\\\\s+|$)"), ' ').strip();\
    return element;\
  \},\
\
  toggleClassName: function(element, className) \{\
    if (!(element = $(element))) return;\
    return element[element.hasClassName(className) ?\
      'removeClassName' : 'addClassName'](className);\
  \},\
\
  // 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.blank();\
  \},\
\
  descendantOf: function(element, ancestor) \{\
    element = $(element), ancestor = $(ancestor);\
\
    if (element.compareDocumentPosition)\
      return (element.compareDocumentPosition(ancestor) & 8) === 8;\
\
    if (element.sourceIndex && !Prototype.Browser.Opera) \{\
      var e = element.sourceIndex, a = ancestor.sourceIndex,\
       nextAncestor = ancestor.nextSibling;\
      if (!nextAncestor) \{\
        do \{ ancestor = ancestor.parentNode; \}\
        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);\
      \}\
      if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);\
    \}\
\
    while (element = element.parentNode)\
      if (element == ancestor) return true;\
    return false;\
  \},\
\
  scrollTo: function(element) \{\
    element = $(element);\
    var pos = element.cumulativeOffset();\
    window.scrollTo(pos[0], pos[1]);\
    return element;\
  \},\
\
  getStyle: function(element, style) \{\
    element = $(element);\
    style = style == 'float' ? 'cssFloat' : style.camelize();\
    var value = element.style[style];\
    if (!value) \{\
      var css = document.defaultView.getComputedStyle(element, null);\
      value = css ? css[style] : null;\
    \}\
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;\
    return value == 'auto' ? null : value;\
  \},\
\
  getOpacity: function(element) \{\
    return $(element).getStyle('opacity');\
  \},\
\
  setStyle: function(element, styles) \{\
    element = $(element);\
    var elementStyle = element.style, match;\
    if (Object.isString(styles)) \{\
      element.style.cssText += ';' + styles;\
      return styles.include('opacity') ?\
        element.setOpacity(styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1]) : element;\
    \}\
    for (var property in styles)\
      if (property == 'opacity') element.setOpacity(styles[property]);\
      else\
        elementStyle[(property == 'float' || property == 'cssFloat') ?\
          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :\
            property] = styles[property];\
\
    return element;\
  \},\
\
  setOpacity: function(element, value) \{\
    element = $(element);\
    element.style.opacity = (value == 1 || value === '') ? '' :\
      (value < 0.00001) ? 0 : value;\
    return element;\
  \},\
\
  getDimensions: function(element) \{\
    element = $(element);\
    var display = $(element).getStyle('display');\
    if (display != 'none' && display != null) // Safari bug\
      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;\
    var originalDisplay = els.display;\
    els.visibility = 'hidden';\
    els.position = 'absolute';\
    els.display = 'block';\
    var originalWidth = element.clientWidth;\
    var originalHeight = element.clientHeight;\
    els.display = originalDisplay;\
    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;\
    element._overflow = Element.getStyle(element, 'overflow') || 'auto';\
    if (element._overflow !== 'hidden')\
      element.style.overflow = 'hidden';\
    return element;\
  \},\
\
  undoClipping: function(element) \{\
    element = $(element);\
    if (!element._overflow) return element;\
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;\
    element._overflow = null;\
    return element;\
  \},\
\
  cumulativeOffset: function(element) \{\
    var valueT = 0, valueL = 0;\
    do \{\
      valueT += element.offsetTop  || 0;\
      valueL += element.offsetLeft || 0;\
      element = element.offsetParent;\
    \} while (element);\
    return Element._returnOffset(valueL, valueT);\
  \},\
\
  positionedOffset: function(element) \{\
    var valueT = 0, valueL = 0;\
    do \{\
      valueT += element.offsetTop  || 0;\
      valueL += element.offsetLeft || 0;\
      element = element.offsetParent;\
      if (element) \{\
        if (element.tagName == 'BODY') break;\
        var p = Element.getStyle(element, 'position');\
        if (p == 'relative' || p == 'absolute') break;\
      \}\
    \} while (element);\
    return Element._returnOffset(valueL, valueT);\
  \},\
\
  absolutize: function(element) \{\
    element = $(element);\
    if (element.getStyle('position') == 'absolute') return;\
    // Position.prepare(); // To be done manually by Scripty when it needs it.\
\
    var offsets = element.positionedOffset();\
    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';\
    return element;\
  \},\
\
  relativize: function(element) \{\
    element = $(element);\
    if (element.getStyle('position') == 'relative') return;\
    // Position.prepare(); // To be done manually by Scripty when it needs it.\
\
    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;\
    return element;\
  \},\
\
  cumulativeScrollOffset: function(element) \{\
    var valueT = 0, valueL = 0;\
    do \{\
      valueT += element.scrollTop  || 0;\
      valueL += element.scrollLeft || 0;\
      element = element.parentNode;\
    \} while (element);\
    return Element._returnOffset(valueL, valueT);\
  \},\
\
  getOffsetParent: 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);\
  \},\
\
  viewportOffset: 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 &&\
        Element.getStyle(element, 'position') == 'absolute') break;\
\
    \} while (element = element.offsetParent);\
\
    element = forElement;\
    do \{\
      if (!Prototype.Browser.Opera || element.tagName == 'BODY') \{\
        valueT -= element.scrollTop  || 0;\
        valueL -= element.scrollLeft || 0;\
      \}\
    \} while (element = element.parentNode);\
\
    return Element._returnOffset(valueL, valueT);\
  \},\
\
  clonePosition: function(element, source) \{\
    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 = source.viewportOffset();\
\
    // find coordinate system to use\
    element = $(element);\
    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(element, 'position') == 'absolute') \{\
      parent = element.getOffsetParent();\
      delta = parent.viewportOffset();\
    \}\
\
    // 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)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';\
    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';\
    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';\
    if (options.setHeight) element.style.height = source.offsetHeight + 'px';\
    return element;\
  \}\
\};\
\
Element.Methods.identify.counter = 1;\
\
Object.extend(Element.Methods, \{\
  getElementsBySelector: Element.Methods.select,\
  childElements: Element.Methods.immediateDescendants\
\});\
\
Element._attributeTranslations = \{\
  write: \{\
    names: \{\
      className: 'class',\
      htmlFor:   'for'\
    \},\
    values: \{ \}\
  \}\
\};\
\
\
if (!document.createRange || Prototype.Browser.Opera) \{\
  Element.Methods.insert = function(element, insertions) \{\
    element = $(element);\
\
    if (Object.isString(insertions) || Object.isNumber(insertions) ||\
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))\
          insertions = \{ bottom: insertions \};\
\
    var t = Element._insertionTranslations, content, position, pos, tagName;\
\
    for (position in insertions) \{\
      content  = insertions[position];\
      position = position.toLowerCase();\
      pos      = t[position];\
\
      if (content && content.toElement) content = content.toElement();\
      if (Object.isElement(content)) \{\
        pos.insert(element, content);\
        continue;\
      \}\
\
      content = Object.toHTML(content);\
      tagName = ((position == 'before' || position == 'after')\
        ? element.parentNode : element).tagName.toUpperCase();\
\
      if (t.tags[tagName]) \{\
        var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\
        if (position == 'top' || position == 'after') fragments.reverse();\
        fragments.each(pos.insert.curry(element));\
      \}\
      else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());\
\
      content.evalScripts.bind(content).defer();\
    \}\
\
    return element;\
  \};\
\}\
\
if (Prototype.Browser.Opera) \{\
  Element.Methods._getStyle = Element.Methods.getStyle;\
  Element.Methods.getStyle = function(element, style) \{\
    switch(style) \{\
      case 'left':\
      case 'top':\
      case 'right':\
      case 'bottom':\
        if (Element._getStyle(element, 'position') == 'static') return null;\
      default: return Element._getStyle(element, style);\
    \}\
  \};\
  Element.Methods._readAttribute = Element.Methods.readAttribute;\
  Element.Methods.readAttribute = function(element, attribute) \{\
    if (attribute == 'title') return element.title;\
    return Element._readAttribute(element, attribute);\
  \};\
\}\
\
else if (Prototype.Browser.IE) \{\
  $w('positionedOffset getOffsetParent viewportOffset').each(function(method) \{\
    Element.Methods[method] = Element.Methods[method].wrap(\
      function(proceed, element) \{\
        element = $(element);\
        var position = element.getStyle('position');\
        if (position != 'static') return proceed(element);\
        element.setStyle(\{ position: 'relative' \});\
        var value = proceed(element);\
        element.setStyle(\{ position: position \});\
        return value;\
      \}\
    );\
  \});\
\
  Element.Methods.getStyle = function(element, style) \{\
    element = $(element);\
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();\
    var value = element.style[style];\
    if (!value && element.currentStyle) value = element.currentStyle[style];\
\
    if (style == 'opacity') \{\
      if (value = (element.getStyle('filter') || '').match(/alpha\\(opacity=(.*)\\)/))\
        if (value[1]) return parseFloat(value[1]) / 100;\
      return 1.0;\
    \}\
\
    if (value == 'auto') \{\
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))\
        return element['offset' + style.capitalize()] + 'px';\
      return null;\
    \}\
    return value;\
  \};\
\
  Element.Methods.setOpacity = function(element, value) \{\
    function stripAlpha(filter)\{\
      return filter.replace(/alpha\\([^\\)]*\\)/gi,'');\
    \}\
    element = $(element);\
    var currentStyle = element.currentStyle;\
    if ((currentStyle && !currentStyle.hasLayout) ||\
      (!currentStyle && element.style.zoom == 'normal'))\
        element.style.zoom = 1;\
\
    var filter = element.getStyle('filter'), style = element.style;\
    if (value == 1 || value === '') \{\
      (filter = stripAlpha(filter)) ?\
        style.filter = filter : style.removeAttribute('filter');\
      return element;\
    \} else if (value < 0.00001) value = 0;\
    style.filter = stripAlpha(filter) +\
      'alpha(opacity=' + (value * 100) + ')';\
    return element;\
  \};\
\
  Element._attributeTranslations = \{\
    read: \{\
      names: \{\
        'class': 'className',\
        'for':   'htmlFor'\
      \},\
      values: \{\
        _getAttr: function(element, attribute) \{\
          return element.getAttribute(attribute, 2);\
        \},\
        _getAttrNode: function(element, attribute) \{\
          var node = element.getAttributeNode(attribute);\
          return node ? node.value : "";\
        \},\
        _getEv: function(element, attribute) \{\
          var attribute = element.getAttribute(attribute);\
          return attribute ? attribute.toString().slice(23, -2) : null;\
        \},\
        _flag: function(element, attribute) \{\
          return $(element).hasAttribute(attribute) ? attribute : null;\
        \},\
        style: function(element) \{\
          return element.style.cssText.toLowerCase();\
        \},\
        title: function(element) \{\
          return element.title;\
        \}\
      \}\
    \}\
  \};\
\
  Element._attributeTranslations.write = \{\
    names: Object.clone(Element._attributeTranslations.read.names),\
    values: \{\
      checked: function(element, value) \{\
        element.checked = !!value;\
      \},\
\
      style: function(element, value) \{\
        element.style.cssText = value ? value : '';\
      \}\
    \}\
  \};\
\
  Element._attributeTranslations.has = \{\};\
\
  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +\
      'encType maxLength readOnly longDesc').each(function(attr) \{\
    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;\
    Element._attributeTranslations.has[attr.toLowerCase()] = attr;\
  \});\
\
  (function(v) \{\
    Object.extend(v, \{\
      href:        v._getAttr,\
      src:         v._getAttr,\
      type:        v._getAttr,\
      action:      v._getAttrNode,\
      disabled:    v._flag,\
      checked:     v._flag,\
      readonly:    v._flag,\
      multiple:    v._flag,\
      onload:      v._getEv,\
      onunload:    v._getEv,\
      onclick:     v._getEv,\
      ondblclick:  v._getEv,\
      onmousedown: v._getEv,\
      onmouseup:   v._getEv,\
      onmouseover: v._getEv,\
      onmousemove: v._getEv,\
      onmouseout:  v._getEv,\
      onfocus:     v._getEv,\
      onblur:      v._getEv,\
      onkeypress:  v._getEv,\
      onkeydown:   v._getEv,\
      onkeyup:     v._getEv,\
      onsubmit:    v._getEv,\
      onreset:     v._getEv,\
      onselect:    v._getEv,\
      onchange:    v._getEv\
    \});\
  \})(Element._attributeTranslations.read.values);\
\}\
\
else if (Prototype.Browser.Gecko && /rv:1\\.8\\.0/.test(navigator.userAgent)) \{\
  Element.Methods.setOpacity = function(element, value) \{\
    element = $(element);\
    element.style.opacity = (value == 1) ? 0.999999 :\
      (value === '') ? '' : (value < 0.00001) ? 0 : value;\
    return element;\
  \};\
\}\
\
else if (Prototype.Browser.WebKit) \{\
  Element.Methods.setOpacity = function(element, value) \{\
    element = $(element);\
    element.style.opacity = (value == 1 || value === '') ? '' :\
      (value < 0.00001) ? 0 : value;\
\
    if (value == 1)\
      if(element.tagName == 'IMG' && element.width) \{\
        element.width++; element.width--;\
      \} else try \{\
        var n = document.createTextNode(' ');\
        element.appendChild(n);\
        element.removeChild(n);\
      \} catch (e) \{ \}\
\
    return element;\
  \};\
\
  // Safari returns margins on body which is incorrect if the child is absolutely\
  // positioned.  For performance reasons, redefine Position.cumulativeOffset for\
  // KHTML/WebKit only.\
  Element.Methods.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 Element._returnOffset(valueL, valueT);\
  \};\
\}\
\
if (Prototype.Browser.IE || Prototype.Browser.Opera) \{\
  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements\
  Element.Methods.update = function(element, content) \{\
    element = $(element);\
\
    if (content && content.toElement) content = content.toElement();\
    if (Object.isElement(content)) return element.update().insert(content);\
\
    content = Object.toHTML(content);\
    var tagName = element.tagName.toUpperCase();\
\
    if (tagName in Element._insertionTranslations.tags) \{\
      $A(element.childNodes).each(function(node) \{ element.removeChild(node) \});\
      Element._getContentFromAnonymousElement(tagName, content.stripScripts())\
        .each(function(node) \{ element.appendChild(node) \});\
    \}\
    else element.innerHTML = content.stripScripts();\
\
    content.evalScripts.bind(content).defer();\
    return element;\
  \};\
\}\
\
if (document.createElement('div').outerHTML) \{\
  Element.Methods.replace = function(element, content) \{\
    element = $(element);\
\
    if (content && content.toElement) content = content.toElement();\
    if (Object.isElement(content)) \{\
      element.parentNode.replaceChild(content, element);\
      return element;\
    \}\
\
    content = Object.toHTML(content);\
    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();\
\
    if (Element._insertionTranslations.tags[tagName]) \{\
      var nextSibling = element.next();\
      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\
      parent.removeChild(element);\
      if (nextSibling)\
        fragments.each(function(node) \{ parent.insertBefore(node, nextSibling) \});\
      else\
        fragments.each(function(node) \{ parent.appendChild(node) \});\
    \}\
    else element.outerHTML = content.stripScripts();\
\
    content.evalScripts.bind(content).defer();\
    return element;\
  \};\
\}\
\
Element._returnOffset = function(l, t) \{\
  var result = [l, t];\
  result.left = l;\
  result.top = t;\
  return result;\
\};\
\
Element._getContentFromAnonymousElement = function(tagName, html) \{\
  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];\
  div.innerHTML = t[0] + html + t[1];\
  t[2].times(function() \{ div = div.firstChild \});\
  return $A(div.childNodes);\
\};\
\
Element._insertionTranslations = \{\
  before: \{\
    adjacency: 'beforeBegin',\
    insert: function(element, node) \{\
      element.parentNode.insertBefore(node, element);\
    \},\
    initializeRange: function(element, range) \{\
      range.setStartBefore(element);\
    \}\
  \},\
  top: \{\
    adjacency: 'afterBegin',\
    insert: function(element, node) \{\
      element.insertBefore(node, element.firstChild);\
    \},\
    initializeRange: function(element, range) \{\
      range.selectNodeContents(element);\
      range.collapse(true);\
    \}\
  \},\
  bottom: \{\
    adjacency: 'beforeEnd',\
    insert: function(element, node) \{\
      element.appendChild(node);\
    \}\
  \},\
  after: \{\
    adjacency: 'afterEnd',\
    insert: function(element, node) \{\
      element.parentNode.insertBefore(node, element.nextSibling);\
    \},\
    initializeRange: function(element, range) \{\
      range.setStartAfter(element);\
    \}\
  \},\
  tags: \{\
    TABLE:  ['<table>',                '</table>',                   1],\
    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],\
    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],\
    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],\
    SELECT: ['<select>',               '</select>',                  1]\
  \}\
\};\
\
(function() \{\
  this.bottom.initializeRange = this.top.initializeRange;\
  Object.extend(this.tags, \{\
    THEAD: this.tags.TBODY,\
    TFOOT: this.tags.TBODY,\
    TH:    this.tags.TD\
  \});\
\}).call(Element._insertionTranslations);\
\
Element.Methods.Simulated = \{\
  hasAttribute: function(element, attribute) \{\
    attribute = Element._attributeTranslations.has[attribute] || attribute;\
    var node = $(element).getAttributeNode(attribute);\
    return node && node.specified;\
  \}\
\};\
\
Element.Methods.ByTag = \{ \};\
\
Object.extend(Element, Element.Methods);\
\
if (!Prototype.BrowserFeatures.ElementExtensions &&\
    document.createElement('div').__proto__) \{\
  window.HTMLElement = \{ \};\
  window.HTMLElement.prototype = document.createElement('div').__proto__;\
  Prototype.BrowserFeatures.ElementExtensions = true;\
\}\
\
Element.extend = (function() \{\
  if (Prototype.BrowserFeatures.SpecificElementExtensions)\
    return Prototype.K;\
\
  var Methods = \{ \}, ByTag = Element.Methods.ByTag;\
\
  var extend = Object.extend(function(element) \{\
    if (!element || element._extendedByPrototype ||\
        element.nodeType != 1 || element == window) return element;\
\
    var methods = Object.clone(Methods),\
      tagName = element.tagName, property, value;\
\
    // extend methods for specific tags\
    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);\
\
    for (property in methods) \{\
      value = methods[property];\
      if (Object.isFunction(value) && !(property in element))\
        element[property] = value.methodize();\
    \}\
\
    element._extendedByPrototype = Prototype.emptyFunction;\
    return element;\
\
  \}, \{\
    refresh: function() \{\
      // extend methods for all tags (Safari doesn't need this)\
      if (!Prototype.BrowserFeatures.ElementExtensions) \{\
        Object.extend(Methods, Element.Methods);\
        Object.extend(Methods, Element.Methods.Simulated);\
      \}\
    \}\
  \});\
\
  extend.refresh();\
  return extend;\
\})();\
\
Element.hasAttribute = function(element, attribute) \{\
  if (element.hasAttribute) return element.hasAttribute(attribute);\
  return Element.Methods.Simulated.hasAttribute(element, attribute);\
\};\
\
Element.addMethods = function(methods) \{\
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;\
\
  if (!methods) \{\
    Object.extend(Form, Form.Methods);\
    Object.extend(Form.Element, Form.Element.Methods);\
    Object.extend(Element.Methods.ByTag, \{\
      "FORM":     Object.clone(Form.Methods),\
      "INPUT":    Object.clone(Form.Element.Methods),\
      "SELECT":   Object.clone(Form.Element.Methods),\
      "TEXTAREA": Object.clone(Form.Element.Methods)\
    \});\
  \}\
\
  if (arguments.length == 2) \{\
    var tagName = methods;\
    methods = arguments[1];\
  \}\
\
  if (!tagName) Object.extend(Element.Methods, methods || \{ \});\
  else \{\
    if (Object.isArray(tagName)) tagName.each(extend);\
    else extend(tagName);\
  \}\
\
  function extend(tagName) \{\
    tagName = tagName.toUpperCase();\
    if (!Element.Methods.ByTag[tagName])\
      Element.Methods.ByTag[tagName] = \{ \};\
    Object.extend(Element.Methods.ByTag[tagName], methods);\
  \}\
\
  function copy(methods, destination, onlyIfAbsent) \{\
    onlyIfAbsent = onlyIfAbsent || false;\
    for (var property in methods) \{\
      var value = methods[property];\
      if (!Object.isFunction(value)) continue;\
      if (!onlyIfAbsent || !(property in destination))\
        destination[property] = value.methodize();\
    \}\
  \}\
\
  function findDOMClass(tagName) \{\
    var klass;\
    var trans = \{\
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",\
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",\
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",\
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",\
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":\
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":\
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":\
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":\
      "FrameSet", "IFRAME": "IFrame"\
    \};\
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';\
    if (window[klass]) return window[klass];\
    klass = 'HTML' + tagName + 'Element';\
    if (window[klass]) return window[klass];\
    klass = 'HTML' + tagName.capitalize() + 'Element';\
    if (window[klass]) return window[klass];\
\
    window[klass] = \{ \};\
    window[klass].prototype = document.createElement(tagName).__proto__;\
    return window[klass];\
  \}\
\
  if (F.ElementExtensions) \{\
    copy(Element.Methods, HTMLElement.prototype);\
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);\
  \}\
\
  if (F.SpecificElementExtensions) \{\
    for (var tag in Element.Methods.ByTag) \{\
      var klass = findDOMClass(tag);\
      if (Object.isUndefined(klass)) continue;\
      copy(T[tag], klass.prototype);\
    \}\
  \}\
\
  Object.extend(Element, Element.Methods);\
  delete Element.ByTag;\
\
  if (Element.extend.refresh) Element.extend.refresh();\
  Element.cache = \{ \};\
\};\
\
document.viewport = \{\
  getDimensions: function() \{\
    var dimensions = \{ \};\
    $w('width height').each(function(d) \{\
      var D = d.capitalize();\
      dimensions[d] = self['inner' + D] ||\
       (document.documentElement['client' + D] || document.body['client' + D]);\
    \});\
    return dimensions;\
  \},\
\
  getWidth: function() \{\
    return this.getDimensions().width;\
  \},\
\
  getHeight: function() \{\
    return this.getDimensions().height;\
  \},\
\
  getScrollOffsets: function() \{\
    return Element._returnOffset(\
      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,\
      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);\
  \}\
\};\
/* Portions of the Selector class are derived from Jack Slocum\'e2\'80\'99s DomQuery,\
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style\
 * license.  Please see http://www.yui-ext.com/ for more information. */\
\
var Selector = Class.create(\{\
  initialize: function(expression) \{\
    this.expression = expression.strip();\
    this.compileMatcher();\
  \},\
\
  compileMatcher: function() \{\
    // Selectors with namespaced attributes can't use the XPath version\
    if (Prototype.BrowserFeatures.XPath && !(/(\\[[\\w-]*?:|:checked)/).test(this.expression))\
      return this.compileXPathMatcher();\
\
    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,\
        c = Selector.criteria, le, p, m;\
\
    if (Selector._cache[e]) \{\
      this.matcher = Selector._cache[e];\
      return;\
    \}\
\
    this.matcher = ["this.matcher = function(root) \{",\
                    "var r = root, h = Selector.handlers, c = false, n;"];\
\
    while (e && le != e && (/\\S/).test(e)) \{\
      le = e;\
      for (var i in ps) \{\
        p = ps[i];\
        if (m = e.match(p)) \{\
          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :\
    	      new Template(c[i]).evaluate(m));\
          e = e.replace(m[0], '');\
          break;\
        \}\
      \}\
    \}\
\
    this.matcher.push("return h.unique(n);\\n\}");\
    eval(this.matcher.join('\\n'));\
    Selector._cache[this.expression] = this.matcher;\
  \},\
\
  compileXPathMatcher: function() \{\
    var e = this.expression, ps = Selector.patterns,\
        x = Selector.xpath, le, m;\
\
    if (Selector._cache[e]) \{\
      this.xpath = Selector._cache[e]; return;\
    \}\
\
    this.matcher = ['.//*'];\
    while (e && le != e && (/\\S/).test(e)) \{\
      le = e;\
      for (var i in ps) \{\
        if (m = e.match(ps[i])) \{\
          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :\
            new Template(x[i]).evaluate(m));\
          e = e.replace(m[0], '');\
          break;\
        \}\
      \}\
    \}\
\
    this.xpath = this.matcher.join('');\
    Selector._cache[this.expression] = this.xpath;\
  \},\
\
  findElements: function(root) \{\
    root = root || document;\
    if (this.xpath) return document._getElementsByXPath(this.xpath, root);\
    return this.matcher(root);\
  \},\
\
  match: function(element) \{\
    this.tokens = [];\
\
    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;\
    var le, p, m;\
\
    while (e && le !== e && (/\\S/).test(e)) \{\
      le = e;\
      for (var i in ps) \{\
        p = ps[i];\
        if (m = e.match(p)) \{\
          // use the Selector.assertions methods unless the selector\
          // is too complex.\
          if (as[i]) \{\
            this.tokens.push([i, Object.clone(m)]);\
            e = e.replace(m[0], '');\
          \} else \{\
            // reluctantly do a document-wide search\
            // and look for a match in the array\
            return this.findElements(document).include(element);\
          \}\
        \}\
      \}\
    \}\
\
    var match = true, name, matches;\
    for (var i = 0, token; token = this.tokens[i]; i++) \{\
      name = token[0], matches = token[1];\
      if (!Selector.assertions[name](element, matches)) \{\
        match = false; break;\
      \}\
    \}\
\
    return match;\
  \},\
\
  toString: function() \{\
    return this.expression;\
  \},\
\
  inspect: function() \{\
    return "#<Selector:" + this.expression.inspect() + ">";\
  \}\
\});\
\
Object.extend(Selector, \{\
  _cache: \{ \},\
\
  xpath: \{\
    descendant:   "//*",\
    child:        "/*",\
    adjacent:     "/following-sibling::*[1]",\
    laterSibling: '/following-sibling::*',\
    tagName:      function(m) \{\
      if (m[1] == '*') return '';\
      return "[local-name()='" + m[1].toLowerCase() +\
             "' or local-name()='" + m[1].toUpperCase() + "']";\
    \},\
    className:    "[contains(concat(' ', @class, ' '), ' #\{1\} ')]",\
    id:           "[@id='#\{1\}']",\
    attrPresence: "[@#\{1\}]",\
    attr: function(m) \{\
      m[3] = m[5] || m[6];\
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);\
    \},\
    pseudo: function(m) \{\
      var h = Selector.xpath.pseudos[m[1]];\
      if (!h) return '';\
      if (Object.isFunction(h)) return h(m);\
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);\
    \},\
    operators: \{\
      '=':  "[@#\{1\}='#\{3\}']",\
      '!=': "[@#\{1\}!='#\{3\}']",\
      '^=': "[starts-with(@#\{1\}, '#\{3\}')]",\
      '$=': "[substring(@#\{1\}, (string-length(@#\{1\}) - string-length('#\{3\}') + 1))='#\{3\}']",\
      '*=': "[contains(@#\{1\}, '#\{3\}')]",\
      '~=': "[contains(concat(' ', @#\{1\}, ' '), ' #\{3\} ')]",\
      '|=': "[contains(concat('-', @#\{1\}, '-'), '-#\{3\}-')]"\
    \},\
    pseudos: \{\
      'first-child': '[not(preceding-sibling::*)]',\
      'last-child':  '[not(following-sibling::*)]',\
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',\
      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \\t\\r\\n', '') = '')]",\
      'checked':     "[@checked]",\
      'disabled':    "[@disabled]",\
      'enabled':     "[not(@disabled)]",\
      'not': function(m) \{\
        var e = m[6], p = Selector.patterns,\
            x = Selector.xpath, le, m, v;\
\
        var exclusion = [];\
        while (e && le != e && (/\\S/).test(e)) \{\
          le = e;\
          for (var i in p) \{\
            if (m = e.match(p[i])) \{\
              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);\
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");\
              e = e.replace(m[0], '');\
              break;\
            \}\
          \}\
        \}\
        return "[not(" + exclusion.join(" and ") + ")]";\
      \},\
      'nth-child':      function(m) \{\
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);\
      \},\
      'nth-last-child': function(m) \{\
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);\
      \},\
      'nth-of-type':    function(m) \{\
        return Selector.xpath.pseudos.nth("position() ", m);\
      \},\
      'nth-last-of-type': function(m) \{\
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);\
      \},\
      'first-of-type':  function(m) \{\
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);\
      \},\
      'last-of-type':   function(m) \{\
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);\
      \},\
      'only-of-type':   function(m) \{\
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);\
      \},\
      nth: function(fragment, m) \{\
        var mm, formula = m[6], predicate;\
        if (formula == 'even') formula = '2n+0';\
        if (formula == 'odd')  formula = '2n+1';\
        if (mm = formula.match(/^(\\d+)$/)) // digit only\
          return '[' + fragment + "= " + mm[1] + ']';\
        if (mm = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) \{ // an+b\
          if (mm[1] == "-") mm[1] = -1;\
          var a = mm[1] ? Number(mm[1]) : 1;\
          var b = mm[2] ? Number(mm[2]) : 0;\
          predicate = "[((#\{fragment\} - #\{b\}) mod #\{a\} = 0) and " +\
          "((#\{fragment\} - #\{b\}) div #\{a\} >= 0)]";\
          return new Template(predicate).evaluate(\{\
            fragment: fragment, a: a, b: b \});\
        \}\
      \}\
    \}\
  \},\
\
  criteria: \{\
    tagName:      'n = h.tagName(n, r, "#\{1\}", c);   c = false;',\
    className:    'n = h.className(n, r, "#\{1\}", c); c = false;',\
    id:           'n = h.id(n, r, "#\{1\}", c);        c = false;',\
    attrPresence: 'n = h.attrPresence(n, r, "#\{1\}"); c = false;',\
    attr: function(m) \{\
      m[3] = (m[5] || m[6]);\
      return new Template('n = h.attr(n, r, "#\{1\}", "#\{3\}", "#\{2\}"); c = false;').evaluate(m);\
    \},\
    pseudo: function(m) \{\
      if (m[6]) m[6] = m[6].replace(/"/g, '\\\\"');\
      return new Template('n = h.pseudo(n, "#\{1\}", "#\{6\}", r, c); c = false;').evaluate(m);\
    \},\
    descendant:   'c = "descendant";',\
    child:        'c = "child";',\
    adjacent:     'c = "adjacent";',\
    laterSibling: 'c = "laterSibling";'\
  \},\
\
  patterns: \{\
    // combinators must be listed first\
    // (and descendant needs to be last combinator)\
    laterSibling: /^\\s*~\\s*/,\
    child:        /^\\s*>\\s*/,\
    adjacent:     /^\\s*\\+\\s*/,\
    descendant:   /^\\s/,\
\
    // selectors follow\
    tagName:      /^\\s*(\\*|[\\w\\-]+)(\\b|$)?/,\
    id:           /^#([\\w\\-\\*]+)(\\b|$)/,\
    className:    /^\\.([\\w\\-\\*]+)(\\b|$)/,\
    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\\((.*?)\\))?(\\b|$|(?=\\s)|(?=:))/,\
    attrPresence: /^\\[([\\w]+)\\]/,\
    attr:         /\\[((?:[\\w-]*:)?[\\w-]+)\\s*(?:([!^$*~|]?=)\\s*((['"])([^\\4]*?)\\4|([^'"][^\\]]*?)))?\\]/\
  \},\
\
  // for Selector.match and Element#match\
  assertions: \{\
    tagName: function(element, matches) \{\
      return matches[1].toUpperCase() == element.tagName.toUpperCase();\
    \},\
\
    className: function(element, matches) \{\
      return Element.hasClassName(element, matches[1]);\
    \},\
\
    id: function(element, matches) \{\
      return element.id === matches[1];\
    \},\
\
    attrPresence: function(element, matches) \{\
      return Element.hasAttribute(element, matches[1]);\
    \},\
\
    attr: function(element, matches) \{\
      var nodeValue = Element.readAttribute(element, matches[1]);\
      return Selector.operators[matches[2]](nodeValue, matches[3]);\
    \}\
  \},\
\
  handlers: \{\
    // UTILITY FUNCTIONS\
    // joins two collections\
    concat: function(a, b) \{\
      for (var i = 0, node; node = b[i]; i++)\
        a.push(node);\
      return a;\
    \},\
\
    // marks an array of nodes for counting\
    mark: function(nodes) \{\
      for (var i = 0, node; node = nodes[i]; i++)\
        node._counted = true;\
      return nodes;\
    \},\
\
    unmark: function(nodes) \{\
      for (var i = 0, node; node = nodes[i]; i++)\
        node._counted = undefined;\
      return nodes;\
    \},\
\
    // mark each child node with its position (for nth calls)\
    // "ofType" flag indicates whether we're indexing for nth-of-type\
    // rather than nth-child\
    index: function(parentNode, reverse, ofType) \{\
      parentNode._counted = true;\
      if (reverse) \{\
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) \{\
          var node = nodes[i];\
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;\
        \}\
      \} else \{\
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)\
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;\
      \}\
    \},\
\
    // filters out duplicates and extends all nodes\
    unique: function(nodes) \{\
      if (nodes.length == 0) return nodes;\
      var results = [], n;\
      for (var i = 0, l = nodes.length; i < l; i++)\
        if (!(n = nodes[i])._counted) \{\
          n._counted = true;\
          results.push(Element.extend(n));\
        \}\
      return Selector.handlers.unmark(results);\
    \},\
\
    // COMBINATOR FUNCTIONS\
    descendant: function(nodes) \{\
      var h = Selector.handlers;\
      for (var i = 0, results = [], node; node = nodes[i]; i++)\
        h.concat(results, node.getElementsByTagName('*'));\
      return results;\
    \},\
\
    child: function(nodes) \{\
      var h = Selector.handlers;\
      for (var i = 0, results = [], node; node = nodes[i]; i++) \{\
        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)\
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);\
      \}\
      return results;\
    \},\
\
    adjacent: function(nodes) \{\
      for (var i = 0, results = [], node; node = nodes[i]; i++) \{\
        var next = this.nextElementSibling(node);\
        if (next) results.push(next);\
      \}\
      return results;\
    \},\
\
    laterSibling: function(nodes) \{\
      var h = Selector.handlers;\
      for (var i = 0, results = [], node; node = nodes[i]; i++)\
        h.concat(results, Element.nextSiblings(node));\
      return results;\
    \},\
\
    nextElementSibling: function(node) \{\
      while (node = node.nextSibling)\
	      if (node.nodeType == 1) return node;\
      return null;\
    \},\
\
    previousElementSibling: function(node) \{\
      while (node = node.previousSibling)\
        if (node.nodeType == 1) return node;\
      return null;\
    \},\
\
    // TOKEN FUNCTIONS\
    tagName: function(nodes, root, tagName, combinator) \{\
      tagName = tagName.toUpperCase();\
      var results = [], h = Selector.handlers;\
      if (nodes) \{\
        if (combinator) \{\
          // fastlane for ordinary descendant combinators\
          if (combinator == "descendant") \{\
            for (var i = 0, node; node = nodes[i]; i++)\
              h.concat(results, node.getElementsByTagName(tagName));\
            return results;\
          \} else nodes = this[combinator](nodes);\
          if (tagName == "*") return nodes;\
        \}\
        for (var i = 0, node; node = nodes[i]; i++)\
          if (node.tagName.toUpperCase() == tagName) results.push(node);\
        return results;\
      \} else return root.getElementsByTagName(tagName);\
    \},\
\
    id: function(nodes, root, id, combinator) \{\
      var targetNode = $(id), h = Selector.handlers;\
      if (!targetNode) return [];\
      if (!nodes && root == document) return [targetNode];\
      if (nodes) \{\
        if (combinator) \{\
          if (combinator == 'child') \{\
            for (var i = 0, node; node = nodes[i]; i++)\
              if (targetNode.parentNode == node) return [targetNode];\
          \} else if (combinator == 'descendant') \{\
            for (var i = 0, node; node = nodes[i]; i++)\
              if (Element.descendantOf(targetNode, node)) return [targetNode];\
          \} else if (combinator == 'adjacent') \{\
            for (var i = 0, node; node = nodes[i]; i++)\
              if (Selector.handlers.previousElementSibling(targetNode) == node)\
                return [targetNode];\
          \} else nodes = h[combinator](nodes);\
        \}\
        for (var i = 0, node; node = nodes[i]; i++)\
          if (node == targetNode) return [targetNode];\
        return [];\
      \}\
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];\
    \},\
\
    className: function(nodes, root, className, combinator) \{\
      if (nodes && combinator) nodes = this[combinator](nodes);\
      return Selector.handlers.byClassName(nodes, root, className);\
    \},\
\
    byClassName: function(nodes, root, className) \{\
      if (!nodes) nodes = Selector.handlers.descendant([root]);\
      var needle = ' ' + className + ' ';\
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) \{\
        nodeClassName = node.className;\
        if (nodeClassName.length == 0) continue;\
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))\
          results.push(node);\
      \}\
      return results;\
    \},\
\
    attrPresence: function(nodes, root, attr) \{\
      if (!nodes) nodes = root.getElementsByTagName("*");\
      var results = [];\
      for (var i = 0, node; node = nodes[i]; i++)\
        if (Element.hasAttribute(node, attr)) results.push(node);\
      return results;\
    \},\
\
    attr: function(nodes, root, attr, value, operator) \{\
      if (!nodes) nodes = root.getElementsByTagName("*");\
      var handler = Selector.operators[operator], results = [];\
      for (var i = 0, node; node = nodes[i]; i++) \{\
        var nodeValue = Element.readAttribute(node, attr);\
        if (nodeValue === null) continue;\
        if (handler(nodeValue, value)) results.push(node);\
      \}\
      return results;\
    \},\
\
    pseudo: function(nodes, name, value, root, combinator) \{\
      if (nodes && combinator) nodes = this[combinator](nodes);\
      if (!nodes) nodes = root.getElementsByTagName("*");\
      return Selector.pseudos[name](nodes, value, root);\
    \}\
  \},\
\
  pseudos: \{\
    'first-child': function(nodes, value, root) \{\
      for (var i = 0, results = [], node; node = nodes[i]; i++) \{\
        if (Selector.handlers.previousElementSibling(node)) continue;\
          results.push(node);\
      \}\
      return results;\
    \},\
    'last-child': function(nodes, value, root) \{\
      for (var i = 0, results = [], node; node = nodes[i]; i++) \{\
        if (Selector.handlers.nextElementSibling(node)) continue;\
          results.push(node);\
      \}\
      return results;\
    \},\
    'only-child': function(nodes, value, root) \{\
      var h = Selector.handlers;\
      for (var i = 0, results = [], node; node = nodes[i]; i++)\
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))\
          results.push(node);\
      return results;\
    \},\
    'nth-child':        function(nodes, formula, root) \{\
      return Selector.pseudos.nth(nodes, formula, root);\
    \},\
    'nth-last-child':   function(nodes, formula, root) \{\
      return Selector.pseudos.nth(nodes, formula, root, true);\
    \},\
    'nth-of-type':      function(nodes, formula, root) \{\
      return Selector.pseudos.nth(nodes, formula, root, false, true);\
    \},\
    'nth-last-of-type': function(nodes, formula, root) \{\
      return Selector.pseudos.nth(nodes, formula, root, true, true);\
    \},\
    'first-of-type':    function(nodes, formula, root) \{\
      return Selector.pseudos.nth(nodes, "1", root, false, true);\
    \},\
    'last-of-type':     function(nodes, formula, root) \{\
      return Selector.pseudos.nth(nodes, "1", root, true, true);\
    \},\
    'only-of-type':     function(nodes, formula, root) \{\
      var p = Selector.pseudos;\
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);\
    \},\
\
    // handles the an+b logic\
    getIndices: function(a, b, total) \{\
      if (a == 0) return b > 0 ? [b] : [];\
      return $R(1, total).inject([], function(memo, i) \{\
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);\
        return memo;\
      \});\
    \},\
\
    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type\
    nth: function(nodes, formula, root, reverse, ofType) \{\
      if (nodes.length == 0) return [];\
      if (formula == 'even') formula = '2n+0';\
      if (formula == 'odd')  formula = '2n+1';\
      var h = Selector.handlers, results = [], indexed = [], m;\
      h.mark(nodes);\
      for (var i = 0, node; node = nodes[i]; i++) \{\
        if (!node.parentNode._counted) \{\
          h.index(node.parentNode, reverse, ofType);\
          indexed.push(node.parentNode);\
        \}\
      \}\
      if (formula.match(/^\\d+$/)) \{ // just a number\
        formula = Number(formula);\
        for (var i = 0, node; node = nodes[i]; i++)\
          if (node.nodeIndex == formula) results.push(node);\
      \} else if (m = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) \{ // an+b\
        if (m[1] == "-") m[1] = -1;\
        var a = m[1] ? Number(m[1]) : 1;\
        var b = m[2] ? Number(m[2]) : 0;\
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);\
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) \{\
          for (var j = 0; j < l; j++)\
            if (node.nodeIndex == indices[j]) results.push(node);\
        \}\
      \}\
      h.unmark(nodes);\
      h.unmark(indexed);\
      return results;\
    \},\
\
    'empty': function(nodes, value, root) \{\
      for (var i = 0, results = [], node; node = nodes[i]; i++) \{\
        // IE treats comments as element nodes\
        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\\s*$/))) continue;\
        results.push(node);\
      \}\
      return results;\
    \},\
\
    'not': function(nodes, selector, root) \{\
      var h = Selector.handlers, selectorType, m;\
      var exclusions = new Selector(selector).findElements(root);\
      h.mark(exclusions);\
      for (var i = 0, results = [], node; node = nodes[i]; i++)\
        if (!node._counted) results.push(node);\
      h.unmark(exclusions);\
      return results;\
    \},\
\
    'enabled': function(nodes, value, root) \{\
      for (var i = 0, results = [], node; node = nodes[i]; i++)\
        if (!node.disabled) results.push(node);\
      return results;\
    \},\
\
    'disabled': function(nodes, value, root) \{\
      for (var i = 0, results = [], node; node = nodes[i]; i++)\
        if (node.disabled) results.push(node);\
      return results;\
    \},\
\
    'checked': function(nodes, value, root) \{\
      for (var i = 0, results = [], node; node = nodes[i]; i++)\
        if (node.checked) results.push(node);\
      return results;\
    \}\
  \},\
\
  operators: \{\
    '=':  function(nv, v) \{ return nv == v; \},\
    '!=': function(nv, v) \{ return nv != v; \},\
    '^=': function(nv, v) \{ return nv.startsWith(v); \},\
    '$=': function(nv, v) \{ return nv.endsWith(v); \},\
    '*=': function(nv, v) \{ return nv.include(v); \},\
    '~=': function(nv, v) \{ return (' ' + nv + ' ').include(' ' + v + ' '); \},\
    '|=': function(nv, v) \{ return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); \}\
  \},\
\
  matchElements: function(elements, expression) \{\
    var matches = new Selector(expression).findElements(), h = Selector.handlers;\
    h.mark(matches);\
    for (var i = 0, results = [], element; element = elements[i]; i++)\
      if (element._counted) results.push(element);\
    h.unmark(matches);\
    return results;\
  \},\
\
  findElement: function(elements, expression, index) \{\
    if (Object.isNumber(expression)) \{\
      index = expression; expression = false;\
    \}\
    return Selector.matchElements(elements, expression || '*')[index || 0];\
  \},\
\
  findChildElements: function(element, expressions) \{\
    var exprs = expressions.join(','), expressions = [];\
    exprs.scan(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/, function(m) \{\
      expressions.push(m[1].strip());\
    \});\
    var results = [], h = Selector.handlers;\
    for (var i = 0, l = expressions.length, selector; i < l; i++) \{\
      selector = new Selector(expressions[i].strip());\
      h.concat(results, selector.findElements(element));\
    \}\
    return (l > 1) ? h.unique(results) : results;\
  \}\
\});\
\
function $$() \{\
  return Selector.findChildElements(document, $A(arguments));\
\}\
var Form = \{\
  reset: function(form) \{\
    $(form).reset();\
    return form;\
  \},\
\
  serializeElements: function(elements, options) \{\
    if (typeof options != 'object') options = \{ hash: !!options \};\
    else if (options.hash === undefined) options.hash = true;\
    var key, value, submitted = false, submit = options.submit;\
\
    var data = elements.inject(\{ \}, function(result, element) \{\
      if (!element.disabled && element.name) \{\
        key = element.name; value = $(element).getValue();\
        if (value != null && (element.type != 'submit' || (!submitted &&\
            submit !== false && (!submit || key == submit) && (submitted = true)))) \{\
          if (key in result) \{\
            // a key is already present; construct an array of values\
            if (!Object.isArray(result[key])) result[key] = [result[key]];\
            result[key].push(value);\
          \}\
          else result[key] = value;\
        \}\
      \}\
      return result;\
    \});\
\
    return options.hash ? data : Object.toQueryString(data);\
  \}\
\};\
\
Form.Methods = \{\
  serialize: function(form, options) \{\
    return Form.serializeElements(Form.getElements(form), options);\
  \},\
\
  getElements: function(form) \{\
    return $A($(form).getElementsByTagName('*')).inject([],\
      function(elements, child) \{\
        if (Form.Element.Serializers[child.tagName.toLowerCase()])\
          elements.push(Element.extend(child));\
        return elements;\
      \}\
    );\
  \},\
\
  getInputs: function(form, typeName, name) \{\
    form = $(form);\
    var inputs = form.getElementsByTagName('input');\
\
    if (!typeName && !name) return $A(inputs).map(Element.extend);\
\
    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) \{\
      var input = inputs[i];\
      if ((typeName && input.type != typeName) || (name && input.name != name))\
        continue;\
      matchingInputs.push(Element.extend(input));\
    \}\
\
    return matchingInputs;\
  \},\
\
  disable: function(form) \{\
    form = $(form);\
    Form.getElements(form).invoke('disable');\
    return form;\
  \},\
\
  enable: function(form) \{\
    form = $(form);\
    Form.getElements(form).invoke('enable');\
    return form;\
  \},\
\
  findFirstElement: function(form) \{\
    var elements = $(form).getElements().findAll(function(element) \{\
      return 'hidden' != element.type && !element.disabled;\
    \});\
    var firstByIndex = elements.findAll(function(element) \{\
      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;\
    \}).sortBy(function(element) \{ return element.tabIndex \}).first();\
\
    return firstByIndex ? firstByIndex : elements.find(function(element) \{\
      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());\
    \});\
  \},\
\
  focusFirstElement: function(form) \{\
    form = $(form);\
    form.findFirstElement().activate();\
    return form;\
  \},\
\
  request: function(form, options) \{\
    form = $(form), options = Object.clone(options || \{ \});\
\
    var params = options.parameters, action = form.readAttribute('action') || '';\
    if (action.blank()) action = window.location.href;\
    options.parameters = form.serialize(true);\
\
    if (params) \{\
      if (Object.isString(params)) params = params.toQueryParams();\
      Object.extend(options.parameters, params);\
    \}\
\
    if (form.hasAttribute('method') && !options.method)\
      options.method = form.method;\
\
    return new Ajax.Request(action, options);\
  \}\
\};\
\
/*--------------------------------------------------------------------------*/\
\
Form.Element = \{\
  focus: function(element) \{\
    $(element).focus();\
    return element;\
  \},\
\
  select: function(element) \{\
    $(element).select();\
    return element;\
  \}\
\};\
\
Form.Element.Methods = \{\
  serialize: function(element) \{\
    element = $(element);\
    if (!element.disabled && element.name) \{\
      var value = element.getValue();\
      if (value != undefined) \{\
        var pair = \{ \};\
        pair[element.name] = value;\
        return Object.toQueryString(pair);\
      \}\
    \}\
    return '';\
  \},\
\
  getValue: function(element) \{\
    element = $(element);\
    var method = element.tagName.toLowerCase();\
    return Form.Element.Serializers[method](element);\
  \},\
\
  setValue: function(element, value) \{\
    element = $(element);\
    var method = element.tagName.toLowerCase();\
    Form.Element.Serializers[method](element, value);\
    return element;\
  \},\
\
  clear: function(element) \{\
    $(element).value = '';\
    return element;\
  \},\
\
  present: function(element) \{\
    return $(element).value != '';\
  \},\
\
  activate: function(element) \{\
    element = $(element);\
    try \{\
      element.focus();\
      if (element.select && (element.tagName.toLowerCase() != 'input' ||\
          !['button', 'reset', 'submit'].include(element.type)))\
        element.select();\
    \} catch (e) \{ \}\
    return element;\
  \},\
\
  disable: function(element) \{\
    element = $(element);\
    element.blur();\
    element.disabled = true;\
    return element;\
  \},\
\
  enable: function(element) \{\
    element = $(element);\
    element.disabled = false;\
    return element;\
  \}\
\};\
\
/*--------------------------------------------------------------------------*/\
\
var Field = Form.Element;\
var $F = Form.Element.Methods.getValue;\
\
/*--------------------------------------------------------------------------*/\
\
Form.Element.Serializers = \{\
  input: function(element, value) \{\
    switch (element.type.toLowerCase()) \{\
      case 'checkbox':\
      case 'radio':\
        return Form.Element.Serializers.inputSelector(element, value);\
      default:\
        return Form.Element.Serializers.textarea(element, value);\
    \}\
  \},\
\
  inputSelector: function(element, value) \{\
    if (value === undefined) return element.checked ? element.value : null;\
    else element.checked = !!value;\
  \},\
\
  textarea: function(element, value) \{\
    if (value === undefined) return element.value;\
    else element.value = value;\
  \},\
\
  select: function(element, index) \{\
    if (index === undefined)\
      return this[element.type == 'select-one' ?\
        'selectOne' : 'selectMany'](element);\
    else \{\
      var opt, value, single = !Object.isArray(index);\
      for (var i = 0, length = element.length; i < length; i++) \{\
        opt = element.options[i];\
        value = this.optionValue(opt);\
        if (single) \{\
          if (value == index) \{\
            opt.selected = true;\
            return;\
          \}\
        \}\
        else opt.selected = index.include(value);\
      \}\
    \}\
  \},\
\
  selectOne: function(element) \{\
    var index = element.selectedIndex;\
    return index >= 0 ? this.optionValue(element.options[index]) : null;\
  \},\
\
  selectMany: function(element) \{\
    var values, length = element.length;\
    if (!length) return null;\
\
    for (var i = 0, values = []; i < length; i++) \{\
      var opt = element.options[i];\
      if (opt.selected) values.push(this.optionValue(opt));\
    \}\
    return values;\
  \},\
\
  optionValue: function(opt) \{\
    // extend element because hasAttribute may not be native\
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;\
  \}\
\};\
\
/*--------------------------------------------------------------------------*/\
\
Abstract.TimedObserver = Class.create(PeriodicalExecuter, \{\
  initialize: function($super, element, frequency, callback) \{\
    $super(callback, frequency);\
    this.element   = $(element);\
    this.lastValue = this.getValue();\
  \},\
\
  execute: function() \{\
    var value = this.getValue();\
    if (Object.isString(this.lastValue) && Object.isString(value) ?\
        this.lastValue != value : String(this.lastValue) != String(value)) \{\
      this.callback(this.element, value);\
      this.lastValue = value;\
    \}\
  \}\
\});\
\
Form.Element.Observer = Class.create(Abstract.TimedObserver, \{\
  getValue: function() \{\
    return Form.Element.getValue(this.element);\
  \}\
\});\
\
Form.Observer = Class.create(Abstract.TimedObserver, \{\
  getValue: function() \{\
    return Form.serialize(this.element);\
  \}\
\});\
\
/*--------------------------------------------------------------------------*/\
\
Abstract.EventObserver = Class.create(\{\
  initialize: function(element, callback) \{\
    this.element  = $(element);\
    this.callback = callback;\
\
    this.lastValue = this.getValue();\
    if (this.element.tagName.toLowerCase() == 'form')\
      this.registerFormCallbacks();\
    else\
      this.registerCallback(this.element);\
  \},\
\
  onElementEvent: function() \{\
    var value = this.getValue();\
    if (this.lastValue != value) \{\
      this.callback(this.element, value);\
      this.lastValue = value;\
    \}\
  \},\
\
  registerFormCallbacks: function() \{\
    Form.getElements(this.element).each(this.registerCallback, this);\
  \},\
\
  registerCallback: function(element) \{\
    if (element.type) \{\
      switch (element.type.toLowerCase()) \{\
        case 'checkbox':\
        case 'radio':\
          Event.observe(element, 'click', this.onElementEvent.bind(this));\
          break;\
        default:\
          Event.observe(element, 'change', this.onElementEvent.bind(this));\
          break;\
      \}\
    \}\
  \}\
\});\
\
Form.Element.EventObserver = Class.create(Abstract.EventObserver, \{\
  getValue: function() \{\
    return Form.Element.getValue(this.element);\
  \}\
\});\
\
Form.EventObserver = Class.create(Abstract.EventObserver, \{\
  getValue: function() \{\
    return Form.serialize(this.element);\
  \}\
\});\
if (!window.Event) var Event = \{ \};\
\
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,\
  KEY_INSERT:   45,\
\
  cache: \{ \},\
\
  relatedTarget: function(event) \{\
    var element;\
    switch(event.type) \{\
      case 'mouseover': element = event.fromElement; break;\
      case 'mouseout':  element = event.toElement;   break;\
      default: return null;\
    \}\
    return Element.extend(element);\
  \}\
\});\
\
Event.Methods = (function() \{\
  var isButton;\
\
  if (Prototype.Browser.IE) \{\
    var buttonMap = \{ 0: 1, 1: 4, 2: 2 \};\
    isButton = function(event, code) \{\
      return event.button == buttonMap[code];\
    \};\
\
  \} else if (Prototype.Browser.WebKit) \{\
    isButton = function(event, code) \{\
      switch (code) \{\
        case 0: return event.which == 1 && !event.metaKey;\
        case 1: return event.which == 1 && event.metaKey;\
        default: return false;\
      \}\
    \};\
\
  \} else \{\
    isButton = function(event, code) \{\
      return event.which ? (event.which === code + 1) : (event.button === code);\
    \};\
  \}\
\
  return \{\
    isLeftClick:   function(event) \{ return isButton(event, 0) \},\
    isMiddleClick: function(event) \{ return isButton(event, 1) \},\
    isRightClick:  function(event) \{ return isButton(event, 2) \},\
\
    element: function(event) \{\
      var node = Event.extend(event).target;\
      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);\
    \},\
\
    findElement: function(event, expression) \{\
      var element = Event.element(event);\
      return element.match(expression) ? element : element.up(expression);\
    \},\
\
    pointer: function(event) \{\
      return \{\
        x: event.pageX || (event.clientX +\
          (document.documentElement.scrollLeft || document.body.scrollLeft)),\
        y: event.pageY || (event.clientY +\
          (document.documentElement.scrollTop || document.body.scrollTop))\
      \};\
    \},\
\
    pointerX: function(event) \{ return Event.pointer(event).x \},\
    pointerY: function(event) \{ return Event.pointer(event).y \},\
\
    stop: function(event) \{\
      Event.extend(event);\
      event.preventDefault();\
      event.stopPropagation();\
      event.stopped = true;\
    \}\
  \};\
\})();\
\
Event.extend = (function() \{\
  var methods = Object.keys(Event.Methods).inject(\{ \}, function(m, name) \{\
    m[name] = Event.Methods[name].methodize();\
    return m;\
  \});\
\
  if (Prototype.Browser.IE) \{\
    Object.extend(methods, \{\
      stopPropagation: function() \{ this.cancelBubble = true \},\
      preventDefault:  function() \{ this.returnValue = false \},\
      inspect: function() \{ return "[object Event]" \}\
    \});\
\
    return function(event) \{\
      if (!event) return false;\
      if (event._extendedByPrototype) return event;\
\
      event._extendedByPrototype = Prototype.emptyFunction;\
      var pointer = Event.pointer(event);\
      Object.extend(event, \{\
        target: event.srcElement,\
        relatedTarget: Event.relatedTarget(event),\
        pageX:  pointer.x,\
        pageY:  pointer.y\
      \});\
      return Object.extend(event, methods);\
    \};\
\
  \} else \{\
    Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;\
    Object.extend(Event.prototype, methods);\
    return Prototype.K;\
  \}\
\})();\
\
Object.extend(Event, (function() \{\
  var cache = Event.cache;\
\
  function getEventID(element) \{\
    if (element._eventID) return element._eventID;\
    arguments.callee.id = arguments.callee.id || 1;\
    return element._eventID = ++arguments.callee.id;\
  \}\
\
  function getDOMEventName(eventName) \{\
    if (eventName && eventName.include(':')) return "dataavailable";\
    return eventName;\
  \}\
\
  function getCacheForID(id) \{\
    return cache[id] = cache[id] || \{ \};\
  \}\
\
  function getWrappersForEventName(id, eventName) \{\
    var c = getCacheForID(id);\
    return c[eventName] = c[eventName] || [];\
  \}\
\
  function createWrapper(element, eventName, handler) \{\
    var id = getEventID(element);\
    var c = getWrappersForEventName(id, eventName);\
    if (c.pluck("handler").include(handler)) return false;\
\
    var wrapper = function(event) \{\
      if (!Event || !Event.extend ||\
        (event.eventName && event.eventName != eventName))\
          return false;\
\
      Event.extend(event);\
      handler.call(element, event)\
    \};\
\
    wrapper.handler = handler;\
    c.push(wrapper);\
    return wrapper;\
  \}\
\
  function findWrapper(id, eventName, handler) \{\
    var c = getWrappersForEventName(id, eventName);\
    return c.find(function(wrapper) \{ return wrapper.handler == handler \});\
  \}\
\
  function destroyWrapper(id, eventName, handler) \{\
    var c = getCacheForID(id);\
    if (!c[eventName]) return false;\
    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));\
  \}\
\
  function destroyCache() \{\
    for (var id in cache)\
      for (var eventName in cache[id])\
        cache[id][eventName] = null;\
  \}\
\
  if (window.attachEvent) \{\
    window.attachEvent("onunload", destroyCache);\
  \}\
\
  return \{\
    observe: function(element, eventName, handler) \{\
      element = $(element);\
      var name = getDOMEventName(eventName);\
\
      var wrapper = createWrapper(element, eventName, handler);\
      if (!wrapper) return element;\
\
      if (element.addEventListener) \{\
        element.addEventListener(name, wrapper, false);\
      \} else \{\
        element.attachEvent("on" + name, wrapper);\
      \}\
\
      return element;\
    \},\
\
    stopObserving: function(element, eventName, handler) \{\
      element = $(element);\
      var id = getEventID(element), name = getDOMEventName(eventName);\
\
      if (!handler && eventName) \{\
        getWrappersForEventName(id, eventName).each(function(wrapper) \{\
          element.stopObserving(eventName, wrapper.handler);\
        \});\
        return element;\
\
      \} else if (!eventName) \{\
        Object.keys(getCacheForID(id)).each(function(eventName) \{\
          element.stopObserving(eventName);\
        \});\
        return element;\
      \}\
\
      var wrapper = findWrapper(id, eventName, handler);\
      if (!wrapper) return element;\
\
      if (element.removeEventListener) \{\
        element.removeEventListener(name, wrapper, false);\
      \} else \{\
        element.detachEvent("on" + name, wrapper);\
      \}\
\
      destroyWrapper(id, eventName, handler);\
\
      return element;\
    \},\
\
    fire: function(element, eventName, memo) \{\
      element = $(element);\
      if (element == document && document.createEvent && !element.dispatchEvent)\
        element = document.documentElement;\
\
      if (document.createEvent) \{\
        var event = document.createEvent("HTMLEvents");\
        event.initEvent("dataavailable", true, true);\
      \} else \{\
        var event = document.createEventObject();\
        event.eventType = "ondataavailable";\
      \}\
\
      event.eventName = eventName;\
      event.memo = memo || \{ \};\
\
      if (document.createEvent) \{\
        element.dispatchEvent(event);\
      \} else \{\
        element.fireEvent(event.eventType, event);\
      \}\
\
      return event;\
    \}\
  \};\
\})());\
\
Object.extend(Event, Event.Methods);\
\
Element.addMethods(\{\
  fire:          Event.fire,\
  observe:       Event.observe,\
  stopObserving: Event.stopObserving\
\});\
\
Object.extend(document, \{\
  fire:          Element.Methods.fire.methodize(),\
  observe:       Element.Methods.observe.methodize(),\
  stopObserving: Element.Methods.stopObserving.methodize()\
\});\
\
(function() \{\
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,\
     Matthias Miller, Dean Edwards and John Resig. */\
\
  var timer, fired = false;\
\
  function fireContentLoadedEvent() \{\
    if (fired) return;\
    if (timer) window.clearInterval(timer);\
    document.fire("dom:loaded");\
    fired = true;\
  \}\
\
  if (document.addEventListener) \{\
    if (Prototype.Browser.WebKit) \{\
      timer = window.setInterval(function() \{\
        if (/loaded|complete/.test(document.readyState))\
          fireContentLoadedEvent();\
      \}, 0);\
\
      Event.observe(window, "load", fireContentLoadedEvent);\
\
    \} else \{\
      document.addEventListener("DOMContentLoaded",\
        fireContentLoadedEvent, false);\
    \}\
\
  \} else \{\
    document.write("<script id=__onDOMContentLoaded defer src=//:><\\/script>");\
    $("__onDOMContentLoaded").onreadystatechange = function() \{\
      if (this.readyState == "complete") \{\
        this.onreadystatechange = null;\
        fireContentLoadedEvent();\
      \}\
    \};\
  \}\
\})();\
/*------------------------------- DEPRECATED -------------------------------*/\
\
Hash.toQueryString = Object.toQueryString;\
\
var Toggle = \{ display: Element.toggle \};\
\
Element.Methods.childOf = Element.Methods.descendantOf;\
\
var Insertion = \{\
  Before: function(element, content) \{\
    return Element.insert(element, \{before:content\});\
  \},\
\
  Top: function(element, content) \{\
    return Element.insert(element, \{top:content\});\
  \},\
\
  Bottom: function(element, content) \{\
    return Element.insert(element, \{bottom:content\});\
  \},\
\
  After: function(element, content) \{\
    return Element.insert(element, \{after:content\});\
  \}\
\};\
\
var $continue = new Error('"throw $continue" is deprecated, use "return" instead');\
\
// This should be moved to script.aculo.us; notice the deprecated methods\
// further below, that map to the newer Element methods.\
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;\
  \},\
\
  // 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 = Element.cumulativeOffset(element);\
\
    return (y >= this.offset[1] &&\
            y <  this.offset[1] + element.offsetHeight &&\
            x >= this.offset[0] &&\
            x <  this.offset[0] + element.offsetWidth);\
  \},\
\
  withinIncludingScrolloffsets: function(element, x, y) \{\
    var offsetcache = Element.cumulativeScrollOffset(element);\
\
    this.xcomp = x + offsetcache[0] - this.deltaX;\
    this.ycomp = y + offsetcache[1] - this.deltaY;\
    this.offset = Element.cumulativeOffset(element);\
\
    return (this.ycomp >= this.offset[1] &&\
            this.ycomp <  this.offset[1] + element.offsetHeight &&\
            this.xcomp >= this.offset[0] &&\
            this.xcomp <  this.offset[0] + element.offsetWidth);\
  \},\
\
  // 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;\
  \},\
\
  // Deprecation layer -- use newer Element methods now (1.5.2).\
\
  cumulativeOffset: Element.Methods.cumulativeOffset,\
\
  positionedOffset: Element.Methods.positionedOffset,\
\
  absolutize: function(element) \{\
    Position.prepare();\
    return Element.absolutize(element);\
  \},\
\
  relativize: function(element) \{\
    Position.prepare();\
    return Element.relativize(element);\
  \},\
\
  realOffset: Element.Methods.cumulativeScrollOffset,\
\
  offsetParent: Element.Methods.getOffsetParent,\
\
  page: Element.Methods.viewportOffset,\
\
  clone: function(source, target, options) \{\
    options = options || \{ \};\
    return Element.clonePosition(target, source, options);\
  \}\
\};\
\
/*--------------------------------------------------------------------------*/\
\
if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods)\{\
  function iter(name) \{\
    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";\
  \}\
\
  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?\
  function(element, className) \{\
    className = className.toString().strip();\
    var cond = /\\s/.test(className) ? $w(className).map(iter).join('') : iter(className);\
    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];\
  \} : function(element, className) \{\
    className = className.toString().strip();\
    var elements = [], classNames = (/\\s/.test(className) ? $w(className) : null);\
    if (!classNames && !className) return elements;\
\
    var nodes = $(element).getElementsByTagName('*');\
    className = ' ' + className + ' ';\
\
    for (var i = 0, child, cn; child = nodes[i]; i++) \{\
      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||\
          (classNames && classNames.all(function(name) \{\
            return !name.toString().blank() && cn.include(' ' + name + ' ');\
          \}))))\
        elements.push(Element.extend(child));\
    \}\
    return elements;\
  \};\
\
  return function(className, parentElement) \{\
    return $(parentElement || document.body).getElementsByClassName(className);\
  \};\
\}(Element.Methods);\
\
/*--------------------------------------------------------------------------*/\
\
Element.ClassNames = Class.create();\
Element.ClassNames.prototype = \{\
  initialize: function(element) \{\
    this.element = $(element);\
  \},\
\
  _each: function(iterator) \{\
    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($A(this).concat(classNameToAdd).join(' '));\
  \},\
\
  remove: function(classNameToRemove) \{\
    if (!this.include(classNameToRemove)) return;\
    this.set($A(this).without(classNameToRemove).join(' '));\
  \},\
\
  toString: function() \{\
    return $A(this).join(' ');\
  \}\
\};\
\
Object.extend(Element.ClassNames.prototype, Enumerable);\
\
/*--------------------------------------------------------------------------*/\
\
Element.addMethods();\
}