/*  Prototype JavaScript framework, version 1.4.0 
 *  (c) 2005 Sam Stephenson <sam@conio.net> 
 * 
 *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff 
 *  against the source tree, available from the Prototype darcs repository. 
 * 
 *  Prototype is freely distributable under the terms of an MIT-style license. 
 * 
 *  For details, see the Prototype web site: http://prototype.conio.net/ 
 * 
/*--------------------------------------------------------------------------*/ 
 
var Prototype = { 
  Version: '1.4.0', 
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', 
 
  emptyFunction: function() {}, 
  K: function(x) {return x} 
} 
 
var Class = { 
  create: function() { 
    return function() { 
      this.initialize.apply(this, arguments); 
    } 
  } 
} 
 
var Abstract = new Object(); 
 
Object.extend = function(destination, source) { 
  for (property in source) { 
    destination[property] = source[property]; 
  } 
  return destination; 
} 
 
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; 
  } 
} 
 
Function.prototype.bind = function() { 
  var __method = this, args = $A(arguments), object = args.shift(); 
  return function() { 
    return __method.apply(object, args.concat($A(arguments))); 
  } 
} 
 
Function.prototype.bindAsEventListener = function(object) { 
  var __method = this; 
  return function(event) { 
    return __method.call(object, event || window.event); 
  } 
} 
 
Object.extend(Number.prototype, { 
  toColorPart: function() { 
    var digits = this.toString(16); 
    if (this < 16) return '0' + digits; 
    return digits; 
  }, 
 
  succ: function() { 
    return this + 1; 
  }, 
 
  times: function(iterator) { 
    $R(0, this, true).each(iterator); 
    return this; 
  } 
}); 
 
var Try = { 
  these: function() { 
    var returnValue; 
 
    for (var i = 0; i < arguments.length; i++) { 
      var lambda = arguments[i]; 
      try { 
        returnValue = lambda(); 
        break; 
      } catch (e) {} 
    } 
 
    return returnValue; 
  } 
} 
 
/*--------------------------------------------------------------------------*/ 
 
var PeriodicalExecuter = Class.create(); 
PeriodicalExecuter.prototype = { 
  initialize: function(callback, frequency) { 
    this.callback = callback; 
    this.frequency = frequency; 
    this.currentlyExecuting = false; 
 
    this.registerCallback(); 
  }, 
 
  registerCallback: function() { 
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 
  }, 
 
  onTimerEvent: function() { 
    if (!this.currentlyExecuting) { 
      try { 
        this.currentlyExecuting = true; 
        this.callback(); 
      } finally { 
        this.currentlyExecuting = false; 
      } 
    } 
  } 
} 
 
/*--------------------------------------------------------------------------*/ 
 
function $() { 
  var elements = new Array(); 
 
  for (var i = 0; i < arguments.length; i++) { 
    var element = arguments[i]; 
    if (typeof element == 'string') 
      element = document.getElementById(element); 
 
    if (arguments.length == 1) 
      return element; 
 
    elements.push(element); 
  } 
 
  return elements; 
} 
Object.extend(String.prototype, { 
  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(eval); 
  }, 
 
  escapeHTML: function() { 
    var div = document.createElement('div'); 
    var text = document.createTextNode(this); 
    div.appendChild(text); 
    return div.innerHTML; 
  }, 
 
  unescapeHTML: function() { 
    var div = document.createElement('div'); 
    div.innerHTML = this.stripTags(); 
    return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; 
  }, 
 
  toQueryParams: function() { 
    var pairs = this.match(/^\??(.*)$/)[1].split('&'); 
    return pairs.inject({}, function(params, pairString) { 
      var pair = pairString.split('='); 
      params[pair[0]] = pair[1]; 
      return params; 
    }); 
  }, 
 
  toArray: function() { 
    return this.split(''); 
  }, 
 
  camelize: function() { 
    var oStringList = this.split('-'); 
    if (oStringList.length == 1) return oStringList[0]; 
 
    var camelizedString = this.indexOf('-') == 0 
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) 
      : oStringList[0]; 
 
    for (var i = 1, len = oStringList.length; i < len; i++) { 
      var s = oStringList[i]; 
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1); 
    } 
 
    return camelizedString; 
  }, 
 
  inspect: function() { 
    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; 
  } 
}); 
 
String.prototype.parseQuery = String.prototype.toQueryParams; 
 
var $break    = new Object(); 
var $continue = new Object(); 
 
