/*  lwPrototype JavaScript framework, version 1.5.0_rc1
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  lwPrototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the lwPrototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var lwPrototype = {
  Version: '1.5.0_rc1',
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',

  emptyFunction: function() {},
  K: function(x) {return x}
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object == undefined) return 'undefined';
      if (object == null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },

  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },

  clone: function(object) {
    return Object.extend({}, object);
  }
});

Function.prototype.bind = function() {
  var __method = this, args = $LWA(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($LWA(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this, args = $LWA(arguments), object = args.shift();
  return function(event) {
    return __method.apply(object, [( event || window.event)].concat(args).concat($LWA(arguments)));
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    var digits = this.toString(16);
    if (this < 16) return '0' + digits;
    return digits;
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $LWR(0, this, true).each(iterator);
    return this;
  }
});

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback(this);
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}
Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += (replacement(match) || '').toString();
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return this;
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : this;
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(lwPrototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(lwPrototype.ScriptFragment, 'img');
    var matchOne = new RegExp(lwPrototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  },

  toQueryParams: function() {
    var pairs = this.match(/^\??(.*)$/)[1].split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair  = pairString.split('=');
      var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
      params[decodeURIComponent(pair[0])] = value;
      return params;
    });
  },

  toArray: function() {
    return this.split('');
  },

  camelize: function() {
    var oStringList = this.split('-');
    if (oStringList.length == 1) return oStringList[0];

    var camelizedString = this.indexOf('-') == 0
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
      : oStringList[0];

    for (var i = 1, len = oStringList.length; i < len; i++) {
      var s = oStringList[i];
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }

    return camelizedString;
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.replace(/\\/g, '\\\\');
    if (useDoubleQuotes)
      return '"' + escapedString.replace(/"/g, '\\"') + '"';
    else
      return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (typeof replacement == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
}

String.prototype.parseQuery = String.prototype.toQueryParams;

var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    return this.template.gsub(this.pattern, function(match) {
      var before = match[1];
      if (before == '\\') return match[2];
      return before + (object[match[3]] || '').toString();
    });
  }
}

var $break    = new Object();
var $continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        try {
          iterator(value, index++);
        } catch (e) {
          if (e != $continue) throw e;
        }
      });
    } catch (e) {
      if (e != $break) throw e;
    }
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || lwPrototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = false;
    this.each(function(value, index) {
      if (result = !!(iterator || lwPrototype.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 || lwPrototype.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 = $LWA(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 || lwPrototype.K)(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || lwPrototype.K)(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || lwPrototype.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(lwPrototype.K);
  },

  zip: function() {
    var iterator = lwPrototype.K, args = $LWA(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $LWA = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0; i < iterable.length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0; i < this.length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != undefined || value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value && value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $LWA(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0; i < this.length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function() {
    return this.inject([], function(array, value) {
      return array.include(value) ? array : array.concat([value]);
    });
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});
var Hash = {
  _each: function(iterator) {
    for (var key in this) {
      var value = this[key];
      if (typeof value == 'function') continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $LWH(hash).inject($LWH(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 $LWH(object) {
  var hash = Object.extend({}, object || {});
  Object.extend(hash, Enumerable);
  Object.extend(hash, Hash);
  return hash;
}
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $LWR = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responderToAdd) {
    if (!this.include(responderToAdd))
      this.responders.push(responderToAdd);
  },

  unregister: function(responderToRemove) {
    this.responders = this.responders.without(responderToRemove);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (responder[callback] && typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },

  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      parameters:   ''
    }
    Object.extend(this.options, options || {});
  },

  responseIsSuccess: function() {
    return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  responseIsFailure: function() {
    return !this.responseIsSuccess();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    var parameters = this.options.parameters || '';
    if (parameters.length > 0) parameters += '&_=';

    /* Simulate other verbs over post */
    if (this.options.method != 'get' && this.options.method != 'post') {
      parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
      this.options.method = 'post';
    }

    try {
      this.url = url;
      if (this.options.method == 'get' && parameters.length > 0)
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method, this.url,
        this.options.asynchronous);

      if (this.options.asynchronous)
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      var body = this.options.postBody ? this.options.postBody : parameters;
      this.transport.send(this.options.method == 'post' ? body : null);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    } catch (e) {
      this.dispatchException(e);
    }
  },

  setRequestHeaders: function() {
    var requestHeaders =
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', lwPrototype.Version,
       'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type', this.options.contentType);

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  header: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) {}
  },

  evalJSON: function() {
    try {
      return eval('(' + this.header('X-JSON') + ')');
    } catch (e) {}
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (event == 'Complete') {
      try {
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || lwPrototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || lwPrototype.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 = lwPrototype.emptyFunction;
  },

  dispatchException: function(exception) {
    (this.options.onException || lwPrototype.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 ? $LW(container.success) : $LW(container),
      failure: container.failure ? $LW(container.failure) :
        (container.success ? null : $LW(container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || lwPrototype.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 {
        lwElement.update(receiver, response);
      }
    }

    if (this.responseIsSuccess()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || lwPrototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $LW() {
  var results = [], element;
  for (var i = 0; i < arguments.length; i++) {
    element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);
    results.push(lwElement.extend(element));
  }
  return results.reduce();
}

document.getElementsByClassName = function(className, parentElement) {
  var children = ($LW(parentElement) || document.body).getElementsByTagName('*');
  return $LWA(children).inject([], function(elements, child) {
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      elements.push(lwElement.extend(child));
    return elements;
  });
}

/*--------------------------------------------------------------------------*/

if (!window.lwElement)
	var	lwElement = new Object();

lwElement.extend = function(element) {
  if (!element) return;
  if (_nativeExtensions || element.nodeType == 3) return element;

  if (!element._extended && element.tagName && element != window) {
    var methods = Object.clone(lwElement.Methods), cache = lwElement.extend.cache;

    if (element.tagName == 'FORM')
      Object.extend(methods, Form.Methods);
    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
      Object.extend(methods, Form.Element.Methods);

    for (var property in methods) {
      var value = methods[property];
      if (typeof value == 'function')
        element[property] = cache.findOrStore(value);
    }
  }

  element._extended = true;
  return element;
}

lwElement.extend.cache = {
  findOrStore: function(value) {
    return this[value] = this[value] || function() {
      return value.apply(null, [this].concat($LWA(arguments)));
    }
  }
}

lwElement.Methods = {
  visible: function(element) {
    return $LW(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $LW(element);
    lwElement[lwElement.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $LW(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $LW(element).style.display = '';
    return element;
  },

  remove: function(element) {
    element = $LW(element);
    element.parentNode.removeChild(element);
    return element;
  },

  update: function(element, html) {
    $LW(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  replace: function(element, html) {
    element = $LW(element);
    if (element.outerHTML) {
      element.outerHTML = html.stripScripts();
    } else {
      var range = element.ownerDocument.createRange();
      range.selectNodeContents(element);
      element.parentNode.replaceChild(
        range.createContextualFragment(html.stripScripts()), element);
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  inspect: function(element) {
    element = $LW(element);
    var result = '<' + element.tagName.toLowerCase();
    $LWH({'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 = $LW(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(lwElement.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $LW(element).recursivelyCollect('parentNode');
  },

  descendants: function(element) {
    element = $LW(element);
    return $LWA(element.getElementsByTagName('*'));
  },

  previousSiblings: function(element) {
    return $LW(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $LW(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $LW(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    element = $LW(element);
    if (typeof selector == 'string')
      selector = new Selector(selector);
    return selector.match(element);
  },

  up: function(element, expression, index) {
    return Selector.findElement($LW(element).ancestors(), expression, index);
  },

  down: function(element, expression, index) {
    return Selector.findElement($LW(element).descendants(), expression, index);
  },

  previous: function(element, expression, index) {
    return Selector.findElement($LW(element).previousSiblings(), expression, index);
  },

  next: function(element, expression, index) {
    return Selector.findElement($LW(element).nextSiblings(), expression, index);
  },

  getElementsBySelector: function() {
    var args = $LWA(arguments), element = $LW(args.shift());
    return Selector.findChildElements(element, args);
  },

  getElementsByClassName: function(element, className) {
    element = $LW(element);
    return document.getElementsByClassName(className, element);
  },

  getHeight: function(element) {
    element = $LW(element);
    return element.offsetHeight;
  },

  classNames: function(element) {
    return new lwElement.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $LW(element))) return;
    return lwElement.classNames(element).include(className);
  },

  addClassName: function(element, className) {
    if (!(element = $LW(element))) return;
    lwElement.classNames(element).add(className);
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $LW(element))) return;
    lwElement.classNames(element).remove(className);
    return element;
  },

  observe: function() {
    Event.observe.apply(Event, arguments);
    return $LWA(arguments).first();
  },

  stopObserving: function() {
    Event.stopObserving.apply(Event, arguments);
    return $LWA(arguments).first();
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $LW(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 $LW(element).innerHTML.match(/^\s*$/);
  },

  childOf: function(element, ancestor) {
    element = $LW(element), ancestor = $LW(ancestor);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $LW(element);
    var x = element.x ? element.x : element.offsetLeft,
        y = element.y ? element.y : element.offsetTop;
    window.scrollTo(x, y);
    return element;
  },

  getStyle: function(element, style) {
    element = $LW(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 (lwElement.getStyle(element, 'position') == 'static') value = 'auto';

    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style) {
    element = $LW(element);
    for (var name in style)
      element.style[name.camelize()] = style[name];
    return element;
  },

  getDimensions: function(element) {
    element = $LW(element);
    if (lwElement.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 = $LW(element);
    var pos = lwElement.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 = $LW(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 = $LW(element);
    if (element._overflow) return;
    element._overflow = element.style.overflow || 'auto';
    if ((lwElement.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $LW(element);
    if (!element._overflow) return;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  }
}

// IE is missing .innerHTML support for TABLE-related elements
if(document.all){
  lwElement.Methods.update = function(element, html) {
    element = $LW(element);
    var tagName = element.tagName.toUpperCase();
    if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
      var div = document.createElement('div');
      switch (tagName) {
        case 'THEAD':
        case 'TBODY':
          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
          depth = 2;
          break;
        case 'TR':
          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
          depth = 3;
          break;
        case 'TD':
          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
          depth = 4;
      }
      $LWA(element.childNodes).each(function(node){
        element.removeChild(node)
      });
      depth.times(function(){ div = div.firstChild });

      $LWA(div.childNodes).each(
        function(node){ element.appendChild(node) });
    } else {
      element.innerHTML = html.stripScripts();
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  }
}

Object.extend(lwElement, lwElement.Methods);

var _nativeExtensions = false;

if (!window.HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  /* Emulate HTMLElement, HTMLFormElement, HTMLInputElement, HTMLTextAreaElement,
     and HTMLSelectlwElement in Safari */
  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
    var klass = window['HTML' + tag + 'Element'] = {};
    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
  });
}

lwElement.addMethods = function(methods) {
  Object.extend(lwElement.Methods, methods || {});

  function copy(methods, destination) {
    var cache = lwElement.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      destination[property] = cache.findOrStore(value);
    }
  }

  if (typeof HTMLElement != 'undefined') {
    copy(lwElement.Methods, HTMLElement.prototype);
    copy(Form.Methods, HTMLFormElement.prototype);
    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
      copy(Form.Element.Methods, klass.prototype);
    });
    _nativeExtensions = true;
  }
}

var Toggle = new Object();
Toggle.display = lwElement.toggle;

/*--------------------------------------------------------------------------*/

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $LW(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        var tagName = this.element.tagName.toLowerCase();
        if (tagName == 'tbody' || tagName == 'tr') {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $LWA(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));
  }
});

/*--------------------------------------------------------------------------*/

lwElement.ClassNames = Class.create();
lwElement.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $LW(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(lwElement.ClassNames.prototype, Enumerable);
var Selector = Class.create();
Selector.prototype = {
  initialize: function(expression) {
    this.params = {classNames: []};
    this.expression = expression.toString().strip();
    this.parseExpression();
    this.compileMatcher();
  },

  parseExpression: function() {
    function abort(message) { throw 'Parse error in selector: ' + message; }

    if (this.expression == '')  abort('empty expression');

    var params = this.params, expr = this.expression, match, modifier, clause, rest;
    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
      params.attributes = params.attributes || [];
      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
      expr = match[1];
    }

    if (expr == '*') return this.params.wildcard = true;

    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
      modifier = match[1], clause = match[2], rest = match[3];
      switch (modifier) {
        case '#':       params.id = clause; break;
        case '.':       params.classNames.push(clause); break;
        case '':
        case undefined: params.tagName = clause.toUpperCase(); break;
        default:        abort(expr.inspect());
      }
      expr = rest;
    }

    if (expr.length > 0) abort(expr.inspect());
  },

  buildMatchExpression: function() {
    var params = this.params, conditions = [], clause;

    if (params.wildcard)
      conditions.push('true');
    if (clause = params.id)
      conditions.push('element.id == ' + clause.inspect());
    if (clause = params.tagName)
      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
    if ((clause = params.classNames).length > 0)
      for (var i = 0; i < clause.length; i++)
        conditions.push('lwElement.hasClassName(element, ' + clause[i].inspect() + ')');
    if (clause = params.attributes) {
      clause.each(function(attribute) {
        var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
        var splitValueBy = function(delimiter) {
          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
        }

        switch (attribute.operator) {
          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
          case '|=':      conditions.push(
                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
                          ); break;
          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
          case '':
          case undefined: conditions.push(value + ' != null'); break;
          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
        }
      });
    }

    return conditions.join(' && ');
  },

  compileMatcher: function() {
    this.match = new Function('element', 'if (!element.tagName) return false; \
      return ' + this.buildMatchExpression());
  },

 findElements: function(scope) {
    var element;

    if (element = $LW(this.params.id))
      if (this.match(element))
        if (!scope || lwElement.childOf(element, scope))
          return [element];

    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');

    var results = [];
    for (var i = 0; i < scope.length; i++)
      if (this.match(element = scope[i]))
        results.push(lwElement.extend(element));

    return results;
  },

  toString: function() {
    return this.expression;
  }
}

Object.extend(Selector, {
  matchElements: function(elements, expression) {
    var selector = new Selector(expression);
    return elements.select(selector.match.bind(selector));
  },

  findElement: function(elements, expression, index) {
    if (typeof expression == 'number') index = expression, expression = false;
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

 findChildElements: function(element, expressions) {
    return expressions.map(function(expression) {
      return expression.strip().split(/\s+/).inject([null], function(results, expr) {
        var selector = new Selector(expr);
        return results.inject([], function(elements, result) {
          return elements.concat(selector.findElements(result || element));
        });
      });
    }).flatten();
  }
});

function $$LW() {
  return Selector.findChildElements(document, $LWA(arguments));
}
var Form = {
  reset: function(form) {
    $LW(form).reset();
    return form;
  }
};

Form.Methods = {
  serialize: function(form) {
    var elements = Form.getElements($LW(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 = $LW(form);
    var elements = new Array();

    for (var tagName in Form.Element.Serializers) {
      var tagElements = form.getElementsByTagName(tagName);
      for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
    }
    return elements;
  },

  getInputs: function(form, typeName, name) {
    form = $LW(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name)
      return inputs;

    var matchingInputs = new Array();
    for (var i = 0; i < inputs.length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) ||
          (name && input.name != name))
        continue;
      matchingInputs.push(input);
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $LW(form);
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.blur();
      element.disabled = 'true';
    }
    return form;
  },

  enable: function(form) {
    form = $LW(form);
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.disabled = '';
    }
    return form;
  },

  findFirstElement: function(form) {
    return Form.getElements(form).find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $LW(form);
    Field.activate(Form.findFirstElement(form));
    return form;
  }
}

Object.extend(Form, Form.Methods);

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $LW(element).focus();
    return element;
  },

  select: function(element) {
    $LW(element).select();
    return element;
  }
}

Form.Element.Methods = {
  serialize: function(element) {
    element = $LW(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 = $LW(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter)
      return parameter[1];
  },

  clear: function(element) {
    $LW(element).value = '';
    return element;
  },

  present: function(element) {
    return $LW(element).value != '';
  },

  activate: function(element) {
    element = $LW(element);
    element.focus();
    if (element.select)
      element.select();
    return element;
  },

  disable: function(element) {
    element = $LW(element);
    element.disabled = '';
    return element;
  },

  enable: function(element) {
    element = $LW(element);
    element.blur();
    element.disabled = 'true';
    return element;
  }
}

Object.extend(Form.Element, Form.Element.Methods);
var Field = Form.Element;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
      default:
        return Form.Element.Serializers.textarea(element);
    }
    return false;
  },

  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },

  textarea: function(element) {
    return [element.name, element.value];
  },

  select: function(element) {
    return Form.Element.Serializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = element.options[index];
      value = opt.value || opt.text;
    }
    return [element.name, value];
  },

  selectMany: function(element) {
    var value = [];
    for (var i = 0; i < element.length; i++) {
      var opt = element.options[i];
      if (opt.selected)
        value.push(opt.value || opt.text);
    }
    return [element.name, value];
  }
}

/*--------------------------------------------------------------------------*/

var $F = Form.Element.getValue;

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $LW(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  = $LW(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    var elements = Form.getElements(this.element);
    for (var i = 0; i < elements.length; i++)
      this.registerCallback(elements[i]);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {

  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,

  element: function(event) {
    return event.target || event.srcElement;
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0; i < Event.observers.length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    element = $LW(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.attachEvent))
      name = 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    element = $LW(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.detachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      try {
        element.detachEvent('on' + name, observer);
      } catch (e) {}
    }
  }
});

/* prevent memory leaks in IE */
if (navigator.appVersion.match(/\bMSIE\b/))
  Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        p = lwElement.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 (lwElement.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent==document.body)
        if (lwElement.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!window.opera || element.tagName=='BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $LW(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $LW(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (lwElement.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 = $LW(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 = $LW(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 (lwElement.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}

lwElement.addMethods();

// script.aculo.us effects.js v1.6.5, Wed Nov 08 14:17:49 CET 2006

// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/ 

// converts rgb() and #xxx to #xxxxxx format,  
// returns self (or first argument) if not convertable  
String.prototype.parseColor = function() {  
  var color = '#';  
  if(this.slice(0,4) == 'rgb(') {  
    var cols = this.slice(4,this.length-1).split(',');  
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  } else {  
    if(this.slice(0,1) == '#') {  
      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
      if(this.length==7) color = this.toLowerCase();  
    }  
  }  
  return(color.length==7 ? color : (arguments[0] || this));  
}

/*--------------------------------------------------------------------------*/

lwElement.collectTextNodes = function(element) {  
  return $LWA($LW(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      (node.hasChildNodes() ? lwElement.collectTextNodes(node) : ''));
  }).flatten().join('');
}

lwElement.collectTextNodesIgnoreClass = function(element, className) {  
  return $LWA($LW(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      ((node.hasChildNodes() && !lwElement.hasClassName(node,className)) ? 
        lwElement.collectTextNodesIgnoreClass(node, className) : ''));
  }).flatten().join('');
}

lwElement.setContentZoom = function(element, percent) {
  element = $LW(element);  
  element.setStyle({fontSize: (percent/100) + 'em'});   
  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
  return element;
}

lwElement.getOpacity = function(element){
  element = $LW(element);
  var opacity;
  if (opacity = element.getStyle('opacity'))  
    return parseFloat(opacity);  
  if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))  
    if(opacity[1]) return parseFloat(opacity[1]) / 100;  
  return 1.0;  
}

lwElement.setOpacity = function(element, value){  
  element= $LW(element);  
  if (value == 1){
    element.setStyle({ opacity: 
      (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 
      0.999999 : 1.0 });
    if(/MSIE/.test(navigator.userAgent) && !window.opera)  
      element.setStyle({filter: lwElement.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});  
  } else {  
    if(value < 0.00001) value = 0;  
    element.setStyle({opacity: value});
    if(/MSIE/.test(navigator.userAgent) && !window.opera)  
      element.setStyle(
        { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
            'alpha(opacity='+value*100+')' });  
  }
  return element;
}  
 
lwElement.getInlineOpacity = function(element){  
  return $LW(element).style.opacity || '';
}  

lwElement.forceRerendering = function(element) {
  try {
    element = $LW(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    element.removeChild(n);
  } catch(e) { }
};

/*--------------------------------------------------------------------------*/

Array.prototype.call = function() {
  var args = arguments;
  this.each(function(f){ f.apply(this, args) });
}

/*--------------------------------------------------------------------------*/

var lwEffect = {
  _elementDoesNotExistError: {
    name: 'lwElementDoesNotExistError',
    message: 'The specified DOM element does not exist, but is required for this effect to operate'
  },
  tagifyText: function(element) {
    if(typeof Builder == 'undefined')
      throw("lwEffect.tagifyText requires including script.aculo.us' builder.js library");
      

    var tagifyStyle = 'position:relative';
    if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
    
    element = $LW(element);
    $LWA(element.childNodes).each( function(child) {
      if(child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            Builder.node('span',{style: tagifyStyle},
              character == ' ' ? String.fromCharCode(160) : character), 
              child);
        });
        lwElement.remove(child);
      }
    });
  },
  multiple: function(element, effect) {
    var elements;
    if(((typeof element == 'object') || 
        (typeof element == 'function')) && 
       (element.length))
      elements = element;
    else
      elements = $LW(element).childNodes;
      
    var options = Object.extend({
      speed: 0.1,
      delay: 0.0
    }, arguments[2] || {});
    var masterDelay = options.delay;

    $LWA(elements).each( function(element, index) {
      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
    });
  },
  PAIRS: {
    'slide':  ['SlideDown','SlideUp'],
    'blind':  ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },
  toggle: function(element, effect) {
    element = $LW(element);
    effect = (effect || 'appear').toLowerCase();
    var options = Object.extend({
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
    }, arguments[2] || {});
    lwEffect[element.visible() ? 
      lwEffect.PAIRS[effect][1] : lwEffect.PAIRS[effect][0]](element, options);
  }
};

var lwEffect2 = lwEffect; // deprecated

/* ------------- transitions ------------- */

lwEffect.Transitions = {
  linear: lwPrototype.K,
  sinoidal: function(pos) {
    return (-Math.cos(pos*Math.PI)/2) + 0.5;
  },
  reverse: function(pos) {
    return 1-pos;
  },
  flicker: function(pos) {
    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
  },
  wobble: function(pos) {
    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  },
  pulse: function(pos, pulses) { 
    pulses = pulses || 5; 
    return (
      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
      );
  },
  none: function(pos) {
    return 0;
  },
  full: function(pos) {
    return 1;
  }
};

/* ------------- core effects ------------- */

lwEffect.ScopedQueue = Class.create();
Object.extend(Object.extend(lwEffect.ScopedQueue.prototype, Enumerable), {
  initialize: function() {
    this.effects  = [];
    this.interval = null;
  },
  _each: function(iterator) {
    this.effects._each(iterator);
  },
  add: function(effect) {
    var timestamp = new Date().getTime();
    
    var position = (typeof effect.options.queue == 'string') ? 
      effect.options.queue : effect.options.queue.position;
    
    switch(position) {
      case 'front':
        // move unstarted effects after this effect  
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'with-last':
        timestamp = this.effects.pluck('startOn').max() || timestamp;
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }
    
    effect.startOn  += timestamp;
    effect.finishOn += timestamp;

    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
      this.effects.push(effect);
    
    if(!this.interval) 
      this.interval = setInterval(this.loop.bind(this), 40);
  },
  remove: function(effect) {
    this.effects = this.effects.reject(function(e) { return e==effect });
    if(this.effects.length == 0) {
      clearInterval(this.interval);
      this.interval = null;
    }
  },
  loop: function() {
    var timePos = new Date().getTime();
    this.effects.invoke('loop', timePos);
  }
});

lwEffect.Queues = {
  instances: $LWH(),
  get: function(queueName) {
    if(typeof queueName != 'string') return queueName;
    
    if(!this.instances[queueName])
      this.instances[queueName] = new lwEffect.ScopedQueue();
      
    return this.instances[queueName];
  }
}
lwEffect.Queue = lwEffect.Queues.get('global');

lwEffect.DefaultOptions = {
  transition: lwEffect.Transitions.sinoidal,
  duration:   1.0,   // seconds
  fps:        25.0,  // max. 25fps due to lwEffect.Queue implementation
  sync:       false, // true for combining
  from:       0.0,
  to:         1.0,
  delay:      0.0,
  queue:      'parallel'
}

lwEffect.Base = function() {};
lwEffect.Base.prototype = {
  position: null,
  start: function(options) {
    this.options      = Object.extend(Object.extend({},lwEffect.DefaultOptions), options || {});
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn + (this.options.duration*1000);
    this.event('beforeStart');
    if(!this.options.sync)
      lwEffect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).add(this);
  },
  loop: function(timePos) {
    if(timePos >= this.startOn) {
      if(timePos >= this.finishOn) {
        this.render(1.0);
        this.cancel();
        this.event('beforeFinish');
        if(this.finish) this.finish(); 
        this.event('afterFinish');
        return;  
      }
      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
      var frame = Math.round(pos * this.options.fps * this.options.duration);
      if(frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  render: function(pos) {
    if(this.state == 'idle') {
      this.state = 'running';
      this.event('beforeSetup');
      if(this.setup) this.setup();
      this.event('afterSetup');
    }
    if(this.state == 'running') {
      if(this.options.transition) pos = this.options.transition(pos);
      pos *= (this.options.to-this.options.from);
      pos += this.options.from;
      this.position = pos;
      this.event('beforeUpdate');
      if(this.update) this.update(pos);
      this.event('afterUpdate');
    }
  },
  cancel: function() {
    if(!this.options.sync)
      lwEffect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).remove(this);
    this.state = 'finished';
  },
  event: function(eventName) {
    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
    if(this.options[eventName]) this.options[eventName](this);
  },
  inspect: function() {
    return '#<lwEffect:' + $LWH(this).inspect() + ',options:' + $LWH(this.options).inspect() + '>';
  }
}

lwEffect.Parallel = Class.create();
Object.extend(Object.extend(lwEffect.Parallel.prototype, lwEffect.Base.prototype), {
  initialize: function(effects) {
    this.effects = effects || [];
    this.start(arguments[1]);
  },
  update: function(position) {
    this.effects.invoke('render', position);
  },
  finish: function(position) {
    this.effects.each( function(effect) {
      effect.render(1.0);
      effect.cancel();
      effect.event('beforeFinish');
      if(effect.finish) effect.finish(position);
      effect.event('afterFinish');
    });
  }
});

lwEffect.Event = Class.create();
Object.extend(Object.extend(lwEffect.Event.prototype, lwEffect.Base.prototype), {
  initialize: function() {
    var options = Object.extend({
      duration: 0
    }, arguments[0] || {});
    this.start(options);
  },
  update: lwPrototype.emptyFunction
});

lwEffect.Opacity = Class.create();
Object.extend(Object.extend(lwEffect.Opacity.prototype, lwEffect.Base.prototype), {
  initialize: function(element) {
    this.element = $LW(element);
    if(!this.element) throw(lwEffect._elementDoesNotExistError);
    // make this work on IE on elements without 'layout'
    if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
      this.element.setStyle({zoom: 1});
    var options = Object.extend({
      from: this.element.getOpacity() || 0.0,
      to:   1.0
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    this.element.setOpacity(position);
  }
});

lwEffect.Move = Class.create();
Object.extend(Object.extend(lwEffect.Move.prototype, lwEffect.Base.prototype), {
  initialize: function(element) {
    this.element = $LW(element);
    if(!this.element) throw(lwEffect._elementDoesNotExistError);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Bug in Opera: Opera returns the "real" position of a static element or
    // relative element that does not have top/left explicitly set.
    // ==> Always set top and left for position relative elements in your stylesheets 
    // (to 0 if you do not need them) 
    this.element.makePositioned();
    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
    if(this.options.mode == 'absolute') {
      // absolute movement, so we need to calc deltaX and deltaY
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  update: function(position) {
    this.element.setStyle({
      left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
    });
  }
});

// for backwards compatibility
lwEffect.MoveBy = function(element, toTop, toLeft) {
  return new lwEffect.Move(element, 
    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};

lwEffect.Scale = Class.create();
Object.extend(Object.extend(lwEffect.Scale.prototype, lwEffect.Base.prototype), {
  initialize: function(element, percent) {
    this.element = $LW(element);
    if(!this.element) throw(lwEffect._elementDoesNotExistError);
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
      scaleFrom: 100.0,
      scaleTo:   percent
    }, arguments[2] || {});
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle('position');
    
    this.originalStyle = {};
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
    
    var fontSize = this.element.getStyle('font-size') || '100%';
    ['em','px','%','pt'].each( function(fontSizeType) {
      if(fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));
    
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
    
    this.dims = null;
    if(this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if(this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });

    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = {};
    if(this.options.scaleX) d.width = Math.round(width) + 'px';
    if(this.options.scaleY) d.height = Math.round(height) + 'px';
    if(this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if(this.elementPositioning == 'absolute') {
        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
      } else {
        if(this.options.scaleY) d.top = -topd + 'px';
        if(this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    this.element.setStyle(d);
  }
});

lwEffect.Highlight = Class.create();
Object.extend(Object.extend(lwEffect.Highlight.prototype, lwEffect.Base.prototype), {
  initialize: function(element) {
    this.element = $LW(element);
    if(!this.element) throw(lwEffect._elementDoesNotExistError);
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Prevent executing on elements not in the layout flow
    if(this.element.getStyle('display')=='none') { this.cancel(); return; }
    // Disable background image during the effect
    this.oldStyle = {
      backgroundImage: this.element.getStyle('background-image') };
    this.element.setStyle({backgroundImage: 'none'});
    if(!this.options.endcolor)
      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
    if(!this.options.restorecolor)
      this.options.restorecolor = this.element.getStyle('background-color');
    // init color calculations
    this._base  = $LWR(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
    this._delta = $LWR(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
  },
  update: function(position) {
    this.element.setStyle({backgroundColor: $LWR(0,2).inject('#',function(m,v,i){
      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
  },
  finish: function() {
    this.element.setStyle(Object.extend(this.oldStyle, {
      backgroundColor: this.options.restorecolor
    }));
  }
});

lwEffect.ScrollTo = Class.create();
Object.extend(Object.extend(lwEffect.ScrollTo.prototype, lwEffect.Base.prototype), {
  initialize: function(element) {
    this.element = $LW(element);
    this.start(arguments[1] || {});
  },
  setup: function() {
    Position.prepare();
    var offsets = Position.cumulativeOffset(this.element);
    if(this.options.offset) offsets[1] += this.options.offset;
    var max = window.innerHeight ? 
      window.height - window.innerHeight :
      document.body.scrollHeight - 
        (document.documentElement.clientHeight ? 
          document.documentElement.clientHeight : document.body.clientHeight);
    this.scrollStart = Position.deltaY;
    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
  },
  update: function(position) {
    Position.prepare();
    window.scrollTo(Position.deltaX, 
      this.scrollStart + (position*this.delta));
  }
});

/* ------------- combination effects ------------- */

lwEffect.Fade = function(element) {
  element = $LW(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
  from: element.getOpacity() || 1.0,
  to:   0.0,
  afterFinishInternal: function(effect) { 
    if(effect.options.to!=0) return;
    effect.element.hide().setStyle({opacity: oldOpacity}); 
  }}, arguments[1] || {});
  return new lwEffect.Opacity(element,options);
}

lwEffect.Appear = function(element) {
  element = $LW(element);
  var options = Object.extend({
  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
  to:   1.0,
  // force Safari to render floated elements properly
  afterFinishInternal: function(effect) {
    effect.element.forceRerendering();
  },
  beforeSetup: function(effect) {
    effect.element.setOpacity(effect.options.from).show(); 
  }}, arguments[1] || {});
  return new lwEffect.Opacity(element,options);
}

lwEffect.Puff = function(element) {
  element = $LW(element);
  var oldStyle = { 
    opacity: element.getInlineOpacity(), 
    position: element.getStyle('position'),
    top:  element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height
  };
  return new lwEffect.Parallel(
   [ new lwEffect.Scale(element, 200, 
      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
     new lwEffect.Opacity(element, { sync: true, to: 0.0 } ) ], 
     Object.extend({ duration: 1.0, 
      beforeSetupInternal: function(effect) {
        Position.absolutize(effect.effects[0].element)
      },
      afterFinishInternal: function(effect) {
         effect.effects[0].element.hide().setStyle(oldStyle); }
     }, arguments[1] || {})
   );
}

lwEffect.BlindUp = function(element) {
  element = $LW(element);
  element.makeClipping();
  return new lwEffect.Scale(element, 0,
    Object.extend({ scaleContent: false, 
      scaleX: false, 
      restoreAfterFinish: true,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping();
      } 
    }, arguments[1] || {})
  );
}

lwEffect.BlindDown = function(element) {
  element = $LW(element);
  var elementDimensions = element.getDimensions();
  return new lwEffect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false,
    scaleFrom: 0,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.undoClipping();
    }
  }, arguments[1] || {}));
}

lwEffect.SwitchOff = function(element) {
  element = $LW(element);
  var oldOpacity = element.getInlineOpacity();
  return new lwEffect.Appear(element, Object.extend({
    duration: 0.4,
    from: 0,
    transition: lwEffect.Transitions.flicker,
    afterFinishInternal: function(effect) {
      new lwEffect.Scale(effect.element, 1, { 
        duration: 0.3, scaleFromCenter: true,
        scaleX: false, scaleContent: false, restoreAfterFinish: true,
        beforeSetup: function(effect) { 
          effect.element.makePositioned().makeClipping();
        },
        afterFinishInternal: function(effect) {
          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
        }
      })
    }
  }, arguments[1] || {}));
}

lwEffect.DropOut = function(element) {
  element = $LW(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left'),
    opacity: element.getInlineOpacity() };
  return new lwEffect.Parallel(
    [ new lwEffect.Move(element, {x: 0, y: 100, sync: true }), 
      new lwEffect.Opacity(element, { sync: true, to: 0.0 }) ],
    Object.extend(
      { duration: 0.5,
        beforeSetup: function(effect) {
          effect.effects[0].element.makePositioned(); 
        },
        afterFinishInternal: function(effect) {
          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
        } 
      }, arguments[1] || {}));
}

lwEffect.Shake = function(element) {
  element = $LW(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left') };
    return new lwEffect.Move(element, 
      { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
    new lwEffect.Move(effect.element,
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new lwEffect.Move(effect.element,
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new lwEffect.Move(effect.element,
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new lwEffect.Move(effect.element,
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new lwEffect.Move(effect.element,
      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
        effect.element.undoPositioned().setStyle(oldStyle);
  }}) }}) }}) }}) }}) }});
}