var Enumerable = { 
  each: function(iterator) { 
    var index = 0; 
    try { 
      this._each(function(value) { 
        try { 
          iterator(value, index++); 
        } catch (e) { 
          if (e != $continue) throw e; 
        } 
      }); 
    } catch (e) { 
      if (e != $break) throw e; 
    } 
  }, 
 
  all: function(iterator) { 
    var result = true; 
    this.each(function(value, index) { 
      result = result && !!(iterator || Prototype.K)(value, index); 
      if (!result) throw $break; 
    }); 
    return result; 
  }, 
 
  any: function(iterator) { 
    var result = true; 
    this.each(function(value, index) { 
      if (result = !!(iterator || Prototype.K)(value, index)) 
        throw $break; 
    }); 
    return result; 
  }, 
 
  collect: function(iterator) { 
    var results = []; 
    this.each(function(value, index) { 
      results.push(iterator(value, index)); 
    }); 
    return results; 
  }, 
 
  detect: function (iterator) { 
    var result; 
    this.each(function(value, index) { 
      if (iterator(value, index)) { 
        result = value; 
        throw $break; 
      } 
    }); 
    return result; 
  }, 
 
  findAll: function(iterator) { 
    var results = []; 
    this.each(function(value, index) { 
      if (iterator(value, index)) 
        results.push(value); 
    }); 
    return results; 
  }, 
 
  grep: function(pattern, iterator) { 
    var results = []; 
    this.each(function(value, index) { 
      var stringValue = value.toString(); 
      if (stringValue.match(pattern)) 
        results.push((iterator || Prototype.K)(value, index)); 
    }) 
    return results; 
  }, 
 
  include: function(object) { 
    var found = false; 
    this.each(function(value) { 
      if (value == object) { 
        found = true; 
        throw $break; 
      } 
    }); 
    return found; 
  }, 
 
  inject: function(memo, iterator) { 
    this.each(function(value, index) { 
      memo = iterator(memo, value, index); 
    }); 
    return memo; 
  }, 
 
  invoke: function(method) { 
    var args = $A(arguments).slice(1); 
    return this.collect(function(value) { 
      return value[method].apply(value, args); 
    }); 
  }, 
 
  max: function(iterator) { 
    var result; 
    this.each(function(value, index) { 
      value = (iterator || Prototype.K)(value, index); 
      if (value >= (result || value)) 
        result = value; 
    }); 
    return result; 
  }, 
 
  min: function(iterator) { 
    var result; 
    this.each(function(value, index) { 
      value = (iterator || Prototype.K)(value, index); 
      if (value <= (result || value)) 
        result = value; 
    }); 
    return result; 
  }, 
 
  partition: function(iterator) { 
    var trues = [], falses = []; 
    this.each(function(value, index) { 
      ((iterator || Prototype.K)(value, index) ? 
        trues : falses).push(value); 
    }); 
    return [trues, falses]; 
  }, 
 
  pluck: function(property) { 
    var results = []; 
    this.each(function(value, index) { 
      results.push(value[property]); 
    }); 
    return results; 
  }, 
 
  reject: function(iterator) { 
    var results = []; 
    this.each(function(value, index) { 
      if (!iterator(value, index)) 
        results.push(value); 
    }); 
    return results; 
  }, 
 
  sortBy: function(iterator) { 
    return this.collect(function(value, index) { 
      return {value: value, criteria: iterator(value, index)}; 
    }).sort(function(left, right) { 
      var a = left.criteria, b = right.criteria; 
      return a < b ? -1 : a > b ? 1 : 0; 
    }).pluck('value'); 
  }, 
 
  toArray: function() { 
    return this.collect(Prototype.K); 
  }, 
 
  zip: function() { 
    var iterator = Prototype.K, args = $A(arguments); 
    if (typeof args.last() == 'function') 
      iterator = args.pop(); 
 
    var collections = [this].concat(args).map($A); 
    return this.map(function(value, index) { 
      iterator(value = collections.pluck(index)); 
      return value; 
    }); 
  }, 
 
  inspect: function() { 
    return '#<Enumerable:' + this.toArray().inspect() + '>'; 
  } 
} 
 
Object.extend(Enumerable, { 
  map:     Enumerable.collect, 
  find:    Enumerable.detect, 
  select:  Enumerable.findAll, 
  member:  Enumerable.include, 
  entries: Enumerable.toArray 
}); 
var $A = Array.from = function(iterable) { 
  if (!iterable) return []; 
  if (iterable.toArray) { 
    return iterable.toArray(); 
  } else { 
    var results = []; 
    for (var i = 0; i < iterable.length; i++) 
      results.push(iterable[i]); 
    return results; 
  } 
} 
 
Object.extend(Array.prototype, Enumerable); 
 
Array.prototype._reverse = Array.prototype.reverse; 
 
Object.extend(Array.prototype, { 
  _each: function(iterator) { 
    for (var i = 0; i < this.length; i++) 
      iterator(this[i]); 
  }, 
 
  clear: function() { 
    this.length = 0; 
    return this; 
  }, 
 
  first: function() { 
    return this[0]; 
  }, 
 
  last: function() { 
    return this[this.length - 1]; 
  }, 
 
  compact: function() { 
    return this.select(function(value) { 
      return value != undefined || value != null; 
    }); 
  }, 
 
  flatten: function() { 
    return this.inject([], function(array, value) { 
      return array.concat(value.constructor == Array ? 
        value.flatten() : [value]); 
    }); 
  }, 
 
  without: function() { 
    var values = $A(arguments); 
    return this.select(function(value) { 
      return !values.include(value); 
    }); 
  }, 
 
  indexOf: function(object) { 
    for (var i = 0; i < this.length; i++) 
      if (this[i] == object) return i; 
    return -1; 
  }, 
 
  reverse: function(inline) { 
    return (inline !== false ? this : this.toArray())._reverse(); 
  }, 
 
  shift: function() { 
    var result = this[0]; 
    for (var i = 0; i < this.length - 1; i++) 
      this[i] = this[i + 1]; 
    this.length--; 
    return result; 
  }, 
 
  inspect: function() { 
    return '[' + this.map(Object.inspect).join(', ') + ']'; 
  } 
}); 
var Hash = { 
  _each: function(iterator) { 
    for (key in this) { 
      var value = this[key]; 
      if (typeof value == 'function') continue; 
 
      var pair = [key, value]; 
      pair.key = key; 
      pair.value = value; 
      iterator(pair); 
    } 
  }, 
 
  keys: function() { 
    return this.pluck('key'); 
  }, 
 
  values: function() { 
    return this.pluck('value'); 
  }, 
 
  merge: function(hash) { 
    return $H(hash).inject($H(this), function(mergedHash, pair) { 
      mergedHash[pair.key] = pair.value; 
      return mergedHash; 
    }); 
  }, 
 
  toQueryString: function() { 
    return this.map(function(pair) { 
      return pair.map(encodeURIComponent).join('='); 
    }).join('&'); 
  }, 
 
  inspect: function() { 
    return '#<Hash:{' + this.map(function(pair) { 
      return pair.map(Object.inspect).join(': '); 
    }).join(', ') + '}>'; 
  } 
} 
 
function $H(object) { 
  var hash = Object.extend({}, object || {}); 
  Object.extend(hash, Enumerable); 
  Object.extend(hash, Hash); 
  return hash; 
} 
ObjectRange = Class.create(); 
Object.extend(ObjectRange.prototype, Enumerable); 
Object.extend(ObjectRange.prototype, { 
  initialize: function(start, end, exclusive) { 
    this.start = start; 
    this.end = end; 
    this.exclusive = exclusive; 
  }, 
 
  _each: function(iterator) { 
    var value = this.start; 
    do { 
      iterator(value); 
      value = value.succ(); 
    } while (this.include(value)); 
  }, 
 
  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 ActiveXObject('Msxml2.XMLHTTP')}, 
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}, 
      function() {return new XMLHttpRequest()} 
    ) || false; 
  }, 
 
  activeRequestCount: 0 
} 
 
Ajax.Responders = { 
  responders: [], 
 
  _each: function(iterator) { 
    this.responders._each(iterator); 
  }, 
 
  register: function(responderToAdd) { 
    if (!this.include(responderToAdd)) 
      this.responders.push(responderToAdd); 
  }, 
 
  unregister: function(responderToRemove) { 
    this.responders = this.responders.without(responderToRemove); 
  }, 
 
  dispatch: function(callback, request, transport, json) { 
    this.each(function(responder) { 
      if (responder[callback] && typeof responder[callback] == 'function') { 
        try { 
          responder[callback].apply(responder, [request, transport, json]); 
        } catch (e) {} 
      } 
    }); 
  } 
}; 
 
Object.extend(Ajax.Responders, Enumerable); 
 
Ajax.Responders.register({ 
  onCreate: function() { 
    Ajax.activeRequestCount++; 
  }, 
 
  onComplete: function() { 
    Ajax.activeRequestCount--; 
  } 
}); 
 
Ajax.Base = function() {}; 
Ajax.Base.prototype = { 
  setOptions: function(options) { 
    this.options = { 
      method:       'post', 
      asynchronous: true, 
      parameters:   '' 
    } 
    Object.extend(this.options, options || {}); 
  }, 
 
  responseIsSuccess: function() { 
    return this.transport.status == undefined 
        || this.transport.status == 0 
        || (this.transport.status >= 200 && this.transport.status < 300); 
  }, 
 
  responseIsFailure: function() { 
    return !this.responseIsSuccess(); 
  } 
} 
 
Ajax.Request = Class.create(); 
Ajax.Request.Events = 
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 
 
Ajax.Request.prototype = Object.extend(new Ajax.Base(), { 
  initialize: function(url, options) { 
    this.transport = Ajax.getTransport(); 
    this.setOptions(options); 
    this.request(url); 
  }, 
 
  request: function(url) { 
    var parameters = this.options.parameters || ''; 
    if (parameters.length > 0) parameters += '&_='; 
 
    try { 
      this.url = url; 
      if (this.options.method == 'get' && parameters.length > 0) 
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; 
 
      Ajax.Responders.dispatch('onCreate', this, this.transport); 
 
      this.transport.open(this.options.method, this.url, 
        this.options.asynchronous); 
 
      if (this.options.asynchronous) { 
        this.transport.onreadystatechange = this.onStateChange.bind(this); 
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); 
      } 
 
      this.setRequestHeaders(); 
 
      var body = this.options.postBody ? this.options.postBody : parameters; 
      this.transport.send(this.options.method == 'post' ? body : null); 
 
    } catch (e) { 
      this.dispatchException(e); 
    } 
  }, 
 
  setRequestHeaders: function() { 
    var requestHeaders = 
      ['X-Requested-With', 'XMLHttpRequest', 
       'X-Prototype-Version', Prototype.Version]; 
 
    if (this.options.method == 'post') { 
      requestHeaders.push('Content-type', 
        'application/x-www-form-urlencoded'); 
 
      /* Force "Connection: close" for Mozilla browsers to work around 
       * a bug where XMLHttpReqeuest sends an incorrect Content-length 
       * header. See Mozilla Bugzilla #246651. 
       */ 
      if (this.transport.overrideMimeType) 
        requestHeaders.push('Connection', 'close'); 
    } 
 
    if (this.options.requestHeaders) 
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); 
 
    for (var i = 0; i < requestHeaders.length; i += 2) 
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); 
  }, 
 
  onStateChange: function() { 
    var readyState = this.transport.readyState; 
    if (readyState != 1) 
      this.respondToReadyState(this.transport.readyState); 
  }, 
 
  header: function(name) { 
    try { 
      return this.transport.getResponseHeader(name); 
    } catch (e) {} 
  }, 
 
  evalJSON: function() { 
    try { 
      return eval(this.header('X-JSON')); 
    } catch (e) {} 
  }, 
 
  evalResponse: function() { 
    try { 
      return eval(this.transport.responseText); 
    } catch (e) { 
      this.dispatchException(e); 
    } 
  }, 
 
  respondToReadyState: function(readyState) { 
    var event = Ajax.Request.Events[readyState]; 
    var transport = this.transport, json = this.evalJSON(); 
 
    if (event == 'Complete') { 
      try { 
        (this.options['on' + this.transport.status] 
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] 
         || Prototype.emptyFunction)(transport, json); 
      } catch (e) { 
        this.dispatchException(e); 
      } 
 
      if ((this.header('Content-type') || '').match(/^text\/javascript/i)) 
        this.evalResponse(); 
    } 
 
    try { 
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json); 
      Ajax.Responders.dispatch('on' + event, this, transport, json); 
    } catch (e) { 
      this.dispatchException(e); 
    } 
 
    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ 
    if (event == 'Complete') 
      this.transport.onreadystatechange = Prototype.emptyFunction; 
  }, 
 
  dispatchException: function(exception) { 
    (this.options.onException || Prototype.emptyFunction)(this, exception); 
    Ajax.Responders.dispatch('onException', this, exception); 
  } 
}); 
 