lwEffect.SlideDown = function(element) {
  element = $LW(element).cleanWhitespace();
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  var oldInnerBottom = element.down().getStyle('bottom');
  var elementDimensions = element.getDimensions();
  return new lwEffect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false, 
    scaleFrom: window.opera ? 0 : 1,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if(window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
    },
    afterFinishInternal: function(effect) {
      effect.element.undoClipping().undoPositioned();
      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
    }, arguments[1] || {})
  );
}

lwEffect.SlideUp = function(element) {
  element = $LW(element).cleanWhitespace();
  var oldInnerBottom = element.down().getStyle('bottom');
  return new lwEffect.Scale(element, window.opera ? 0 : 1,
   Object.extend({ scaleContent: false, 
    scaleX: false, 
    scaleMode: 'box',
    scaleFrom: 100,
    restoreAfterFinish: true,
    beforeStartInternal: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if(window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().show();
    },  
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' });
    },
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
      effect.element.down().undoPositioned();
    }
   }, arguments[1] || {})
  );
}

// Bug in opera makes the TD containing this element expand for a instance after finish 
lwEffect.Squish = function(element) {
  return new lwEffect.Scale(element, window.opera ? 1 : 0, { 
    restoreAfterFinish: true,
    beforeSetup: function(effect) {
      effect.element.makeClipping(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping(); 
    }
  });
}

lwEffect.Grow = function(element) {
  element = $LW(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: lwEffect.Transitions.sinoidal,
    scaleTransition: lwEffect.Transitions.sinoidal,
    opacityTransition: lwEffect.Transitions.full
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();    
  var initialMoveX, initialMoveY;
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      initialMoveX = initialMoveY = moveX = moveY = 0; 
      break;
    case 'top-right':
      initialMoveX = dims.width;
      initialMoveY = moveY = 0;
      moveX = -dims.width;
      break;
    case 'bottom-left':
      initialMoveX = moveX = 0;
      initialMoveY = dims.height;
      moveY = -dims.height;

      break;
    case 'bottom-right':
      initialMoveX = dims.width;
      initialMoveY = dims.height;
      moveX = -dims.width;
      moveY = -dims.height;
      break;
    case 'center':
      initialMoveX = dims.width / 2;
      initialMoveY = dims.height / 2;
      moveX = -dims.width / 2;
      moveY = -dims.height / 2;
      break;
  }
  
  return new lwEffect.Move(element, {
    x: initialMoveX,
    y: initialMoveY,
    duration: 0.01, 
    beforeSetup: function(effect) {
      effect.element.hide().makeClipping().makePositioned();
    },
    afterFinishInternal: function(effect) {
      new lwEffect.Parallel(
        [ new lwEffect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
          new lwEffect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
          new lwEffect.Scale(effect.element, 100, {
            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
        ], Object.extend({
             beforeSetup: function(effect) {
               effect.effects[0].element.setStyle({height: '0px'}).show(); 
             },
             afterFinishInternal: function(effect) {
               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
             }
           }, options)
      )
    }
  });
}

lwEffect.Shrink = function(element) {
  element = $LW(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: lwEffect.Transitions.sinoidal,
    scaleTransition: lwEffect.Transitions.sinoidal,
    opacityTransition: lwEffect.Transitions.none
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      moveX = moveY = 0;
      break;
    case 'top-right':
      moveX = dims.width;
      moveY = 0;
      break;
    case 'bottom-left':
      moveX = 0;
      moveY = dims.height;
      break;
    case 'bottom-right':
      moveX = dims.width;
      moveY = dims.height;
      break;
    case 'center':  
      moveX = dims.width / 2;
      moveY = dims.height / 2;
      break;
  }
  
  return new lwEffect.Parallel(
    [ new lwEffect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
      new lwEffect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
      new lwEffect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
    ], Object.extend({            
         beforeStartInternal: function(effect) {
           effect.effects[0].element.makePositioned().makeClipping(); 
         },
         afterFinishInternal: function(effect) {
           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
       }, options)
  );
}

lwEffect.Pulsate = function(element) {
  element = $LW(element);
  var options    = arguments[1] || {};
  var oldOpacity = element.getInlineOpacity();
  var transition = options.transition || lwEffect.Transitions.sinoidal;
  var reverser   = function(pos){ return transition(1-lwEffect.Transitions.pulse(pos, options.pulses)) };
  reverser.bind(transition);
  return new lwEffect.Opacity(element, 
    Object.extend(Object.extend({  duration: 2.0, from: 0,
      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
    }, options), {transition: reverser}));
}

lwEffect.Fold = function(element) {
  element = $LW(element);
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height };
  element.makeClipping();
  return new lwEffect.Scale(element, 5, Object.extend({   
    scaleContent: false,
    scaleX: false,
    afterFinishInternal: function(effect) {
    new lwEffect.Scale(element, 1, { 
      scaleContent: false, 
      scaleY: false,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping().setStyle(oldStyle);
      } });
  }}, arguments[1] || {}));
};

['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
 'collectTextNodes','collectTextNodesIgnoreClass'].each( 
  function(f) { lwElement.Methods[f] = lwElement[f]; }
);

lwElement.Methods.visualEffect = function(element, effect, options) {
  s = effect.gsub(/_/, '-').camelize();
  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
  new lwEffect[effect_class](element, options);
  return $LW(element);
};

lwElement.addMethods();


// lightWindow.js v1.2.1
//
// Copyright (c) 2007 Einstein Industries
// Author: Kevin P Miller | http://www.stickmanlabs.com
//
// LightWindow is freely distributable under the terms of an MIT-style license.
//
// I don't care what you think about the file size...
//   Be a pro:
//	    http://www.thinkvitamin.com/features/webapps/serving-javascript-fast
//      http://rakaz.nl/item/make_your_pages_load_faster_by_combining_and_compressing_javascript_and_css_files
//

/*-----------------------------------------------------------------------------------------------*/

if(typeof lwEffect == 'undefined')
  throw("lightWindow.js requires including script.aculo.us' effects.js library!");

var lightWindow = Class.create();
lightWindow.prototype = {
	//
	//	Setup Variables
	//
	element : null,
	contentToFetch : null,
	boxOverFlow : 'hidden',
	retroIE : null,
	windowType : null,
	animating : false,
	scrollX : null,
	scrollY : null,
	imageArray : [],
	preloadImage : null,
	activeGallery : null,
	activeImage : 0,
	galleryDirection : null,
	showDataToggle : false,
	galleryToggle : false,
	showTitleToggle : false,
	//
	//	Initialize the lightWindow.
	//
	initialize : function(options) {
		this.options = Object.extend({
			resizeSpeed : 9,
			cushion : 10,
			dimensions : {
				image : {height : 250, width : 250},
				page : {height : 250, width : 500},
				inline : {height : 250, width : 500},
				media : {height : 250, width : 250},
				external : {height : 250, width : 250},
				dataHeight : 60,
				titleHeight : 25
			},
			classNames : {
				standard : 'lWOn',
				action : 'lWAction'
			},
			fileTypes : {
				page : ['asp', 'aspx', 'cgi', 'htm', 'html', 'pl', 'php4', 'php3', 'php', 'php5', 'phtml', 'rhtml', 'shtml', 'txt', 'vbs', 'rb'],
				media : ['aif', 'aiff', 'asf', 'avi', 'divx', 'm1v', 'm2a', 'm2v', 'm3u', 'mid', 'midi', 'mov', 'moov', 'movie', 'mp2', 'mp3', 'mpa', 'mpa', 'mpe', 'mpeg', 'mpg', 'mpg', 'mpga', 'pps', 'qt', 'rm', 'ram', 'swf', 'viv', 'vivo', 'wav'],
				image : ['bmp', 'gif', 'jpg', 'png', 'tiff']
			},
			mimeTypes : {
				avi : 'video/avi',
				aif : 'audio/aiff',
				aiff : 'audio/aiff',
				gif : 'image/gif',
				bmp : 'image/bmp',
				jpeg : 'image/jpeg',
				m1v : 'video/mpeg',
				m2a : 'audio/mpeg',
				m2v : 'video/mpeg',
				m3u : 'audio/x-mpequrl',
				mid : 'audio/x-midi',
				midi : 'audio/x-midi',
				mjpg : 'video/x-motion-jpeg',
				moov : 'video/quicktime',
				mov : 'video/quicktime',
				movie : 'video/x-sgi-movie',
				mp2 : 'audio/mpeg',
				mp3 : 'audio/mpeg3',
				mpa : 'audio/mpeg',
				mpa : 'video/mpeg',
				mpe : 'video/mpeg',
				mpeg : 'video/mpeg',
				mpg : 'audio/mpeg',
				mpg : 'video/mpeg',
				mpga : 'audio/mpeg',
				pdf : 'application/pdf',
				png : 'image/png',
				pps : 'application/mspowerpoint',
				qt : 'video/quicktime',
				ram : 'audio/x-pn-realaudio-plugin',
				rm : 'application/vnd.rn-realmedia',
				swf	: 'application/x-shockwave-flash',
				tiff : 'image/tiff',
				viv : 'video/vivo',
				vivo : 'video/vivo',
				wav : 'audio/wav'
			},
			loadingDialog : {
				message : 'Loading',
				image :  '/common/images/lightwindow/ajax-loading.gif',
				options : '<a onclick="javascript: mylightWindow.deactivate();">Cancel</a>',
				delay : 3.0
			},
			authorLead : 'by ',
			galleryTab : {
				name : 'Galleries',
				height : 20,
				visible : true
			},
			overlay : {
				color : '#000000',
				opacity : 70,
				image : '/common/images/lightwindow/black-70.png'
			},
			formMethod : 'get',
			hideFlash : true,
			showTitleBar : true
		}, options || {})
		this.duration = ((11-this.options.resizeSpeed)*0.15);
		this.setupLinks();
		this.addLightWindowMarkup(false);
		this.setupDimensions(true);
	},
	//
	//  Set Links Up
	//
	setupLinks : function () {
		var links = $$LW('.'+this.options.classNames.standard);
		links.each(function(link) {
			if (this.fileType(link.href) == 'image') {
				if (gallery = this.getGalleryInfo(link.rel)) {
					if (!this.imageArray[gallery[0]]) this.imageArray[gallery[0]] = new Array();
					if (!this.imageArray[gallery[0]][gallery[1]]) this.imageArray[gallery[0]][gallery[1]] = new Array();
					this.imageArray[gallery[0]][gallery[1]].push(new Array(link.href, link.getAttribute('title'), link.getAttribute('caption'), link.getAttribute('author'), link.getAttribute('rel'), link.getAttribute('params')));
				}
			}
			var url = link.getAttribute('href');
			if (link.href.indexOf('?') > -1) url = url.substring(0, url.indexOf('?'));
			container = url.substring(url.indexOf('#')+1);
			if($LW(container)) $LW(container).style.display = 'none';
			Event.observe(link, 'click', this.activate.bindAsEventListener(this, link));
			link.onclick = function() {return false;};
		}.bind(this));
	},
	//
	//  Initialize specific window
	//
	initializeWindow : function (id) {
		var link = $LW(id);
		if (this.fileType(link.href) == 'image') {
			if (gallery = this.getGalleryInfo(link.rel)) {
				if (!this.imageArray[gallery[0]]) this.imageArray[gallery[0]] = new Array();
				if (!this.imageArray[gallery[0]][gallery[1]]) this.imageArray[gallery[0]][gallery[1]] = new Array();
				this.imageArray[gallery[0]][gallery[1]].push(new Array(link.href, link.getAttribute('title'), link.getAttribute('caption'), link.getAttribute('author'), link.getAttribute('rel'), link.getAttribute('params')));
			}
		}
		var url = link.getAttribute('href');
		if (link.href.indexOf('?') > -1) url = url.substring(0, url.indexOf('?'));
		container = url.substring(url.indexOf('#')+1);
		if($LW(container)) $LW(container).style.display = 'none';
		Event.observe(link, 'click', this.activate.bindAsEventListener(this, link));
		link.onclick = function() {return false;};
	},
	//
	//	Add the markup to the page.
	//
	addLightWindowMarkup : function(rebuild) {
	    if (!rebuild) {
			var overlay = document.createElement('div');
			overlay.setAttribute('id', 'overlay');
			if (this.checkBrowser('firefox')) {
				overlay.style.backgroundImage = 'url('+this.options.overlay.image+')';
			   	overlay.style.backgroundRepeat = 'repeat';
			} else {
				overlay.style.backgroundColor = this.options.overlay.color;
			    overlay.style.MozOpacity = '.'+this.options.overlay.opacity;
			    overlay.style.opacity = '.'+this.options.overlay.opacity;
			    overlay.style.filter = 'alpha(opacity='+this.options.overlay.opacity+')';
			}
			var lw = document.createElement('div');
			lw.setAttribute('id', 'lightWindow');
		} else {
			var lw = $LW('lightWindow');
		}

		if (this.options.showTitleBar) lw = this.addTitleBarMarkup(lw);

		var lwc = document.createElement('div');
		lwc.setAttribute('id', 'lightWindow-contents');

		var lwcc = document.createElement('div');
		lwcc.setAttribute('id', 'lightWindow-contents-container');
		lwc.appendChild(lwcc);

		var lwl = document.createElement('div');
		lwl.setAttribute('id', 'lightWindow-loading');

		var lwi = document.createElement('img');
		lwi.setAttribute('src', this.options.loadingDialog.image);
		lwl.appendChild(lwi);

		var lwld = document.createElement('span');
		lwld.setAttribute('id', 'lightWindow-loading-message');
		lwld.innerHTML += this.options.loadingDialog.message;
		lwl.appendChild(lwld);

		var lwlo = document.createElement('span');
		lwlo.setAttribute('id', 'lightWindow-loading-options');
		lwlo.setAttribute('style', 'display:none;');
		lwlo.innerHTML += this.options.loadingDialog.options;
		lwl.appendChild(lwlo);

		lwc.appendChild(lwl);

		lw.appendChild(lwc);

		if (!rebuild) {
			var body = document.getElementsByTagName('body')[0];
			body.appendChild(overlay);
			body.appendChild(lw);
			Event.observe(overlay, 'click', this.deactivate.bindAsEventListener(this), false);
			overlay.onclick = function() {return false;};
		}
		this.addDataWindowMarkup();
		this.actions('#lightWindow-loading-options');
	},
	//
	//	Add the Title Bar Markup
	//
	addTitleBarMarkup : function(lw) {

		var lwdt = document.createElement('div');
		lwdt.setAttribute('id', 'lightWindow-title-bar');
		lwdt.style.visibility = 'hidden';

		var lwdtt = document.createElement('div');
		lwdtt.setAttribute('id', 'lightWindow-title-bar-title');
		lwdt.appendChild(lwdtt);

		var lwdtc = document.createElement('div');
		lwdtc.setAttribute('id', 'lightWindow-title-bar-close');


		var lwdtca = document.createElement('a');
		lwdtca.setAttribute('id', 'lightWindow-title-bar-close-link');
		lwdtca.innerHTML = 'close';
		Event.observe(lwdtca, 'click', this.deactivate.bindAsEventListener(this));
		lwdtca.onclick = function() {return false;};
		lwdtc.appendChild(lwdtca);
		lwdt.appendChild(lwdtc);

		lw.appendChild(lwdt);
		return lw;

	},
	//
	//	Add the Data Window Markup
	//
	addDataWindowMarkup : function() {
		var lw = $LW('lightWindow');

		var lwd = document.createElement('div');
		lwd.setAttribute('id', 'lightWindow-data');
		lwd.style.display = 'none';

		// This container needs to be here to get the data slide to slide as a group
		var lwds = document.createElement('div');
		lwds.setAttribute('id', 'lightWindow-data-slide');

		if (!this.options.showTitleBar) {
			var lwdt = document.createElement('div');
			lwdt.setAttribute('id', 'lightWindow-data-title');
			lwds.appendChild(lwdt);
		}

		var lwdc = document.createElement('div');
		lwdc.setAttribute('id', 'lightWindow-data-caption');
		lwds.appendChild(lwdc);

		var lwda = document.createElement('div');
		lwda.setAttribute('id', 'lightWindow-data-author');
		lwds.appendChild(lwda);

		var lwdi = document.createElement('div');
		lwdi.setAttribute('id', 'lightWindow-data-image');
		lwds.appendChild(lwdi);

		lwd.appendChild(lwds);
		lw.appendChild(lwd);
	},
	//
	//	Add Photo Window Markup
	//
	addPhotoWindowMarkup : function() {
		var lwc = $LW('lightWindow-contents');

		var lwpc = document.createElement('div');
		lwpc.setAttribute('id', 'lightWindow-photo-container');
		lwpc.style.display = 'none';

		if (images = parseInt(this.getParameter('lWShowImages'))) {
			for (var x = 0; x < images; x++) {
				lwp = document.createElement('img');
	    		lwp.setAttribute('id', 'lightWindow-photo-'+x);
	    		lwpc.appendChild(lwp);
			}
		} else {
			lwp = document.createElement('img');
    		lwp.setAttribute('id', 'lightWindow-photo-0');
    		lwpc.appendChild(lwp);
		}

		// You ask why I do this?  I ask why you insist on using a browser worse than IE? ...Safari!
		lwps = document.createElement('img');
		lwps.setAttribute('id', 'lightWindow-photo-sizer');
		lwps.style.display = 'none';
		lwps.style.height = '1px';
		lwpc.appendChild(lwps);

    	lwc.appendChild(lwpc);
	},
	//
	//	Add Gallery Window Markup
	//
	addGalleryWindowMarkup : function() {
		var lwpc = $LW('lightWindow-photo-container');

		var lwpg = document.createElement('div');
		lwpg.setAttribute('id', 'lightWindow-photo-galleries');
		lwpg.style.display = 'none';
		if (!this.options.galleryTab.visible) lwpg.style.visibility = 'hidden';

		var lwptc = document.createElement('div');
		lwptc.setAttribute('id', 'lightWindow-photo-tab-container');

		var lwpgt = document.createElement('a');
		lwpgt.setAttribute('id', 'lightWindow-photo-galleries-tab');
		lwpgt.className = 'up';
		lwpgt.innerHTML = this.options.galleryTab.name;
		Event.observe(lwpgt, 'click', this.getGallery.bindAsEventListener(this));
		lwpgt.onclick = function() {return false;};

		lwptc.appendChild(lwpgt);
		lwpg.appendChild(lwptc);

		var lwpgl = document.createElement('div');
		lwpgl.setAttribute('id', 'lightWindow-photo-galleries-list');
		lwpg.appendChild(lwpgl);

    	lwpc.appendChild(lwpg);
	},
	//
	//	Activate the lightWindow.
	//
	activate : function(e, link){
		link.blur();
		this.element = link;
		this.element.title = link.getAttribute('title');
		this.element.author = link.getAttribute('author');
		this.element.caption = link.getAttribute('caption');
		this.element.rel = link.getAttribute('rel');
		this.element.params = this.element.getAttribute('params');
		this.windowType = this.fileType(this.contentToFetch = link.href);
		if (this.element.caption || this.element.author) this.showDataToggle = true;
		if (this.options.showTitleBar && this.element.title) this.showTitleToggle = true;
		else if (!this.options.showTitleBar && this.element.title) this.showDataToggle = true;
		if (this.getGalleryInfo(this.element.rel)) this.galleryToggle = true;
		this.prepareIE(true);
		this.toggleTroubleElements('hidden', false);
		this.displayLightWindow(true);
		this.setupDimensions(true);
		this.monitorKeyboard(true);
		this.loadInfo();
	},
	//
	//	Turn off the window
	//
	deactivate : function(){
		var queue = lwEffect.Queues.get('lightWindowAnimation').each(function(e) {e.cancel();});
		queue = lwEffect.Queues.get('lightWindowAnimation-loading').each(function(e) {e.cancel();});
		if ($LW('lightWindow-iframe')) lwElement.remove($LW('lightWindow-iframe'));
		lwElement.remove($LW('lightWindow-contents'));
		if ($LW('lightWindow-data')) lwElement.remove($LW('lightWindow-data'));
		if ($LW('lightWindow-title-bar')) lwElement.remove($LW('lightWindow-title-bar'));
		this.displayLightWindow(false);
		this.boxOverFlow = 'hidden';
		this.prepareIE(false);
		this.setStatus(false);
		this.showDataToggle = this.galleryToggle = this.showTitleToggle = false;
		this.addLightWindowMarkup(true);
		this.setupDimensions(true);
		this.monitorKeyboard(false);
		this.toggleTroubleElements('visible', false);
	},
	//
	//	Setup our actions
	//
	actions : function(prefix) {
		if (prefix) links = $$LW(prefix+' .'+this.options.classNames.action);
		else links = $$LW('.'+this.options.classNames.action);
		links.each(function(link) {
			Event.observe(link, 'click', this[link.rel].bindAsEventListener(this, link), false);
			link.onclick = function() {return false;};
		}.bind(this));
	},
	//
	//	Set the staus of our animation to keep things from getting clunky
	//
	setStatus : function(status) {
		this.animating = status;
		// We have to put this here to avoid a flicker in FF Mac
		if (this.showTitleToggle && !status && $LW('lightWindow-title-bar')) {
			$LW('lightWindow-title-bar').setStyle({
				visibility : 'visible'
			});
		}
	},
	//
	//	Setup Dimensions of lightWindow.
	//
	setupDataDimensions : function() {
		if ($LW('lightWindow-contents') && $LW('lightWindow-data') && this.showDataToggle) {
			$LW('lightWindow-data').setStyle({
				height : this.options.dimensions.dataHeight+'px',
		  		width : (parseFloat($LW('lightWindow-contents').style.width)+this.options.cushion*2)+'px'
			});
			$LW('lightWindow-data-slide').setStyle({
				height : this.options.dimensions.dataHeight+'px',
		  		overflow : 'hidden' // Because of IE
			});
		}
		if (this.showTitleToggle && $LW('lightWindow-title-bar')) {
			$LW('lightWindow-title-bar').setStyle({
				height : this.options.dimensions.titleHeight+'px',
	  			width : (parseFloat($LW('lightWindow-contents').style.width)+this.options.cushion*2)+'px'
			});
		}
	},
	//
	//	Setup Dimensions of lightWindow.
	//
	setupDimensions : function(reset) {
		if (this.showDataToggle || (this.galleryToggle && this.options.galleryTab.visible)) var adjust = this.options.dimensions.dataHeight;
		else var adjust = 0;

		var originalHeight, originalWidth, titleHeight;
		switch (this.windowType) {
			case 'page' :
				originalHeight = this.options.dimensions.page.height;
				originalWidth = this.options.dimensions.page.width;
				break;

			case 'image' :
				originalHeight = this.options.dimensions.image.height;
				originalWidth = this.options.dimensions.image.width;
				break;

			case 'media' :
				originalHeight = this.options.dimensions.media.height;
				originalWidth = this.options.dimensions.media.width;
				break;

			case 'external' :
				originalHeight = this.options.dimensions.external.height;
				originalWidth = this.options.dimensions.external.width;
				break;

			case 'inline' :
				originalHeight = this.options.dimensions.inline.height;
				originalWidth = this.options.dimensions.inline.width;
				break;

			default :
				originalHeight = this.options.dimensions.page.height;
				originalWidth = this.options.dimensions.page.width;
				break;

		}
		if (this.showTitleToggle) titleHeight = this.options.dimensions.titleHeight; // We subtract one to smooth out the hiccup when the title bar is added
		else titleHeight = 0;

		if (reset) {
			var lightWindowContents = $LW('lightWindow-contents');
			if (lightWindowContents) {
				if (parseFloat($LW('lightWindow-contents').style.height) != originalHeight) {
					lightWindowContents.setStyle({
						top : titleHeight+'px',
					  	width : (originalWidth+this.options.cushion)+'px',
					  	height : (originalHeight+this.options.cushion)+'px'
					});
				} else {
					lightWindowContents.setStyle({
						top : '0px',
					  	width : (originalWidth+this.options.cushion)+'px',
					  	height : (originalHeight+this.options.cushion)+'px'
					});
				}
			}
			$LW('lightWindow').setStyle({
				padding : '0 0 0 0',
			  	width : '0px',
			  	height : '0px',
				margin : (-(((originalHeight+this.options.cushion*3)/2)+(adjust/2)+(titleHeight/2)))+'px 0 0 '+(-((originalWidth+this.options.cushion*3)/2))+'px'
			});
		} else {
			$LW('lightWindow').setStyle({
				padding : parseFloat($LW('lightWindow-contents').style.height)+2*this.options.cushion+titleHeight+'px 0 0 0',
	  			width : '0px',
	  			height : '0px',
				margin : (-(((parseFloat($LW('lightWindow-contents').style.height)+this.options.cushion*2)/2)+(adjust/2)+(titleHeight/2)))+'px 0 0 '+(-((parseFloat($LW('lightWindow-contents').style.width)+this.options.cushion*2)/2))+'px'
			});
			if (parseFloat($LW('lightWindow-contents').style.height) != originalHeight) {
				$LW('lightWindow-contents').setStyle({
					top : titleHeight+'px',
					left : '0px'
				});
			}
		}
	},
	//
	// Setup the Overlay (Special Thanks to quirksmode.com and huddletogether.com)
	//
	setupOverlay : function() {

		var xScroll, yScroll;

		if (window.innerHeight && window.scrollMaxY) {
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else {
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if (self.innerHeight) {
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) {
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) {
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}

		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else {
			pageHeight = yScroll;
		}

		if(xScroll < windowWidth){
			pageWidth = windowWidth;
		} else {
			pageWidth = xScroll;
		}

		$LW('overlay').style.height = pageHeight;
		$LW('overlay').style.width = pageWidth;
	},
	displayLightWindow : function(display) {
		if (display) {
			$LW('overlay').style.display = 'block';
			$LW('lightWindow').style.display =  'block';
			$LW('lightWindow-contents').style.display = 'block';
		} else {
			$LW('overlay').style.display = $LW('lightWindow').style.display = 'none';
		}
	},
	checkBrowser : function(type) {
		var detect = navigator.userAgent.toLowerCase();
		var version = parseInt(navigator.appVersion);
		var place = detect.indexOf(type)+1;
		return place;
	},
	prepareIE : function(setup) {
		if (this.checkBrowser('msie')) {
			var height, overflowX, overflowY;
			if (setup) {
				this.getScroll();
				this.setScroll(0, 0);
				var height = '100%';
			} else {
				var height = 'auto';
			}
			var body = document.getElementsByTagName('body')[0];
			var html = document.getElementsByTagName('html')[0];
			html.style.height = body.style.height = height;
			html.style.margin = body.style.margin = '0';
			this.setupOverlay();
			if (!setup) this.setScroll(this.scrollX, this.scrollY);
		}
	},
	//
	//	Hide Selects from the page because of IE.
	//     We could use iframe shims instead here but why add all the extra markup for one browser when this is much easier and cleaner
	//
	toggleTroubleElements : function(visibility, content){
		if (content) var selects = $LW('lightWindow-contents').getElementsByTagName('select');
		else var selects = document.getElementsByTagName('select');
		for(var i = 0; i < selects.length; i++) {
			selects[i].style.visibility = visibility;
		}
		if (!content) {
			if (this.options.hideFlash){
				var objects = document.getElementsByTagName('object');
				for (i = 0; i != objects.length; i++) {
					objects[i].style.visibility = visibility;
				}
				var embeds = document.getElementsByTagName('embed');
				for (i = 0; i != embeds.length; i++) {
					embeds[i].style.visibility = visibility;
				}
			}
			var iframes = document.getElementsByTagName('iframe');
			for (i = 0; i != iframes.length; i++) {
				iframes[i].style.visibility = visibility;
			}
		}
	},
	//
	//	Get the scroll for the page.
	//
	getScroll : function(){
      	if(typeof(window.pageYOffset) == 'number') {
        	this.scrollY = window.pageYOffset;
        	this.scrollX = window.pageXOffset;
      	} else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
        	this.scrollY = document.body.scrollTop;
        	this.scrollX = document.body.scrollLeft;
      	} else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
        	this.scrollY = document.documentElement.scrollTop;
        	this.scrollX = document.documentElement.scrollLeft;
      	}
	},
	//
	//	Reset the scroll.
	//
	setScroll : function(x, y) {
		document.documentElement.scrollLeft = x;
		document.documentElement.scrollTop = y;
	},
	//
	//	Get the value from the params attribute string.
	//
	getParameter : function(parameter, parameterString) {
		if (!parameterString) {
			if (this.element.params) {
				var parameterString = this.element.params;
			} else {
				return;
			}
		}
		var parameterValue;
        var parameterPair = parameterString.split(',');
        var compareString = parameter+'=';
        var compareStringLength = compareString.length;
        for (var i = 0; i < parameterPair.length; i++) {
        	if (parameterPair[i].substr(0, compareStringLength) == compareString) {
            	var tmp = parameterPair[i].split('=');
                parameterValue = tmp[1];
                break;
            }
        }
		if (!parameterValue) {
			return false;
        } else {
        	return unescape(parameterValue);
    	}
	},
	//
	//	Get the domain from a string.
	//
	getDomain : function(url) {
        var leadSlashes = url.indexOf('//');
        var domainStart = leadSlashes+2;
        var withoutResource = url.substring(domainStart, url.length);
        var nextSlash = withoutResource.indexOf('/');
        var domain = withoutResource.substring(0, nextSlash);
		if (domain.indexOf(':') > -1){
			var portColon = domain.indexOf(':');
			domain = domain.substring(0, portColon);
       	}
		return domain;
    },
	//
	//	Get the type of file.
	//
	fileType : function(url) {

		var image = new RegExp("[^\.]\.("+this.options.fileTypes.image.join('|')+")\s*$", "i");
		if (image.test(url)) return 'image';

		if (url.indexOf('#') > -1 && (document.domain == this.getDomain(url))) return 'inline';
		if (url.indexOf('?') > -1) url = url.substring(0, url.indexOf('?'));

		var type = 'unknown';
		var page = new RegExp("[^\.]\.("+this.options.fileTypes.page.join('|')+")\s*$", "i");
		var media = new RegExp("[^\.]\.("+this.options.fileTypes.media.join('|')+")\s*$", "i");

		if (document.domain != this.getDomain(url)) type = 'external';
	  	if (media.test(url)) type = 'media';

		if (type == 'external' || type == 'media') return type;

	  	if (page.test(url) || url.substr((url.length-1), url.length) == '/') type = 'page';

		return type;
	},
	//
	//  Get file Extension
	//
	fileExtension : function(url) {
		if (url.indexOf('?') > -1) url = url.substring(0, url.indexOf('?'));
		var extenstion = '';
		for (var x = (url.length-1); x > -1; x--) {
			if (url.charAt(x) == '.') {
				return extenstion;
			}
			extenstion = url.charAt(x)+extenstion;
		}
	},
	//
	//	Monitor the keyboard while this lightWindow is up
	//
	monitorKeyboard : function(status) {
		if (status) document.onkeydown = this.eventKeypress.bind(this);
		else document.onkeydown = '';
	},
	//
	//  Perform keyboard actions
	//
	eventKeypress : function(e) {

		if (e == null) var keycode = event.keyCode;
		else var keycode = e.which;

		switch (keycode) {
			case 27:
				this.deactivate();
				break;

			case 13:
				return;

			default:
				break;
		}

		// Gotta stop those quick fingers
		if (this.animating || !this.galleryToggle) return;

		switch (String.fromCharCode(keycode).toLowerCase()) {
			case 'p':
				this.galleryDirection = -1;
				this.changeImage();
				break;

			case 'n':
				this.galleryDirection = 1;
				this.changeImage();
				break;

			default:
				break;
		}
	},
	//
	//	Make the Data Box for the Window
	//
	showData : function() {
		if (this.galleryToggle) $LW('lightWindow-photo-galleries').style.display = 'block';
		this.setupDataDimensions();
		this.setupDimensions(false);
		if (this.showDataToggle) {
			var showDatabox = new lwEffect.Parallel(
				[new lwEffect.SlideDown( 'lightWindow-data', {sync: true, duration: this.duration+1.0, from: 0.0, to: 1.0}),
			 	new lwEffect.Appear('lightWindow-data', {sync: true, duration: 1.0}) ],
				{duration: 0.65, afterFinish: this.setStatus.bind(this, false), queue: {position: 'end', scope: 'lightWindowAnimation'} }
			);
		} else {
			 this.setStatus(false);
		}
	},
	//
	//	Insert Data into Window
	//
	insertData : function() {
		if (this.element.title) {
			if (this.showTitleToggle) $LW('lightWindow-title-bar-title').innerHTML = this.element.title;
			else $LW('lightWindow-data-title').innerHTML = this.element.title;
		}
		if (this.element.caption) $LW('lightWindow-data-caption').innerHTML = this.element.caption;
		if (this.element.author) $LW('lightWindow-data-author').innerHTML = this.options.authorLead+this.element.author;
	},
	//
	//	Reset the scroll.
	//
	getGalleryInfo : function(rel) {
		if (rel.indexOf('[') > -1) {
			return new Array(escape(rel.substring(0, rel.indexOf('['))), escape(rel.substring(rel.indexOf('[')+1, rel.indexOf(']'))));
		} else {
			return false;
		}
	},
	//
	//	Choose a gallery/category
	//
	getGallery : function() {
		var isBadBrowser = this.checkBrowser('msie 6');
		if (!$LW('lightWindow-photo-galleries').style.height || parseInt($LW('lightWindow-photo-galleries').style.height) == this.options.galleryTab.height) {
			if (isBadBrowser) {
				var gallerySize = 100;
			} else {
				var gallerySize = ((parseInt($LW('lightWindow-contents').style.height)*0.95)/this.options.galleryTab.height)*100;
			}

			$LW('lightWindow-photo-galleries-list').setStyle({
				height : (parseInt($LW('lightWindow-contents').style.height)*0.95)-this.options.galleryTab.height+'px'
			});

			// Get out Galleries from the imageArray
			$LW('lightWindow-photo-galleries-list').innerHTML = '';
			var output = '';
			for (i in this.imageArray) {
				if (typeof this.imageArray[i] == 'object') {
					output += '<div class="lightWindow-photo-gallery-listing"><h1>'+unescape(i)+'</h1><ul>';
					for (j in this.imageArray[i]) {
						if (typeof this.imageArray[i][j] == 'object') {
							if (this.imageArray[i][j][0][5]) showImages = ',lWShowImages='+this.getParameter('lWShowImages', this.imageArray[i][j][0][5]);
							else showImages = '';
							output += '<li><a href="#" params="lWGallery='+escape(i)+',lWCategory='+escape(j)+''+showImages+'" class="'+this.options.classNames.action+'" rel="reloadGallery" >'+unescape(j)+'</a></li>';
						}
					}
					output += '</ul></div>';
				}
			}
			new Insertion.Top('lightWindow-photo-galleries-list', output);
			this.actions('.lightWindow-photo-gallery-listing');

			// IE CSS support sucks and I cannot scale from the bottom....
			if (isBadBrowser) {
				$LW('lightWindow-photo-galleries').setStyle({
					height : (parseInt($LW('lightWindow-contents').style.height)*0.95)+'px',
					bottom : '0px'
				});
				$LW('lightWindow-photo-galleries-tab').className = 'down';
			} else {
				var showGalleries = new lwEffect.CushionScale('lightWindow-photo-galleries', gallerySize, {duration: this.duration, afterFinish: function(){$LW('lightWindow-photo-galleries-list').style.overflow = 'auto'; $LW('lightWindow-photo-galleries-tab').className = 'down';}, scaleX: false, scaleY: true, scaleContent: false, scaleFromCenter: false, queue: {position: 'end', scope: 'lightWindowAnimation'}});
			}
		} else {
			if (isBadBrowser) {
				var bottom = -(parseInt($LW('lightWindow-contents').style.height)*0.95)+this.options.galleryTab.height;
			} else {
				var bottom = 0;
			}

			$LW('lightWindow-photo-galleries').setStyle({
				height : this.options.galleryTab.height+'px',
				bottom : bottom+'px',
				top : ''
			});
			$LW('lightWindow-photo-galleries-list').setStyle({
				overflow : 'hidden'
			});
			$LW('lightWindow-photo-galleries-tab').className = 'up';
		}
	},
	//
	//	Set the gallery up.
	//
	setupGallery : function(gallery, start)
	{
		var lwc = $LW('lightWindow-photo-container');

		if (!(images = parseInt(this.getParameter('lWShowImages')))) images = 1;

		for (var x = 0; x < this.imageArray[gallery[0]][gallery[1]].length; x++) {
			if (this.imageArray[gallery[0]][gallery[1]][x][0] == this.contentToFetch) break;
		}

		this.activeImage = x;
		this.activeGallery = gallery;

		var lwn = document.createElement("div");
		lwn.setAttribute('id','lightWindow-navigation');
		lwc.appendChild(lwn);

		if (x != 0 && this.imageArray[gallery[0]][gallery[1]][x-images]) {
			var lwnp = document.createElement("a");
			lwnp.setAttribute('id','lightWindow-previous');
			lwnp.setAttribute('href','#');
			lwn.appendChild(lwnp);
			Event.observe(lwnp, 'click', this.changeImage.bindAsEventListener(this, this.imageArray[gallery[0]][gallery[1]][x-images][0], this.imageArray[gallery[0]][gallery[1]][x-images][1], this.imageArray[gallery[0]][gallery[1]][x-images][2], this.imageArray[gallery[0]][gallery[1]][x-images][3], this.imageArray[gallery[0]][gallery[1]][x-images][4]));
			lwnp.onclick = function(){return false;};
		}
		if ((x+1) < this.imageArray[gallery[0]][gallery[1]].length && this.imageArray[gallery[0]][gallery[1]][x+images]) {
			var lwnn = document.createElement("a");
			lwnn.setAttribute('id','lightWindow-next');
			lwnn.setAttribute('href','#');
			lwn.appendChild(lwnn);
			Event.observe(lwnn, 'click', this.changeImage.bindAsEventListener(this, this.imageArray[gallery[0]][gallery[1]][x+images][0], this.imageArray[gallery[0]][gallery[1]][x+images][1], this.imageArray[gallery[0]][gallery[1]][x+images][2], this.imageArray[gallery[0]][gallery[1]][x+images][3], this.imageArray[gallery[0]][gallery[1]][x+images][4]));
			lwnn.onclick = function(){return false;};
		}
		if (images == 1) $LW('lightWindow-data-image').innerHTML = 'Image '+(x+1)+' of '+this.imageArray[gallery[0]][gallery[1]].length;
		this.addGalleryWindowMarkup();
	},
	//
	//	Get the contents for the window
	//
	loadInfo : function() {
		var showLoadingOptions = new lwEffect.Appear('lightWindow-loading-options', {delay: this.options.loadingDialog.delay, duration: this.duration, queue: {position: 'front', scope: 'lightWindowAnimation-loading'}});
		switch (this.windowType) {
			case 'image' :
				this.preloadImage = new Array();
				if (!$LW('lightWindow-photo-container')) {
					this.addPhotoWindowMarkup();
					this.addDataWindowMarkup();
					this.addGalleryWindowMarkup();
				}
				var totalWidth = 0;
				var totalHeight = 0;
				var gallery = this.getGalleryInfo(this.element.rel);
				if (images = parseInt(this.getParameter('lWShowImages'))) {
					for (var z = 0; z < this.imageArray[gallery[0]][gallery[1]].length; z++) {
						if (this.imageArray[gallery[0]][gallery[1]][z][0] == this.contentToFetch) break;
					}
					$LW('lightWindow-photo-container').style.display = 'none';
					this.loading = images-1;
					for (var x = 0; x < images; x++) {
						if (this.imageArray[gallery[0]][gallery[1]][x+z]) {
							this.preloadImage[x] = new Image();
							this.preloadImage[x].onload=function(){
								if ($LW('lightWindow-photo-container').style.display != 'block') {
									for (var t = 0; t <= x; t++) {
										if (this.preloadImage[t] && (this.preloadImage[t].width != 0 && this.preloadImage[t].height != 0)) {
											totalWidth = totalWidth+this.preloadImage[t].width;
											totalHeight = this.preloadImage[t].height;
											this.preloadImage.splice(t, 1);
											this.loading--;
										}
									}
									if (this.loading < 0) {
										$LW('lightWindow-photo-container').setStyle({
											display : 'block'
										});
										$LW('lightWindow-photo-sizer').setStyle({
											width : totalWidth+'px',
											height : totalHeight+'px'
										});
										this.processInfo();
									}
								}
							}.bind(this, x);
							this.preloadImage[x].src = $LW('lightWindow-photo-'+x).src = this.imageArray[gallery[0]][gallery[1]][x+z][0];
						}
					}
					this.activeImage = this.activeImage+x-1;
					if (this.galleryToggle) this.setupGallery(this.getGalleryInfo(this.element.rel));
				} else {
					this.preloadImage[0] = new Image();
					this.preloadImage[0].onload=function(){
						totalWidth = this.preloadImage[0].width;
						totalHeight = this.preloadImage[0].height;
						$LW('lightWindow-photo-container').setStyle({
							display : 'block'
						});
						$LW('lightWindow-photo-sizer').setStyle({
							width : totalWidth+'px',
							height : totalHeight+'px'
						});
						this.processInfo();
					}.bind(this);
					this.preloadImage[0].src = $LW('lightWindow-photo-0').src = this.contentToFetch;
					if (this.galleryToggle) this.setupGallery(this.getGalleryInfo(this.element.rel));
				}
				break;

			case 'media' :
				// We load the info in loadFinish so that the iframe will be properly sixe and set in our favorite browser... Safari-crap
				this.processInfo();
				break;

			case 'external' :
				var lwi = '<iframe id="lightWindow-iframe" name="lightWindow-iframe" height="100%" width="100%" frameborder="0" scrolling="auto"></iframe>';
				new Insertion.Top($LW('lightWindow-contents'), lwi);
				parent.$LW('lightWindow-iframe').style.visibility = 'hidden';
				this.processInfo();
				break;

			case 'page' :
				var newAJAX = new Ajax.Request(
        			this.contentToFetch,
        			{method: 'get', parameters: '', onComplete: this.processInfo.bind(this)}
				);
				break;

			case 'inline' :
				var content = this.contentToFetch;
				if (content.indexOf('?') > -1) {
					content = content.substring(0, content.indexOf('?'));
				}
				content = content.substring(content.indexOf('#')+1);
				new Insertion.Top($LW('lightWindow-contents-container'), $LW(content).innerHTML);
				this.toggleTroubleElements('hidden', true);
				this.processInfo();
				break;

			default :
				throw('Page Type could not be determined, please amend this lightWindow URL '+this.contentToFetch);
				break;
			}
	},
	//
	//	Finish the loading process and clean up.
	//
	loadFinish : function() {
		this.actions();
		this.insertData(false);
		switch (this.windowType) {
			case 'page' :
				var hideLoading = new lwEffect.Fade('lightWindow-loading', {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: 'end', scope: 'lightWindowAnimation'}});
				break;

			case 'image' :
				var hideLoading = new lwEffect.Fade('lightWindow-loading', {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: 'end', scope: 'lightWindowAnimation'}});
				break;

			case 'media' :
				// We load the info in loadFinish so that the iframe will be properly sixe and set in our favorite browser... Safari-crap
				var lwi = '<iframe id="lightWindow-iframe" name="lightWindow-iframe" height="100%" width="100%" frameborder="0" scrolling="no" ></iframe>';
				new Insertion.Top($LW('lightWindow-contents'), lwi);
				iframeContent = '<html><head><style type="text/css">*, html, body{ margin: 0px; padding: 0px;}</style></head><body><embed type="'+this.options.mimeTypes[this.fileExtension(this.contentToFetch)]+'" src="'+this.contentToFetch+'" width="100%" height="100%" name="lightWindow-media" id="lightWindow-media" quality="high" wmode="opaque" /></body></html>';
				if (parent.$LW('lightWindow-iframe').contentWindow){
					parent.$LW('lightWindow-iframe').contentWindow.document.open();
					parent.$LW('lightWindow-iframe').contentWindow.document.write(iframeContent);
					parent.$LW('lightWindow-iframe').contentWindow.document.close();
				} else {
					parent.$LW('lightWindow-iframe').contentDocument.open();
					parent.$LW('lightWindow-iframe').contentDocument.write(iframeContent);
					parent.$LW('lightWindow-iframe').contentDocument.close();
				}
				var hideLoading = new lwEffect.Fade('lightWindow-loading', {duration: 0, afterFinish: this.windowAdjust.bind(this), queue: {position: 'end', scope: 'lightWindowAnimation'}});
				break;

			case 'external' :
				parent.$LW('lightWindow-iframe').src = this.contentToFetch;
				var hideLoading = new lwEffect.Fade('lightWindow-loading', {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: 'end', scope: 'lightWindowAnimation'}});
				break;

			case 'inline' :
				var hideLoading = new lwEffect.Fade('lightWindow-loading', {duration: this.duration, afterFinish: this.windowAdjust.bind(this), queue: {position: 'end', scope: 'lightWindowAnimation'}});
				break;

			default :
				break;
		}
	},
	//
	//  Adjust the Window and add the data box if it needs it
	//
	windowAdjust : function() {
		if (this.windowType == 'external' || this.windowType == 'media') {
			// No I don't like this but it works with a small flicker, FF for the Mac is a little more buggy than I would have thought
			// Of Note this is really for the quicktime samples as far as I can tell....
			if (this.checkBrowser('firefox')) {
				if ($LW('overlay').style.height == '100%' || !$LW('overlay').style.height) $LW('overlay').style.height = '101%';
				else $LW('overlay').style.height = '100%';
			}
			parent.$LW('lightWindow-iframe').style.visibility = 'visible';
		}
		$LW('lightWindow-contents').style.overflow = this.boxOverFlow;
		this.toggleTroubleElements('visible', true);
		if (this.showDataToggle || this.showTitleToggle) {
			this.showData();
		}
	},
	//
	//	Get the content into the window and show it off.
	//
	processInfo : function(response) {
		if(this.checkBrowser('msie')) {
            var windowHeight = document.documentElement.clientHeight;
            var windowWidth = document.documentElement.clientWidth;
        } else {
            var windowHeight = window.innerHeight;
            var windowWidth = window.innerWidth;
        }

		// What if the window size is ridiculously small? If so we need some overrides to make it fit and make it usable (even on set dimensions)
		if (this.showDataToggle) var dataWindow = this.options.dimensions.dataHeight;
		else var dataWindow = 0;
		// Set the title height for the bar
		if (this.options.showTitleBar) titleHeight = this.options.dimensions.titleHeight;
		else titleHeight = 0;
		var lWcWidth = parseInt($LW('lightWindow-contents').style.width);
		var lWcHeight = parseInt($LW('lightWindow-contents').style.height);
		var availableHeight = windowHeight-dataWindow-2*this.options.cushion-titleHeight;
		var availableWidth = windowWidth-2*this.options.cushion;
      	var boxWidth, boxScrollWidth, boxHeight, boxScrollHeight, scaleX, scaleY;
		var totalHeight = 0;
		var totalWidth = 0;
		switch (this.windowType) {
			case 'image' :
				if (!(images = parseInt(this.getParameter('lWShowImages')))) images = 1;
				boxWidth = $LW('lightWindow-contents').offsetWidth;
				boxHeight = $LW('lightWindow-contents').offsetHeight;
				if ($LW('lightWindow-photo-0').height > availableHeight) {
					var totalWidth = 0;
					for (var x = 0; x < images; x++) {
						$LW('lightWindow-photo-'+x).height = availableHeight;
						totalWidth = totalWidth+$LW('lightWindow-photo-'+x).width;
					}
					if (images > 1) totalWidth++; // This is needed for putting images side by side when we resize the iamge only
					boxScrollHeight = availableHeight;
					boxScrollWidth = totalWidth;
					$LW('lightWindow-photo-sizer').style.height = availableHeight+'px';
					$LW('lightWindow-photo-sizer').style.width = totalWidth+'px';
				} else {
					boxScrollHeight = parseInt($LW('lightWindow-photo-sizer').style.height);
					boxScrollWidth = parseInt($LW('lightWindow-photo-sizer').style.width);
				}
				break;

			case 'external' :
		    	boxWidth = $LW('lightWindow-contents').offsetWidth;
				boxHeight = $LW('lightWindow-contents').offsetHeight;
				break;

			case 'media' :
			    boxWidth = $LW('lightWindow-contents').offsetWidth;
				boxHeight = $LW('lightWindow-contents').offsetHeight;
				break;

			case 'page' :
				new Insertion.Top($LW('lightWindow-contents-container'), response.responseText);
				this.toggleTroubleElements('hidden', true);
				boxWidth = $LW('lightWindow-contents').offsetWidth;
				boxScrollWidth = $LW('lightWindow-contents').scrollWidth;
				boxHeight = $LW('lightWindow-contents').offsetHeight;
				boxScrollHeight = $LW('lightWindow-contents').scrollHeight;
				break;

			case 'inline' :
				boxWidth = $LW('lightWindow-contents').offsetWidth;
				boxScrollWidth = $LW('lightWindow-contents').scrollWidth;
				boxHeight = $LW('lightWindow-contents').offsetHeight;
				boxScrollHeight = $LW('lightWindow-contents').scrollHeight+3;
				break;

			default :
				break;

		}

		// Were dimensions set?
		// This also resizes to fit the window, for things like flash!
		var ignorelWHeight = false;
      	if (lWWidth = this.getParameter('lWWidth')) {
			boxScrollWidth = parseFloat(lWWidth);
			if (boxScrollWidth > (windowWidth*.95)) {
				tmp = boxScrollWidth;
				boxScrollWidth = 0.90*windowWidth;
				lWHeight = this.getParameter('lWHeight'); // For this case I require a height to be set, why would you set width and not set height?
				boxScrollHeight = parseFloat(lWHeight);
				boxScrollHeight = boxScrollHeight * (boxScrollWidth/tmp)
				ignorelWHeight = true;
			}
		}

		if (lWHeight = this.getParameter('lWHeight')) {
			if (!ignorelWHeight) {
				boxScrollHeight = parseFloat(lWHeight);
				if (boxScrollHeight > (windowHeight*.8)) {
					boxScrollHeight = 0.8*windowHeight;
				}
			}
		}

		if (lWOverflow = this.getParameter('lWOverflow')) this.boxOverFlow = lWOverflow;

		if ((boxScrollHeight < (windowHeight*.8)) && this.windowType != 'external' && this.windowType != 'image') {
			scaleY = parseFloat((boxScrollHeight/boxHeight)*100);
		} else if (this.windowType == 'external' && !lWHeight) {
			scaleY = parseFloat((windowHeight/(1.2*boxHeight))*100);
		} else if (this.windowType == 'external' && lWHeight) {
			scaleY = parseFloat((boxScrollHeight/(boxHeight))*100);
		} else if (this.windowType == 'image' || this.windowType == 'media') {
			scaleY = parseFloat(((boxScrollHeight)/boxHeight)*100);
		} else {
			if (this.windowType != 'media') this.boxOverFlow = 'auto';
			$LW('lightWindow-contents-container').marginRight = '16px';
			scaleY = parseFloat((windowHeight/(1.2*boxHeight))*100);
		}
		if ((boxScrollWidth < (windowWidth*.8)) && this.windowType != 'external' && this.windowType != 'image' && this.windowType != 'media') {
			scaleX = parseFloat(((boxScrollWidth)/boxWidth)*100);
		} else if (this.windowType == 'external' && !lWWidth) {
			scaleX = parseFloat((windowWidth/(1.1*boxWidth))*100);
		} else if (this.windowType == 'external' && lWWidth) {
			scaleX = parseFloat((boxScrollWidth/(boxWidth))*100);
		} else if (this.windowType == 'image' || this.windowType == 'media') {
			scaleX = parseFloat(((boxScrollWidth)/boxWidth)*100);
		} else {
			if (this.windowType != 'media') this.boxOverFlow = 'auto';
			$LW('lightWindow-contents-container').marginRight = '16px';
			scaleX = parseFloat((windowWidth/(1.1*boxWidth))*100);
		}

		this.setStatus(true);
		var doDelay = 0;
		if (scaleX != 100 && lWcWidth != boxScrollWidth) {
			if (scaleY == 100) var doX = new lwEffect.CushionScale('lightWindow-contents', scaleX, {duration: this.duration, scaleX: true, scaleY: false, scaleCushion: {top: this.options.cushion, left: this.options.cushion}, afterFinish: this.loadFinish.bind(this), scaleFromCenter: true, scaleContent: false, queue: {position: 'front', scope: 'lightWindowAnimation'}});
			else var doX = new lwEffect.CushionScale('lightWindow-contents', scaleX, {duration: this.duration, scaleX: true, scaleY: false, scaleCushion: {top: this.options.cushion, left: this.options.cushion}, scaleContent: false, scaleFromCenter: true, queue: {position: 'front', scope: 'lightWindowAnimation'}});
			doDelay = this.duration/2;
		}
		if (scaleY != 100 && lWcHeight != boxScrollHeight) {
			var doY = new lwEffect.CushionScale('lightWindow-contents', scaleY, {duration: this.duration, delay: doDelay, scaleX: false, scaleY: true, scaleCushion: {top: this.options.cushion, left: this.options.cushion}, afterFinish: this.loadFinish.bind(this), scaleContent: false, scaleFromCenter: true, queue: {position: 'end', scope: 'lightWindowAnimation'}});
		}
		if ((!doX && !doY) || (doX && scaleY != 100 && !doY)) this.loadFinish();
	},
	//
	//	Reload the window with another location
	//
	reloadWindow : function(element) {
		lwElement.remove($LW('lightWindow-contents'));
		if ($LW('lightWindow-data')) lwElement.remove($LW('lightWindow-data'));
		this.element = element;
		this.contentToFetch = this.element.href;
		this.addLightWindowMarkup(true);
		this.setupDimensions(true);
		this.displayLightWindow(true);
		this.loadInfo();
	},
	//
	//  Reload the Gallery
	//
	reloadGallery : function(e, link) {
		this.element.params = link.getAttribute('params');
		var gallery = this.getParameter('lWGallery', this.element.params);
		var category = this.getParameter('lWCategory', this.element.paramse);
		this.element.rel = this.imageArray[gallery][category][0][4];
		this.element.title = this.imageArray[gallery][category][0][1];
		this.element.caption = this.imageArray[gallery][category][0][2];
		this.element.author = this.imageArray[gallery][category][0][3];
		this.contentToFetch = this.imageArray[gallery][category][0][0];
		lwElement.remove($LW('lightWindow-photo-container'));
		if ($LW('lightWindow-data')) lwElement.remove($LW('lightWindow-data'));
		if ($LW('lightWindow-title-bar')) $LW('lightWindow-title-bar').style.display = 'none';
		this.galleryToggle = true;
		this.activeGallery[0] = gallery
		this.activeGallery[1] = category;
		this.activeImage = 0;
		// Becuase of IE we have to use either Appear or setOpacity/show
		var showLoading = lwEffect.Appear('lightWindow-loading', {duration: 0, afterFinish: this.loadInfo.bind(this)});
	},
	//
	//	Change the Image
	//
	changeImage : function(e) {
		var queue = lwEffect.Queues.get('lightWindowAnimation').each(function(e) {e.cancel();});
	  	var data = $LWA(arguments);
	  	data.shift();
		if (data != '') {
			this.contentToFetch = data[0];
			this.element.title = data[1];
			this.element.caption = data[2];
			this.element.author = data[3];
			this.element.rel = data[4];
		} else {
			if (!(images = parseInt(this.getParameter('lWShowImages')))) images = 1;
			if ((this.galleryDirection < 0 && (this.activeImage-1*images) < 0) || (this.galleryDirection > 0 && (this.activeImage+1*images) >= this.imageArray[this.activeGallery[0]][this.activeGallery[1]].length)) return false;
			this.element.title = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][1];
			this.element.caption = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][2];
			this.element.author = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][3];
			this.element.params = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][0][5];
			this.element.rel = unescape(this.activeGallery[0]+'['+this.activeGallery[1]+']');
			this.contentToFetch = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+this.galleryDirection*images][0];
			this.activeImage = this.activeImage+this.galleryDirection*images;
		}
		// Preload the previous and next images
		if ((this.activeImage-1) >= 0) {
			var preloadNextImage = new Image();
			preloadNextImage.src = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage-1][0];
		}
		if ((this.activeImage+1) < this.imageArray[this.activeGallery[0]][this.activeGallery[1]].length) {
			var preloadPrevImage = new Image();
			preloadPrevImage.src = this.imageArray[this.activeGallery[0]][this.activeGallery[1]][this.activeImage+1][0];
		}
		lwElement.remove($LW('lightWindow-photo-container'));
		if ($LW('lightWindow-data')) lwElement.remove($LW('lightWindow-data'));
		if ($LW('lightWindow-title-bar')) $LW('lightWindow-title-bar').style.visibility = 'hidden';
		this.galleryToggle = true;
		$LW('lightWindow-loading-options').style.display = 'none';
		// Becuase of IE we have to use either Appear or setOpacity/show
		var showLoading = lwEffect.Appear('lightWindow-loading', {duration: 0, afterFinish: this.loadInfo.bind(this)});
	},
	//
	//	Submit a form to another lightWindow
	//
	insertForm : function(e) {
		var element = Event.element(e).parentNode;
		var parameterString = Form.serialize(this.getParameter('lWForm', element.getAttribute('params')));
		if (this.options.formMethod == 'post') {
			var newAJAX = new Ajax.Request(
			    element.href,
			    {method: 'post', postBody: parameterString, onComplete: this.reloadWindow.bind(this, element)}
			);
		} else if (this.options.formMethod == 'get') {
			var newAJAX = new Ajax.Request(
			    element.href,
			    {method: 'get', parameters: parameterString, onComplete: this.reloadWindow.bind(this, element)}
			);
		}
	}
}