Ajax.Updater = Class.create(); 
 
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { 
  initialize: function(container, url, options) { 
    this.containers = { 
      success: container.success ? $(container.success) : $(container), 
      failure: container.failure ? $(container.failure) : 
        (container.success ? null : $(container)) 
    } 
 
    this.transport = Ajax.getTransport(); 
    this.setOptions(options); 
 
    var onComplete = this.options.onComplete || Prototype.emptyFunction; 
    this.options.onComplete = (function(transport, object) { 
      this.updateContent(); 
      onComplete(transport, object); 
    }).bind(this); 
 
    this.request(url); 
  }, 
 
  updateContent: function() { 
    var receiver = this.responseIsSuccess() ? 
      this.containers.success : this.containers.failure; 
    var response = this.transport.responseText; 
 
    if (!this.options.evalScripts) 
      response = response.stripScripts(); 
 
    if (receiver) { 
      if (this.options.insertion) { 
        new this.options.insertion(receiver, response); 
      } else { 
        Element.update(receiver, response); 
      } 
    } 
 
    if (this.responseIsSuccess()) { 
      if (this.onComplete) 
        setTimeout(this.onComplete.bind(this), 10); 
    } 
  } 
}); 
 
Ajax.PeriodicalUpdater = Class.create(); 
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { 
  initialize: function(container, url, options) { 
    this.setOptions(options); 
    this.onComplete = this.options.onComplete; 
 
    this.frequency = (this.options.frequency || 2); 
    this.decay = (this.options.decay || 1); 
 
    this.updater = {}; 
    this.container = container; 
    this.url = url; 
 
    this.start(); 
  }, 
 
  start: function() { 
    this.options.onComplete = this.updateComplete.bind(this); 
    this.onTimerEvent(); 
  }, 
 
  stop: function() { 
    this.updater.onComplete = undefined; 
    clearTimeout(this.timer); 
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments); 
  }, 
 
  updateComplete: function(request) { 
    if (this.options.decay) { 
      this.decay = (request.responseText == this.lastText ? 
        this.decay * this.options.decay : 1); 
 
      this.lastText = request.responseText; 
    } 
    this.timer = setTimeout(this.onTimerEvent.bind(this), 
      this.decay * this.frequency * 1000); 
  }, 
 
  onTimerEvent: function() { 
    this.updater = new Ajax.Updater(this.container, this.url, this.options); 
  } 
}); 
document.getElementsByClassName = function(className, parentElement) { 
  var children = ($(parentElement) || document.body).getElementsByTagName('*'); 
  return $A(children).inject([], function(elements, child) { 
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) 
      elements.push(child); 
    return elements; 
  }); 
} 
 
/*--------------------------------------------------------------------------*/ 
 
if (!window.Element) { 
  var Element = new Object(); 
} 
 
Object.extend(Element, { 
  visible: function(element) { 
    return $(element).style.display != 'none'; 
  }, 
 
  toggle: function() { 
    for (var i = 0; i < arguments.length; i++) { 
      var element = $(arguments[i]); 
      Element[Element.visible(element) ? 'hide' : 'show'](element); 
    } 
  }, 
 
  hide: function() { 
    for (var i = 0; i < arguments.length; i++) { 
      var element = $(arguments[i]); 
      element.style.display = 'none'; 
    } 
  }, 
 
  show: function() { 
    for (var i = 0; i < arguments.length; i++) { 
      var element = $(arguments[i]); 
      element.style.display = ''; 
    } 
  }, 
 
  remove: function(element) { 
    element = $(element); 
    element.parentNode.removeChild(element); 
  }, 
 
  update: function(element, html) { 
    $(element).innerHTML = html.stripScripts(); 
    setTimeout(function() {html.evalScripts()}, 10); 
  }, 
 
  getHeight: function(element) { 
    element = $(element); 
    return element.offsetHeight; 
  }, 
 
  classNames: function(element) { 
    return new Element.ClassNames(element); 
  }, 
 
  hasClassName: function(element, className) { 
    if (!(element = $(element))) return; 
    return Element.classNames(element).include(className); 
  }, 
 
  addClassName: function(element, className) { 
    if (!(element = $(element))) return; 
    return Element.classNames(element).add(className); 
  }, 
 
  removeClassName: function(element, className) { 
    if (!(element = $(element))) return; 
    return Element.classNames(element).remove(className); 
  }, 
 
  // removes whitespace-only text node children 
  cleanWhitespace: function(element) { 
    element = $(element); 
    for (var i = 0; i < element.childNodes.length; i++) { 
      var node = element.childNodes[i]; 
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) 
        Element.remove(node); 
    } 
  }, 
 
  empty: function(element) { 
    return $(element).innerHTML.match(/^\s*$/); 
  }, 
 
  scrollTo: function(element) { 
    element = $(element); 
    var x = element.x ? element.x : element.offsetLeft, 
        y = element.y ? element.y : element.offsetTop; 
    window.scrollTo(x, y); 
  }, 
 
  getStyle: function(element, style) { 
    element = $(element); 
    var value = element.style[style.camelize()]; 
    if (!value) { 
      if (document.defaultView && document.defaultView.getComputedStyle) { 
        var css = document.defaultView.getComputedStyle(element, null); 
        value = css ? css.getPropertyValue(style) : null; 
      } else if (element.currentStyle) { 
        value = element.currentStyle[style.camelize()]; 
      } 
    } 
 
    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) 
      if (Element.getStyle(element, 'position') == 'static') value = 'auto'; 
 
    return value == 'auto' ? null : value; 
  }, 
 
  setStyle: function(element, style) { 
    element = $(element); 
    for (name in style) 
      element.style[name.camelize()] = style[name]; 
  }, 
 
  getDimensions: function(element) { 
    element = $(element); 
    if (Element.getStyle(element, 'display') != 'none') 
      return {width: element.offsetWidth, height: element.offsetHeight}; 
 
    // All *Width and *Height properties give 0 on elements with display none, 
    // so enable the element temporarily 
    var els = element.style; 
    var originalVisibility = els.visibility; 
    var originalPosition = els.position; 
    els.visibility = 'hidden'; 
    els.position = 'absolute'; 
    els.display = ''; 
    var originalWidth = element.clientWidth; 
    var originalHeight = element.clientHeight; 
    els.display = 'none'; 
    els.position = originalPosition; 
    els.visibility = originalVisibility; 
    return {width: originalWidth, height: originalHeight}; 
  }, 
 
  makePositioned: function(element) { 
    element = $(element); 
    var pos = Element.getStyle(element, 'position'); 
    if (pos == 'static' || !pos) { 
      element._madePositioned = true; 
      element.style.position = 'relative'; 
      // Opera returns the offset relative to the positioning context, when an 
      // element is position relative but top and left have not been defined 
      if (window.opera) { 
        element.style.top = 0; 
        element.style.left = 0; 
      } 
    } 
  }, 
 
  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 = ''; 
    } 
  }, 
 
  makeClipping: function(element) { 
    element = $(element); 
    if (element._overflow) return; 
    element._overflow = element.style.overflow; 
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') 
      element.style.overflow = 'hidden'; 
  }, 
 
  undoClipping: function(element) { 
    element = $(element); 
    if (element._overflow) return; 
    element.style.overflow = element._overflow; 
    element._overflow = undefined; 
  } 
}); 
 
var Toggle = new Object(); 
Toggle.display = Element.toggle; 
 
/*--------------------------------------------------------------------------*/ 
 
Abstract.Insertion = function(adjacency) { 
  this.adjacency = adjacency; 
} 
 
Abstract.Insertion.prototype = { 
  initialize: function(element, content) { 
    this.element = $(element); 
    this.content = content.stripScripts(); 
 
    if (this.adjacency && this.element.insertAdjacentHTML) { 
      try { 
        this.element.insertAdjacentHTML(this.adjacency, this.content); 
      } catch (e) { 
        if (this.element.tagName.toLowerCase() == 'tbody') { 
          this.insertContent(this.contentFromAnonymousTable()); 
        } else { 
          throw e; 
        } 
      } 
    } else { 
      this.range = this.element.ownerDocument.createRange(); 
      if (this.initializeRange) this.initializeRange(); 
      this.insertContent([this.range.createContextualFragment(this.content)]); 
    } 
 
    setTimeout(function() {content.evalScripts()}, 10); 
  }, 
 
  contentFromAnonymousTable: function() { 
    var div = document.createElement('div'); 
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>'; 
    return $A(div.childNodes[0].childNodes[0].childNodes); 
  } 
} 
 
var Insertion = new Object(); 
 
Insertion.Before = Class.create(); 
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { 
  initializeRange: function() { 
    this.range.setStartBefore(this.element); 
  }, 
 
  insertContent: function(fragments) { 
    fragments.each((function(fragment) { 
      this.element.parentNode.insertBefore(fragment, this.element); 
    }).bind(this)); 
  } 
}); 
 
Insertion.Top = Class.create(); 
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { 
  initializeRange: function() { 
    this.range.selectNodeContents(this.element); 
    this.range.collapse(true); 
  }, 
 
  insertContent: function(fragments) { 
    fragments.reverse(false).each((function(fragment) { 
      this.element.insertBefore(fragment, this.element.firstChild); 
    }).bind(this)); 
  } 
}); 
 
Insertion.Bottom = Class.create(); 
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { 
  initializeRange: function() { 
    this.range.selectNodeContents(this.element); 
    this.range.collapse(this.element); 
  }, 
 
  insertContent: function(fragments) { 
    fragments.each((function(fragment) { 
      this.element.appendChild(fragment); 
    }).bind(this)); 
  } 
}); 
 
Insertion.After = Class.create(); 
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { 
  initializeRange: function() { 
    this.range.setStartAfter(this.element); 
  }, 
 
  insertContent: function(fragments) { 
    fragments.each((function(fragment) { 
      this.element.parentNode.insertBefore(fragment, 
        this.element.nextSibling); 
    }).bind(this)); 
  } 
}); 
 
/*--------------------------------------------------------------------------*/ 
 
Element.ClassNames = Class.create(); 
Element.ClassNames.prototype = { 
  initialize: function(element) { 
    this.element = $(element); 
  }, 
 
  _each: function(iterator) { 
    this.element.className.split(/\s+/).select(function(name) { 
      return name.length > 0; 
    })._each(iterator); 
  }, 
 
  set: function(className) { 
    this.element.className = className; 
  }, 
 
  add: function(classNameToAdd) { 
    if (this.include(classNameToAdd)) return; 
    this.set(this.toArray().concat(classNameToAdd).join(' ')); 
  }, 
 
  remove: function(classNameToRemove) { 
    if (!this.include(classNameToRemove)) return; 
    this.set(this.select(function(className) { 
      return className != classNameToRemove; 
    }).join(' ')); 
  }, 
 
  toString: function() { 
    return this.toArray().join(' '); 
  } 
} 
 
Object.extend(Element.ClassNames.prototype, Enumerable); 
var Field = { 
  clear: function() { 
    for (var i = 0; i < arguments.length; i++) 
      $(arguments[i]).value = ''; 
  }, 
 
  focus: function(element) { 
    $(element).focus(); 
  }, 
 
  present: function() { 
    for (var i = 0; i < arguments.length; i++) 
      if ($(arguments[i]).value == '') return false; 
    return true; 
  }, 
 
  select: function(element) { 
    $(element).select(); 
  }, 
 
  activate: function(element) { 
    element = $(element); 
    element.focus(); 
    if (element.select) 
      element.select(); 
  } 
} 
 