/*-----------------------------------------------------------------------------------------------*/

Event.observe(window, 'load', lightWindowInit, false);

//
//	Set up all of our links
//
var mylightWindow = null;
function lightWindowInit() {
	mylightWindow = new lightWindow();
}


/*-----------------------------------------------------------------------------------------------
	Problem:
		This effect does not take into account padding or a border on an element, especially an
		absolutely position element.

	Added:
		Options:
			scaleCushion: 0	// or {top, left} with provided values

			Example:
				scaleCushion: {top: 10, left: 10}

		Code:
			To setDimensions: function(height, width)

				Original:
		    		if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
	        		if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';

				New:
			    	if(this.options.scaleCushion == 'none') {
		        		if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
		        		if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
					} else {
			        	if(this.options.scaleY) d.top = (this.originalTop-topd-this.options.scaleCushion.top-this.options.scaleCushion.bottom) + 'px';
			        	if(this.options.scaleX) d.left = (this.originalLeft-leftd-this.options.scaleCushion.right-this.options.scaleCushion.left) + 'px';
					}

	Credit: Kevin P Miller http://www.stickmanlabs.com
-----------------------------------------------------------------------------------------------*/

lwEffect.CushionScale = Class.create();
Object.extend(Object.extend(lwEffect.CushionScale.prototype, lwEffect.Base.prototype), {
  initialize: function(element, percent) {
    this.element = $LW(element);
    if(!this.element) throw(lwEffect._elementDoesNotExistError);
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
      scaleFrom: 100.0,
      scaleTo: percent,
	  scaleCushion: 'none'	   // 'none' or {} with provided values
    }, arguments[2] || {});
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle('position');

    this.originalStyle = {};
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));

    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;

    var fontSize = this.element.getStyle('font-size') || '100%';
    ['em','px','%','pt'].each( function(fontSizeType) {
      if(fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));

    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;

    this.dims = null;
    if(this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if(this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = {};
	if(this.options.scaleX) d.width = width + 'px';
	if(this.options.scaleY) d.height = height + 'px';
	if(this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if(this.elementPositioning == 'absolute') {
	    if(this.options.scaleCushion == 'none') {
        	if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
        	if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
		} else {
        	if(this.options.scaleY) d.top = (this.originalTop-topd-this.options.scaleCushion.top) + 'px';
        	if(this.options.scaleX) d.left = (this.originalLeft-leftd-this.options.scaleCushion.left) + 'px';
		}
      } else {
        if(this.options.scaleY) d.top = -topd + 'px';
        if(this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    this.element.setStyle(d);
  }
});