/*--------------------------------------------------------------------------*/ 
 
var Form = { 
  serialize: function(form) { 
    var elements = Form.getElements($(form)); 
    var queryComponents = new Array(); 
 
    for (var i = 0; i < elements.length; i++) { 
      var queryComponent = Form.Element.serialize(elements[i]); 
      if (queryComponent) 
        queryComponents.push(queryComponent); 
    } 
 
    return queryComponents.join('&'); 
  }, 
 
  getElements: function(form) { 
    form = $(form); 
    var elements = new Array(); 
 
    for (tagName in Form.Element.Serializers) { 
      var tagElements = form.getElementsByTagName(tagName); 
      for (var j = 0; j < tagElements.length; j++) 
        elements.push(tagElements[j]); 
    } 
    return elements; 
  }, 
 
  getInputs: function(form, typeName, name) { 
    form = $(form); 
    var inputs = form.getElementsByTagName('input'); 
 
    if (!typeName && !name) 
      return inputs; 
 
    var matchingInputs = new Array(); 
    for (var i = 0; i < inputs.length; i++) { 
      var input = inputs[i]; 
      if ((typeName && input.type != typeName) || 
          (name && input.name != name)) 
        continue; 
      matchingInputs.push(input); 
    } 
 
    return matchingInputs; 
  }, 
 
  disable: function(form) { 
    var elements = Form.getElements(form); 
    for (var i = 0; i < elements.length; i++) { 
      var element = elements[i]; 
      element.blur(); 
      element.disabled = 'true'; 
    } 
  }, 
 
  enable: function(form) { 
    var elements = Form.getElements(form); 
    for (var i = 0; i < elements.length; i++) { 
      var element = elements[i]; 
      element.disabled = ''; 
    } 
  }, 
 
  findFirstElement: function(form) { 
    return Form.getElements(form).find(function(element) { 
      return element.type != 'hidden' && !element.disabled && 
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); 
    }); 
  }, 
 
  focusFirstElement: function(form) { 
    Field.activate(Form.findFirstElement(form)); 
  }, 
 
  reset: function(form) { 
    $(form).reset(); 
  } 
} 
 
Form.Element = { 
  serialize: function(element) { 
    element = $(element); 
    var method = element.tagName.toLowerCase(); 
    var parameter = Form.Element.Serializers[method](element); 
 
    if (parameter) { 
      var key = encodeURIComponent(parameter[0]); 
      if (key.length == 0) return; 
 
      if (parameter[1].constructor != Array) 
        parameter[1] = [parameter[1]]; 
 
      return parameter[1].map(function(value) { 
        return key + '=' + encodeURIComponent(value); 
      }).join('&'); 
    } 
  }, 
 
  getValue: function(element) { 
    element = $(element); 
    var method = element.tagName.toLowerCase(); 
    var parameter = Form.Element.Serializers[method](element); 
 
    if (parameter) 
      return parameter[1]; 
  } 
} 
 
Form.Element.Serializers = { 
  input: function(element) { 
    switch (element.type.toLowerCase()) { 
      case 'submit': 
      case 'hidden': 
      case 'password': 
      case 'text': 
        return Form.Element.Serializers.textarea(element); 
      case 'checkbox': 
      case 'radio': 
        return Form.Element.Serializers.inputSelector(element); 
    } 
    return false; 
  }, 
 
  inputSelector: function(element) { 
    if (element.checked) 
      return [element.name, element.value]; 
  }, 
 
  textarea: function(element) { 
    return [element.name, element.value]; 
  }, 
 
  select: function(element) { 
    return Form.Element.Serializers[element.type == 'select-one' ? 
      'selectOne' : 'selectMany'](element); 
  }, 
 
  selectOne: function(element) { 
    var value = '', opt, index = element.selectedIndex; 
    if (index >= 0) { 
      opt = element.options[index]; 
      value = opt.value; 
      if (!value && !('value' in opt)) 
        value = opt.text; 
    } 
    return [element.name, value]; 
  }, 
 
  selectMany: function(element) { 
    var value = new Array(); 
    for (var i = 0; i < element.length; i++) { 
      var opt = element.options[i]; 
      if (opt.selected) { 
        var optValue = opt.value; 
        if (!optValue && !('value' in opt)) 
          optValue = opt.text; 
        value.push(optValue); 
      } 
    } 
    return [element.name, value]; 
  } 
} 
 
/*--------------------------------------------------------------------------*/ 
 
var $F = Form.Element.getValue; 
 
/*--------------------------------------------------------------------------*/ 
 
Abstract.TimedObserver = function() {} 
Abstract.TimedObserver.prototype = { 
  initialize: function(element, frequency, callback) { 
    this.frequency = frequency; 
    this.element   = $(element); 
    this.callback  = callback; 
 
    this.lastValue = this.getValue(); 
    this.registerCallback(); 
  }, 
 
  registerCallback: function() { 
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); 
  }, 
 
  onTimerEvent: function() { 
    var value = this.getValue(); 
    if (this.lastValue != value) { 
      this.callback(this.element, value); 
      this.lastValue = value; 
    } 
  } 
} 
 
Form.Element.Observer = Class.create(); 
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 
  getValue: function() { 
    return Form.Element.getValue(this.element); 
  } 
}); 
 
Form.Observer = Class.create(); 
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { 
  getValue: function() { 
    return Form.serialize(this.element); 
  } 
}); 
 
/*--------------------------------------------------------------------------*/ 
 
Abstract.EventObserver = function() {} 
Abstract.EventObserver.prototype = { 
  initialize: function(element, callback) { 
    this.element  = $(element); 
    this.callback = callback; 
 
    this.lastValue = this.getValue(); 
    if (this.element.tagName.toLowerCase() == 'form') 
      this.registerFormCallbacks(); 
    else 
      this.registerCallback(this.element); 
  }, 
 
  onElementEvent: function() { 
    var value = this.getValue(); 
    if (this.lastValue != value) { 
      this.callback(this.element, value); 
      this.lastValue = value; 
    } 
  }, 
 
  registerFormCallbacks: function() { 
    var elements = Form.getElements(this.element); 
    for (var i = 0; i < elements.length; i++) 
      this.registerCallback(elements[i]); 
  }, 
 
  registerCallback: function(element) { 
    if (element.type) { 
      switch (element.type.toLowerCase()) { 
        case 'checkbox': 
        case 'radio': 
          Event.observe(element, 'click', this.onElementEvent.bind(this)); 
          break; 
        case 'password': 
        case 'text': 
        case 'textarea': 
        case 'select-one': 
        case 'select-multiple': 
          Event.observe(element, 'change', this.onElementEvent.bind(this)); 
          break; 
      } 
    } 
  } 
} 
 
Form.Element.EventObserver = Class.create(); 
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 
  getValue: function() { 
    return Form.Element.getValue(this.element); 
  } 
}); 
 
Form.EventObserver = Class.create(); 
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { 
  getValue: function() { 
    return Form.serialize(this.element); 
  } 
}); 
if (!window.Event) { 
  var Event = new Object(); 
} 
 
Object.extend(Event, { 
  KEY_BACKSPACE: 8, 
  KEY_TAB:       9, 
  KEY_RETURN:   13, 
  KEY_ESC:      27, 
  KEY_LEFT:     37, 
  KEY_UP:       38, 
  KEY_RIGHT:    39, 
  KEY_DOWN:     40, 
  KEY_DELETE:   46, 
 
  element: function(event) { 
    return event.target || event.srcElement; 
  }, 
 
  isLeftClick: function(event) { 
    return (((event.which) && (event.which == 1)) || 
            ((event.button) && (event.button == 1))); 
  }, 
 
  pointerX: function(event) { 
    return event.pageX || (event.clientX + 
      (document.documentElement.scrollLeft || document.body.scrollLeft)); 
  }, 
 
  pointerY: function(event) { 
    return event.pageY || (event.clientY + 
      (document.documentElement.scrollTop || document.body.scrollTop)); 
  }, 
 
  stop: function(event) { 
    if (event.preventDefault) { 
      event.preventDefault(); 
      event.stopPropagation(); 
    } else { 
      event.returnValue = false; 
      event.cancelBubble = true; 
    } 
  }, 
 
  // find the first node with the given tagName, starting from the 
  // node the event was triggered on; traverses the DOM upwards 
  findElement: function(event, tagName) { 
    var element = Event.element(event); 
    while (element.parentNode && (!element.tagName || 
        (element.tagName.toUpperCase() != tagName.toUpperCase()))) 
      element = element.parentNode; 
    return element; 
  }, 
 
  observers: false, 
 
  _observeAndCache: function(element, name, observer, useCapture) { 
    if (!this.observers) this.observers = []; 
    if (element.addEventListener) { 
      this.observers.push([element, name, observer, useCapture]); 
      element.addEventListener(name, observer, useCapture); 
    } else if (element.attachEvent) { 
      this.observers.push([element, name, observer, useCapture]); 
      element.attachEvent('on' + name, observer); 
    } 
  }, 
 
  unloadCache: function() { 
    if (!Event.observers) return; 
    for (var i = 0; i < Event.observers.length; i++) { 
      Event.stopObserving.apply(this, Event.observers[i]); 
      Event.observers[i][0] = null; 
    } 
    Event.observers = false; 
  }, 
 
  observe: function(element, name, observer, useCapture) { 
    var element = $(element); 
    useCapture = useCapture || false; 
 
    if (name == 'keypress' && 
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/) 
        || element.attachEvent)) 
      name = 'keydown'; 
 
    this._observeAndCache(element, name, observer, useCapture); 
  }, 
 
  stopObserving: function(element, name, observer, useCapture) { 
    var element = $(element); 
    useCapture = useCapture || false; 
 
    if (name == 'keypress' && 
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/) 
        || element.detachEvent)) 
      name = 'keydown'; 
 
    if (element.removeEventListener) { 
      element.removeEventListener(name, observer, useCapture); 
    } else if (element.detachEvent) { 
      element.detachEvent('on' + name, observer); 
    } 
  } 
}); 
 
/* prevent memory leaks in IE */ 
Event.observe(window, 'unload', Event.unloadCache, false); 
var Position = { 
  // set to true if needed, warning: firefox performance problems 
  // NOT neeeded for page scrolling, only if draggable contained in 
  // scrollable elements 
  includeScrollOffsets: false, 
 
  // must be called before calling withinIncludingScrolloffset, every time the 
  // page is scrolled 
  prepare: function() { 
    this.deltaX =  window.pageXOffset 
                || document.documentElement.scrollLeft 
                || document.body.scrollLeft 
                || 0; 
    this.deltaY =  window.pageYOffset 
                || document.documentElement.scrollTop 
                || document.body.scrollTop 
                || 0; 
  }, 
 
  realOffset: function(element) { 
    var valueT = 0, valueL = 0; 
    do { 
      valueT += element.scrollTop  || 0; 
      valueL += element.scrollLeft || 0; 
      element = element.parentNode; 
    } while (element); 
    return [valueL, valueT]; 
  }, 
 
  cumulativeOffset: function(element) { 
    var valueT = 0, valueL = 0; 
    do { 
      valueT += element.offsetTop  || 0; 
      valueL += element.offsetLeft || 0; 
      element = element.offsetParent; 
    } while (element); 
    return [valueL, valueT]; 
  }, 
 
  positionedOffset: function(element) { 
    var valueT = 0, valueL = 0; 
    do { 
      valueT += element.offsetTop  || 0; 
      valueL += element.offsetLeft || 0; 
      element = element.offsetParent; 
      if (element) { 
        p = Element.getStyle(element, 'position'); 
        if (p == 'relative' || p == 'absolute') break; 
      } 
    } while (element); 
    return [valueL, valueT]; 
  }, 
 
  offsetParent: function(element) { 
    if (element.offsetParent) return element.offsetParent; 
    if (element == document.body) return element; 
 
    while ((element = element.parentNode) && element != document.body) 
      if (Element.getStyle(element, 'position') != 'static') 
        return element; 
 
    return document.body; 
  }, 
 
  // caches x/y coordinate pair to use with overlap 
  within: function(element, x, y) { 
    if (this.includeScrollOffsets) 
      return this.withinIncludingScrolloffsets(element, x, y); 
    this.xcomp = x; 
    this.ycomp = y; 
    this.offset = this.cumulativeOffset(element); 
 
    return (y >= this.offset[1] && 
            y <  this.offset[1] + element.offsetHeight && 
            x >= this.offset[0] && 
            x <  this.offset[0] + element.offsetWidth); 
  }, 
 
  withinIncludingScrolloffsets: function(element, x, y) { 
    var offsetcache = this.realOffset(element); 
 
    this.xcomp = x + offsetcache[0] - this.deltaX; 
    this.ycomp = y + offsetcache[1] - this.deltaY; 
    this.offset = this.cumulativeOffset(element); 
 
    return (this.ycomp >= this.offset[1] && 
            this.ycomp <  this.offset[1] + element.offsetHeight && 
            this.xcomp >= this.offset[0] && 
            this.xcomp <  this.offset[0] + element.offsetWidth); 
  }, 
 
  // within must be called directly before 
  overlap: function(mode, element) { 
    if (!mode) return 0; 
    if (mode == 'vertical') 
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) / 
        element.offsetHeight; 
    if (mode == 'horizontal') 
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) / 
        element.offsetWidth; 
  }, 
 
  clone: function(source, target) { 
    source = $(source); 
    target = $(target); 
    target.style.position = 'absolute'; 
    var offsets = this.cumulativeOffset(source); 
    target.style.top    = offsets[1] + 'px'; 
    target.style.left   = offsets[0] + 'px'; 
    target.style.width  = source.offsetWidth + 'px'; 
    target.style.height = source.offsetHeight + 'px'; 
  }, 
 
  page: function(forElement) { 
    var valueT = 0, valueL = 0; 
 
    var element = forElement; 
    do { 
      valueT += element.offsetTop  || 0; 
      valueL += element.offsetLeft || 0; 
 
      // Safari fix 
      if (element.offsetParent==document.body) 
        if (Element.getStyle(element,'position')=='absolute') break; 
 
    } while (element = element.offsetParent); 
 
    element = forElement; 
    do { 
      valueT -= element.scrollTop  || 0; 
      valueL -= element.scrollLeft || 0; 
    } while (element = element.parentNode); 
 
    return [valueL, valueT]; 
  }, 
 
  clone: function(source, target) { 
    var options = Object.extend({ 
      setLeft:    true, 
      setTop:     true, 
      setWidth:   true, 
      setHeight:  true, 
      offsetTop:  0, 
      offsetLeft: 0 
    }, arguments[2] || {}) 
 
    // find page position of source 
    source = $(source); 
    var p = Position.page(source); 
 
    // find coordinate system to use 
    target = $(target); 
    var delta = [0, 0]; 
    var parent = null; 
    // delta [0,0] will do fine with position: fixed elements, 
    // position:absolute needs offsetParent deltas 
    if (Element.getStyle(target,'position') == 'absolute') { 
      parent = Position.offsetParent(target); 
      delta = Position.page(parent); 
    } 
 
    // correct by body offsets (fixes Safari) 
    if (parent == document.body) { 
      delta[0] -= document.body.offsetLeft; 
      delta[1] -= document.body.offsetTop; 
    } 
 
    // set position 
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px'; 
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px'; 
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px'; 
    if(options.setHeight) target.style.height = source.offsetHeight + 'px'; 
  }, 
 
  absolutize: function(element) { 
    element = $(element); 
    if (element.style.position == 'absolute') return; 
    Position.prepare(); 
 
    var offsets = Position.positionedOffset(element); 
    var top     = offsets[1]; 
    var left    = offsets[0]; 
    var width   = element.clientWidth; 
    var height  = element.clientHeight; 
 
    element._originalLeft   = left - parseFloat(element.style.left  || 0); 
    element._originalTop    = top  - parseFloat(element.style.top || 0); 
    element._originalWidth  = element.style.width; 
    element._originalHeight = element.style.height; 
 
    element.style.position = 'absolute'; 
    element.style.top    = top + 'px';; 
    element.style.left   = left + 'px';; 
    element.style.width  = width + 'px';; 
    element.style.height = height + 'px';; 
  }, 
 
  relativize: function(element) { 
    element = $(element); 
    if (element.style.position == 'relative') return; 
    Position.prepare(); 
 
    element.style.position = 'relative'; 
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0); 
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); 
 
    element.style.top    = top + 'px'; 
    element.style.left   = left + 'px'; 
    element.style.height = element._originalHeight; 
    element.style.width  = element._originalWidth; 
  } 
} 
 
// Safari returns margins on body which is incorrect if the child is absolutely 
// positioned.  For performance reasons, redefine Position.cumulativeOffset for 
// KHTML/WebKit only. 
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { 
  Position.cumulativeOffset = function(element) { 
    var valueT = 0, valueL = 0; 
    do { 
      valueT += element.offsetTop  || 0; 
      valueL += element.offsetLeft || 0; 
      if (element.offsetParent == document.body) 
        if (Element.getStyle(element, 'position') == 'absolute') break; 
 
      element = element.offsetParent; 
    } while (element); 
 
    return [valueL, valueT]; 
  } 
}
