/*  Prototype JavaScript framework, version 1.5.0_rc0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.5.0_rc0',
  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.inspect = function(object) {
  try {
    if (object == undefined) return 'undefined';
    if (object == null) return 'null';
    return object.inspect ? object.inspect() : object.toString();
  } catch (e) {
    if (e instanceof RangeError) return '...';
    throw e;
  }
}

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this;
  return function(event) {
    return __method.call(object, event || window.event);
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    var digits = this.toString(16);
    if (this < 16) return '0' + digits;
    return digits;
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  }
});

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}
Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += (replacement(match) || '').toString();
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return this;
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : this;
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  },

  toQueryParams: function() {
    var pairs = this.match(/^\??(.*)$/)[1].split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair = pairString.split('=');
      params[pair[0]] = pair[1];
      return params;
    });
  },

  toArray: function() {
    return this.split('');
  },

  camelize: function() {
    var oStringList = this.split('-');
    if (oStringList.length == 1) return oStringList[0];

    var camelizedString = this.indexOf('-') == 0
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
      : oStringList[0];

    for (var i = 1, len = oStringList.length; i < len; i++) {
      var s = oStringList[i];
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }

    return camelizedString;
  },

  inspect: function() {
    return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'";
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (typeof replacement == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
}

String.prototype.parseQuery = String.prototype.toQueryParams;

var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    return this.template.gsub(this.pattern, function(match) {
      var before = match[1];
      if (before == '\\') return match[2];
      return before + (object[match[3]] || '').toString();
    });
  }
}

var $break    = new Object();
var $continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        try {
          iterator(value, index++);
        } catch (e) {
          if (e != $continue) throw e;
        }
      });
    } catch (e) {
      if (e != $break) throw e;
    }
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push(iterator(value, index));
    });
    return results;
  },

  detect: function (iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },

  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.collect(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator) {
    return this.collect(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.collect(Prototype.K);
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0; i < iterable.length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0; i < this.length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != undefined || value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value && value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0; i < this.length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});
var Hash = {
  _each: function(iterator) {
    for (var key in this) {
      var value = this[key];
      if (typeof value == 'function') continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $H(hash).inject($H(this), function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  toQueryString: function() {
    return this.map(function(pair) {
      return pair.map(encodeURIComponent).join('=');
    }).join('&');
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  }
}

function $H(object) {
  var hash = Object.extend({}, object || {});
  Object.extend(hash, Enumerable);
  Object.extend(hash, Hash);
  return hash;
}
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    do {
      iterator(value);
      value = value.succ();
    } while (this.include(value));
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new 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 += '&_=';

    try {
      this.url = url;
      if (this.options.method == 'get' && parameters.length > 0)
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method, this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
      }

      //this.setRequestHeaders();

      //var body = this.options.postBody ? this.options.postBody : parameters;
      //this.transport.send(this.options.method == 'post' ? body : null);

    } catch (e) {
      this.dispatchException(e);
    }
  },

  setRequestHeaders: function() {
    var requestHeaders =
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', Prototype.Version,
       'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type', this.options.contentType);

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  header: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) {}
  },

  evalJSON: function() {
    try {
      return eval('(' + this.header('X-JSON') + ')');
    } catch (e) {}
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (event == 'Complete') {
      try {
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + event, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.containers = {
      success: container.success ? $(container.success) : $(container),
      failure: container.failure ? $(container.failure) :
        (container.success ? null : $(container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, object) {
      this.updateContent();
      onComplete(transport, object);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.responseIsSuccess() ?
      this.containers.success : this.containers.failure;
    var response = this.transport.responseText;

    if (!this.options.evalScripts)
      response = response.stripScripts();

    if (receiver) {
      if (this.options.insertion) {
        new this.options.insertion(receiver, response);
      } else {
        Element.update(receiver, response);
      }
    }

    if (this.responseIsSuccess()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $() {
  var results = [], element;
  for (var i = 0; i < arguments.length; i++) {
    element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);
    results.push(Element.extend(element));
  }
  return results.length < 2 ? results[0] : results;
}

document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  return $A(children).inject([], function(elements, child) {
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      elements.push(Element.extend(child));
    return elements;
  });
}

/*--------------------------------------------------------------------------*/

if (!window.Element)
  var Element = new Object();

Element.extend = function(element) {
  if (!element) return;
  if (_nativeExtensions) return element;

  if (!element._extended && element.tagName && element != window) {
    var methods = Element.Methods, cache = Element.extend.cache;
    for (property in methods) {
      var value = methods[property];
      if (typeof value == 'function')
        element[property] = cache.findOrStore(value);
    }
  }

  element._extended = true;
  return element;
}

Element.extend.cache = {
  findOrStore: function(value) {
    return this[value] = this[value] || function() {
      return value.apply(null, [this].concat($A(arguments)));
    }
  }
}

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      if (element != "undefined") {
        Element[Element.visible(element) ? 'hide' : 'show'](element);
      }
    }
  },

  hide: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      if (element != "undefined") {
        element.style.display = 'none';
      }
    }
  },

  show: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = '';
    }
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
  },

  update: function(element, html) {
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
  },

  replace: function(element, html) {
    element = $(element);
    if (element.outerHTML) {
      element.outerHTML = html.stripScripts();
    } else {
      var range = element.ownerDocument.createRange();
      range.selectNodeContents(element);
      element.parentNode.replaceChild(
        range.createContextualFragment(html.stripScripts()), element);
    }
    setTimeout(function() {html.evalScripts()}, 10);
  },

  getHeight: function(element) {
    element = $(element);
    return element.offsetHeight;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).include(className);
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).add(className);
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).remove(className);
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    for (var i = 0; i < element.childNodes.length; i++) {
      var node = element.childNodes[i];
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        Element.remove(node);
    }
  },

  empty: function(element) {
    return $(element).innerHTML.match(/^\s*$/);
  },

  childOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var x = element.x ? element.x : element.offsetLeft,
        y = element.y ? element.y : element.offsetTop;
    window.scrollTo(x, y);
  },

  getStyle: function(element, style) {
    element = $(element);
    var value = element.style[style.camelize()];
    if (!value) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        var css = document.defaultView.getComputedStyle(element, null);
        value = css ? css.getPropertyValue(style) : null;
      } else if (element.currentStyle) {
        value = element.currentStyle[style.camelize()];
      }
    }

    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
      if (Element.getStyle(element, 'position') == 'static') value = 'auto';

    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style) {
    element = $(element);
    for (var name in style)
      element.style[name.camelize()] = style[name];
  },

  getDimensions: function(element) {
    element = $(element);
    if (Element.getStyle(element, 'display') != 'none')
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = '';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = 'none';
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element._overflow = element.style.overflow;
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
  },

  undoClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element.style.overflow = element._overflow;
    element._overflow = undefined;
  }
}

Object.extend(Element, Element.Methods);

var _nativeExtensions = false;

if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  var HTMLElement = {}
  HTMLElement.prototype = document.createElement('div').__proto__;
}

Element.addMethods = function(methods) {
  Object.extend(Element.Methods, methods || {});

  if(typeof HTMLElement != 'undefined') {
    var methods = Element.Methods, cache = Element.extend.cache;
    for (property in methods) {
      var value = methods[property];
      if (typeof value == 'function')
        HTMLElement.prototype[property] = cache.findOrStore(value);
    }
    _nativeExtensions = true;
  }
}

Element.addMethods();

var Toggle = new Object();
Toggle.display = Element.toggle;

/*--------------------------------------------------------------------------*/

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        var tagName = this.element.tagName.toLowerCase();
        if (tagName == 'tbody' || tagName == 'tr') {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set(this.toArray().concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set(this.select(function(className) {
      return className != classNameToRemove;
    }).join(' '));
  },

  toString: function() {
    return this.toArray().join(' ');
  }
}

Object.extend(Element.ClassNames.prototype, Enumerable);
var Selector = Class.create();
Selector.prototype = {
  initialize: function(expression) {
    this.params = {classNames: []};
    this.expression = expression.toString().strip();
    this.parseExpression();
    this.compileMatcher();
  },

  parseExpression: function() {
    function abort(message) { throw 'Parse error in selector: ' + message; }

    if (this.expression == '')  abort('empty expression');

    var params = this.params, expr = this.expression, match, modifier, clause, rest;
    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
      params.attributes = params.attributes || [];
      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
      expr = match[1];
    }

    if (expr == '*') return this.params.wildcard = true;

    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
      modifier = match[1], clause = match[2], rest = match[3];
      switch (modifier) {
        case '#':       params.id = clause; break;
        case '.':       params.classNames.push(clause); break;
        case '':
        case undefined: params.tagName = clause.toUpperCase(); break;
        default:        abort(expr.inspect());
      }
      expr = rest;
    }

    if (expr.length > 0) abort(expr.inspect());
  },

  buildMatchExpression: function() {
    var params = this.params, conditions = [], clause;

    if (params.wildcard)
      conditions.push('true');
    if (clause = params.id)
      conditions.push('element.id == ' + clause.inspect());
    if (clause = params.tagName)
      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
    if ((clause = params.classNames).length > 0)
      for (var i = 0; i < clause.length; i++)
        conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
    if (clause = params.attributes) {
      clause.each(function(attribute) {
        var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
        var splitValueBy = function(delimiter) {
          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
        }

        switch (attribute.operator) {
          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
          case '|=':      conditions.push(
                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
                          ); break;
          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
          case '':
          case undefined: conditions.push(value + ' != null'); break;
          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
        }
      });
    }

    return conditions.join(' && ');
  },

  compileMatcher: function() {
    this.match = new Function('element', 'if (!element.tagName) return false; \
      return ' + this.buildMatchExpression());
  },

  findElements: function(scope) {
    var element;

    if (element = $(this.params.id))
      if (this.match(element))
        if (!scope || Element.childOf(element, scope))
          return [element];

    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');

    var results = [];
    for (var i = 0; i < scope.length; i++)
      if (this.match(element = scope[i]))
        results.push(Element.extend(element));

    return results;
  },

  toString: function() {
    return this.expression;
  }
}

function $$() {
  return $A(arguments).map(function(expression) {
    return expression.strip().split(/\s+/).inject([null], function(results, expr) {
      var selector = new Selector(expr);
      return results.map(selector.findElements.bind(selector)).flatten();
    });
  }).flatten();
}
var Field = {
  clear: function() {
    for (var i = 0; i < arguments.length; i++)
      $(arguments[i]).value = '';
  },

  focus: function(element) {
    $(element).focus();
  },

  present: function() {
    for (var i = 0; i < arguments.length; i++)
      if ($(arguments[i]).value == '') return false;
    return true;
  },

  select: function(element) {
    $(element).select();
  },

  activate: function(element) {
    element = $(element);
    element.focus();
    if (element.select)
      element.select();
  }
}

/*--------------------------------------------------------------------------*/

var Form = {
  serialize: function(form) {
    var elements = Form.getElements($(form));
    var queryComponents = new Array();

    for (var i = 0; i < elements.length; i++) {
      var queryComponent = Form.Element.serialize(elements[i]);
      if (queryComponent)
        queryComponents.push(queryComponent);
    }

    return queryComponents.join('&');
  },

  getElements: function(form) {
    form = $(form);
    var elements = new Array();

    for (var tagName in Form.Element.Serializers) {
      var tagElements = form.getElementsByTagName(tagName);
      for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
    }
    return elements;
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name)
      return inputs;

    var matchingInputs = new Array();
    for (var i = 0; i < inputs.length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) ||
          (name && input.name != name))
        continue;
      matchingInputs.push(input);
    }

    return matchingInputs;
  },

  disable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.blur();
      element.disabled = 'true';
    }
  },

  enable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.disabled = '';
    }
  },

  findFirstElement: function(form) {
    return Form.getElements(form).find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    Field.activate(Form.findFirstElement(form));
  },

  reset: function(form) {
    $(form).reset();
  }
}

Form.Element = {
  serialize: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter) {
      var key = encodeURIComponent(parameter[0]);
      if (key.length == 0) return;

      if (parameter[1].constructor != Array)
        parameter[1] = [parameter[1]];

      return parameter[1].map(function(value) {
        return key + '=' + encodeURIComponent(value);
      }).join('&');
    }
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter)
      return parameter[1];
  }
}

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'submit':
      case 'hidden':
      case 'password':
      case 'text':
        return Form.Element.Serializers.textarea(element);
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
    }
    return false;
  },

  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },

  textarea: function(element) {
    return [element.name, element.value];
  },

  select: function(element) {
    return Form.Element.Serializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = element.options[index];
      value = opt.value || opt.text;
    }
    return [element.name, value];
  },

  selectMany: function(element) {
    var value = [];
    for (var i = 0; i < element.length; i++) {
      var opt = element.options[i];
      if (opt.selected)
        value.push(opt.value || opt.text);
    }
    return [element.name, value];
  }
}

/*--------------------------------------------------------------------------*/

var $F = Form.Element.getValue;

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;

    this.lastValue = this.getValue();
    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    var elements = Form.getElements(this.element);
    for (var i = 0; i < elements.length; i++)
      this.registerCallback(elements[i]);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        case 'password':
        case 'text':
        case 'textarea':
        case 'select-one':
        case 'select-multiple':
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,

  element: function(event) {
    return event.target || event.srcElement;
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0; i < Event.observers.length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.attachEvent))
      name = 'keydown';

    this._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.detachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      element.detachEvent('on' + name, observer);
    }
  }
});

/* prevent memory leaks in IE */
if (navigator.appVersion.match(/\bMSIE\b/))
  Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  clone: function(source, target) {
    source = $(source);
    target = $(target);
    target.style.position = 'absolute';
    var offsets = this.cumulativeOffset(source);
    target.style.top    = offsets[1] + 'px';
    target.style.left   = offsets[0] + 'px';
    target.style.width  = source.offsetWidth + 'px';
    target.style.height = source.offsetHeight + 'px';
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent==document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      valueT -= element.scrollTop  || 0;
      valueL -= element.scrollLeft || 0;
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';;
    element.style.left   = left + 'px';;
    element.style.width  = width + 'px';;
    element.style.height = height + 'px';;
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}


/////////////////////////////////

function N2EventManager()
{
    this.aEvents = {};
    
    // 1) Register a widget to be notified when any event in the
    // given list is published.
    // ARGS: oWidget a ref to a widget
    //       aMessages a ref to an array of events to subscribe to
    this.subscribe = function(oWidget, aEvents)
    {
        var i;
        for (i = 0; i< aEvents.length; i++)
        {
            var sEvent = aEvents[i];
            var aWidgets = this.aEvents[sEvent];
            if (!aWidgets)
            {
                aWidgets = this.aEvents[sEvent] = [];
            }
            // Push widget onto array
            aWidgets.push(oWidget);
        }
    };

	this.unsubscribe = function(oWidget)
    {
        for (var i in this.aEvents)
        {
            var aWidgets = this.aEvents[i];
            // Push widget onto array
			for (a = 0; a< aWidgets.length; a++){
				if (aWidgets[a] === oWidget){
					aWidgets.splice(a,1);
				}
			}
        }
    };
    
    // 2) When an event comes in notify all the widgets that have 
    // subscribed to the event
    this.publish = function(oSrcWidget, sEvent, oData)
    {   
        var aWidgets = this.aEvents[sEvent];
        if (aWidgets)
        {
            var i;
            for (i = 0; i < aWidgets.length; i++)
            {
                var oWidget = aWidgets[i];
				//debgdiv("e: " + sEvent + " : "+oWidget.oname);
                oWidget.onEvent(oSrcWidget, sEvent, oData);
            }
        }
	if( sEvent == "newSearchResults" && typeof globalPickerMonitor != 'undefined' ) {
		globalPickerMonitor.toggleClearAll();
	} 
    };
}


/////////////////////////////////////////


var scrollMan = new N2EventManager();



if ( !toggleBrandView ) { var toggleBrandView = function() {}; }

if( typeof eventMan != "undefined" ) {

	scrollMan.numberBrands = 0;

	scrollMan.init = function() {
		var widgets = eventMan.aEvents["newSearchResults"];
		for( var i = 0; i < widgets.length; i++ ) {
			if( widgets[i] instanceof Control.Brands ) {
				for( var brand in widgets[i].things ) {
					if( widgets[i].things[brand].selected == true ) {
						scrollMan.onEvent("", "selectBrand", brand);
					}
				}
				break;
			}
		}
	}
	
	scrollMan.onEvent = function(oSrcWidget, sEvent, oData) {
		if( sEvent == "selectBrand" ) {
			if( !($("content-" + oData)) ) {
				scrollMan.numberBrands++;
				var bscroller=new Control.BrandScroller(oData, "brandScrollerView");
				eventMan.subscribe(bscroller, ["newSearchResults"]);
				if( scrollMan.numberBrands > 10 ) {
					toggleBrandView( false );
				} else if (scrollMan.numberBrands == 1 ) {
					toggleBrandView( true );
				}
			} else {
				scrollMan.numberBrands--;
				if( scrollMan.numberBrands == 0 || scrollMan.numberBrands > 10 ) {
					toggleBrandView( false );
				} else if( scrollMan.numberBrands == 10 ) {
					toggleBrandView( true );
				}
				scrollMan.publish("","remove-" + oData,"");
			}
		} else if( sEvent == "updateSearch" && !(oSrcWidget instanceof Control.Brands) ) {
			scrollMan.publish("", "updateSearch", "");
		}
	}
	
	scrollMan.clearAll = function() {
		scrollMan.numberBrands = 0;
		$('brandScrollerView').innerHTML = "";
	}
	
	eventMan.subscribe(scrollMan, ["selectBrand", "updateSearch"]);
}


if( !debgdiv ) {
	var debgdiv = function() {}
}

function queryObject() {
	this.bv = "";	
	this.overrideBrand = "";
	this.colors = "";
	this.sizes = "";
	this.size = "";
	this.widths = "";
	this.heelheights = "";
	this.brands = "";
	this.keywords = "";
	this.nodes = "";
	this.node = "";
	this.sort = "";
	this.priceHigh = "";
	this.priceLow = "";
	this.onsale = "";
	this.newarrival = "";
	this.page = "1";
	this.bpage = "1";
}

if(!Control) var Control = {};
Control.CScroller = Class.create();

Control.CScroller.prototype = {
	_initialize: function(sName, sHome, sHeaderMarkup) {
		this.homeBase = sHome;
		this.name = sName;
		this.activeLeft = 0;
		this.activeRight = 0;


        var myMarkup = "";
		myMarkup += "<table id=\"table-" + sName + "\">";
		myMarkup += sHeaderMarkup;
		myMarkup += "<tr><td colspan='3'><div id='espace_scroll'></div><h1 id=\"no-result-" + sName + "\" style=\"display: none\">No results found. Please try a different search.</h1></td></tr>"
 		myMarkup += "<tr id='scrollerMain'>";
		myMarkup += "<td valign=\"top\">";
		myMarkup += "<img class='scrollArrow' style=\"display: none;\" id=\"left-image-"+sName+"\" src=\""+jsImg.getImagePath("left_arrow_inactive")+"\" onmouseover=\"scrollMan.publish(this, 'start-right-" + this.name + "', this.id);\" onmouseout=\"scrollMan.publish(this, 'stop-right-" + this.name + "', this.id);\" >";
		myMarkup += "</td>";
		myMarkup += "<td>";
		myMarkup += "<div class=\"contextMain\" id=\"main-" + sName + "\" >";
		myMarkup += "<table><tbody>";
		myMarkup += "<tr id=\"content-" + sName + "\">";
		myMarkup += "</tr>";
		myMarkup += "</tbody></table>";
		myMarkup += "</div>";
		myMarkup += "</td>";
		myMarkup += "<td valign=\"top\">";
		myMarkup += "<img class='scrollArrow' style=\"display: none;\" id=\"right-image-"+sName+"\" src=\""+jsImg.getImagePath("right_arrow")+"\" onmouseover=\"scrollMan.publish(this, 'start-left-" + this.name + "', this.id);\" onmouseout=\"scrollMan.publish(this, 'stop-left-" + this.name + "', this.id);\" >";
		myMarkup += "</td>";
		myMarkup += "</table>";
			
		var createMe = document.createElement("div");
		createMe.innerHTML = myMarkup;
		document.getElementById(this.homeBase).appendChild(createMe);
		this.me = createMe;
		
		scrollMan.subscribe(this, ["start-left-" + sName, "start-right-" + sName, "stop-left-" + sName, "stop-right-" + sName, "left-" + sName, "right-" + sName, "remove-" + sName, "show-list", "updateSearch", "click", "shop-" + sName]);
		
	},
	
	scrollRight: function() {
		if (typeof this._loadImage != 'undefined'){
			this._loadImage();
		}
		if( this.activeRight == 1 ) {
			var beforeInc = $("main-" + this.name).scrollLeft;
			$("main-" + this.name).scrollLeft-=5;
			var afterInc = $("main-" + this.name).scrollLeft;
			if( $("main-" + this.name).scrollLeft == 0 ) {
				$("left-image-" + this.name).src = jsImg.getImagePath("left_arrow_inactive");
			} else {
				$("left-image-" + this.name).src = jsImg.getImagePath("left_arrow");
				setTimeout("scrollMan.publish(null, \"right-" + this.name + "\", null);", 5);
			}
			if( beforeInc != afterInc ) {
				$("right-image-" + this.name).src = jsImg.getImagePath("right_arrow");
			}	
		}
		$('lbound-' + this.name).innerHTML = Math.floor($('main-' + this.name).scrollLeft / this.itemWidth) + 1;
		$('ubound-' + this.name).innerHTML = Math.floor($('main-' + this.name).scrollLeft / this.itemWidth) + this.size;
	},
		
	scrollLeft: function() {
		if (typeof this._loadImage != 'undefined'){
			this._loadImage();
		}
		if( this.activeLeft == 1 ) {
			var beforeInc = $("main-" + this.name).scrollLeft;
			$("main-" + this.name).scrollLeft+=5;
			var afterInc = $("main-" + this.name).scrollLeft;
			if( $("main-" + this.name).scrollLeft == 0 ) {
				$("left-image-" + this.name).src = jsImg.getImagePath("left_arrow_inactive");
			} else {
				$("left-image-" + this.name).src = jsImg.getImagePath("left_arrow");
			}
			if( beforeInc == afterInc ) {
				$("right-image-" + this.name).src = jsImg.getImagePath("right_arrow_inactive");
			} else {
				$("right-image-" + this.name).src = jsImg.getImagePath("right_arrow");
				setTimeout("scrollMan.publish(null, \"left-" + this.name + "\", null);", 5);
			}			
		}
		var before = $('lbound-' + this.name).innerHTML;
		$('lbound-' + this.name).innerHTML = Math.floor($('main-' + this.name).scrollLeft / this.itemWidth) + 1;
		if( typeof this._onEvent != 'undefined' ) {
			this._onEvent("", "scroll-update-" + this.name, $('lbound-' + this.name).innerHTML);
		}
		var after = $('lbound-' + this.name).innerHTML;
		$('ubound-' + this.name).innerHTML = Math.floor($('main-' + this.name).scrollLeft / this.itemWidth) + this.size;
		

	}, 
	
	inMyThings: function( asin ) {
		if( typeof mythingsResponse != "undefined" ) {
			var asins = mythingsResponse.items;
			if( typeof asins != 'undefined' ) {
				for( var i = 0; i < asins.length; i++ ) {
					var item = asins[i];
					if( item.item == asin ) {
						return true;
					}
				}
			}
		}
		return false;
	},
	
	filterImage:function( imgURL ) {
		if(imgURL.indexOf("no-img") >= 0 || imgURL.indexOf("")>=0) {
			imgURL="";
		}
		return imgURL;
	},
	
	onEvent: function(oSrcWidget, sEvent, oData){
		if( typeof this._onEvent != 'undefined' ) {
			this._onEvent(oSrcWidget, sEvent, oData);
		}
		switch(sEvent){
				case "show-list":
					var row = $("content-" + this.name);
					var contextList = $("main-" + this.name);
					if( row.offsetWidth > contextList.offsetWidth ) {
						document.getElementById("left-image-" + this.name).style.display = "inline";
						document.getElementById("right-image-" + this.name).style.display = "inline";
					}
				break;
				case "left-" + this.name: 
					this.scrollLeft();
				break;
				case "right-" + this.name: 
					this.scrollRight();
				break;
				case "start-right-" + this.name: 
					this.activeRight = 1;
					this.scrollRight();
				break;
				case "start-left-" + this.name: 
					this.activeLeft = 1;
					this.scrollLeft();
				break;
				case "stop-right-" + this.name: 
					this.activeRight = 0;
				break;
				case "stop-left-" + this.name: 
					this.activeLeft = 0;
				break;
				case "remove-" + this.name:
					if( this.request != null ) {
						this.request.transport.abort();
					}
					scrollMan.unsubscribe(this);
					$(this.homeBase).removeChild(this.me);
				break;
		}
	},
	
	getPriceMarkup : function( listprice, price ) {
		var mypriceMarkup = "";
		if( typeof listprice != 'undefined' ) {
			mypriceMarkup = "<span class='xprice'>" + listprice + "</span>&nbsp;<span class='salePrice'>" + price + "</span>";
		} else {
			// on affiche pas le prix
			mypriceMarkup ="";
			//mypriceMarkup = "<span class='price'>" + price + "</span>";
		}
		return mypriceMarkup;
	},
	
	getMyThingsMarkup : function( asin ) {
		var myThingsMarkUp = "";
		if( this.inMyThings(asin) == true ) {
			myThingsMarkUp = "<span class=\"prodImgSaved\"><img src=\"" + $('mSaved').src + "\"></span>";
		}
		return myThingsMarkUp;
	}
	
};

function initSearchScroller( name, leftEdge, itemWidth ) {
//$("main-" + this.name).scrollLeft = (leftEdge - 1) * this.itemWidth;
$("main-" + name).scrollLeft = (leftEdge - 1) * itemWidth;
if( $("main-" + name).scrollLeft != (leftEdge - 1) * itemWidth ) {
	setTimeout( "initSearchScroller('"+name+"',"+leftEdge+","+itemWidth+");", 10 );
}
}

Control.SearchScroller = Class.create();
Control.SearchScroller.prototype = Object.extend({ 
		initialize: function(sName, sHome, sQuery, sAnchorAsin) {
			var myMarkup = "";
			myMarkup += "<tr>";
			myMarkup += "<td colspan='3'><span class=\"contextAmount floatRight\" colspan='2' style=\"display: none;\" id=\"size-bar-" + sName + "\">"+unescape(sName)+": showing <span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">5</span> of <span id=\"size-" + sName + "\"></span></span>";		
			//myMarkup += "<img src=\""+jsImg.getImagePath("continue_shopping")+"\" class=\"contextLink\" onclick=\"scrollMan.publish('', 'shop-" + sName + "', '');\">";
			myMarkup += "<span class=\"contextHeader\"></span>";
			myMarkup += "</td></tr>";
			this._initialize(sName, sHome, myMarkup);
			this.query = sQuery;
			this.queryPageSize = 60;
			this.itemWidth = 93;
			this.request = null;
			this.numberFilled = 0;
			this.numberAsins = 0;
			this.totalSize = 0;
			this.size = 6;
			this.anchorAsin = sAnchorAsin;
			this.anchorAsinFound = false;
			this.anchorAsinIndex = 0;	
			this.anchorAsinLocated = false;
			this.anchorAsinSideSize = 6;
			this.fillAsins();
			this.scrollLeftOccured = false;
		},
		
		fillAsins: function() {
			this.numberFilled++;
			var opt = {
			method: 'post',
			postBody: "lite=1&" + this.queryToString(),
			onSuccess: this.searchReturn.bind(this)
			};
			this.request = new Ajax.Request('/searchliterequest', opt);
		},
		
		searchReturn: function(http_request) {
			var json_data = http_request.responseText;
			var resultSet = {}; 
			resultSet = eval( '(' + json_data + ')' );
			if( this.totalSize == 0 ) {
				var tSize = resultSet.asins.length;
				this.totalSize = tSize; //resultSet.numResults;
				if (this.totalSize <= 1){
					Element.hide('size-' + this.name);
					Element.hide('lbound-' + this.name);
					Element.hide('ubound-' + this.name);
					Element.hide('size-bar-' + this.name);
					Element.hide('scrollerMain'); // Hide scroller completely if only 1 result.
					if (this.totalSize < 1){
						Element.show('no-result-'+ this.name);
					}
				}
				else{
					Element.hide('no-result-'+ this.name);
					Element.show('size-' + this.name);
					Element.show('lbound-' + this.name);
					Element.show('ubound-' + this.name);
					Element.show('size-bar-' + this.name);					
					$('size-' + this.name).innerHTML = tSize;
					$('lbound-' + this.name).innerHTML = Math.min(1, tSize);
					$('ubound-' + this.name).innerHTML = Math.min(this.size, tSize);
				}
			}
			
			for( var i = 0; i < resultSet.asins.length; i++ ) {
				this.addAsin(resultSet.asins[i].asin, resultSet.asins[i].imgURL, resultSet.asins[i].listprice, resultSet.asins[i].price, resultSet.asins[i].outOfStock);
			}	
			
			if (this.anchorAsinFound && !this.anchorAsinLocated) {
				if (this.anchorAsinIndex > Math.floor(this.size / 2)) {
					var leftEdge = (this.anchorAsinIndex - Math.floor(this.size / 2));
					if (this.anchorAsinIndex > (this.totalSize - this.size) ){
						leftEdge = this.totalSize - this.size + 1;
					}	
					//$("main-" + this.name).scrollLeft = (leftEdge - 1) * this.itemWidth;
					initSearchScroller(this.name, leftEdge, this.itemWidth);
					$('lbound-' + this.name).innerHTML = leftEdge;
					$('ubound-' + this.name).innerHTML = leftEdge + this.size - 1;		
					$("left-image-" + this.name).src = jsImg.getImagePath("left_arrow");	
				}
				
			//	var row = document.getElementById("content-" + this.name);
			//	var asinImages = row.getElementsByTagName("img");
				var asinImages = this.getProdImages();
				for (var i=Math.max(0, this.anchorAsinIndex - this.anchorAsinSideSize); i<Math.min(this.numberAsins, this.anchorAsinIndex + this.anchorAsinSideSize); i++){
					asinImage = asinImages[i];
					asinImage.src = asinImage.id;				
				}
				
				this.anchorAsinLocated = true;
			}
						
			//if (!this.anchorAsinFound && this.numberAsins < this.totalSize ){
				//this.fillAsins();
			//}
		},
		
		addAsin: function( asin, image, listprice, price, outofstock ) {
			var row = document.getElementById("content-" + this.name);
			var newAsin = document.createElement("td");
			
			newAsin.className = "result";
			if( typeof previouscontextasin != "undefined" ) {
				if (asin == previouscontextasin)
					newAsin.className = "resultWithBorder";
			}
			newAsin.valign = "top";
			newAsin.id="contextasin"+asin;
			var asinMarkup = "";
			var myThingsMarkUp = this.getMyThingsMarkup(asin);
			var priceMarkup = "<span class='price'>Unavailable</span>";
			if( outofstock == 0 ) {
				priceMarkup = this.getPriceMarkup(listprice, price);
			} 		
			//asinMarkup += "<div class='result' onclick=\"detailMan.publish('', 'updateDetailPage', '" + asin + "');\"><center><img class=\"prodImg\"  src=\"" + image + "\"><br>" + myThingsMarkUp + priceMarkup + "</center>";
			var center = document.createElement('center');
			
			var asinImage = document.createElement('img');
			asinImage.className = "prodImg cadre3";
			asinImage.src = image;
			asinImage.id = image;
			center.appendChild(asinImage);
			center.innerHTML += "<br>" + myThingsMarkUp + priceMarkup;
			asinMarkup += "<div class='result' onclick=\"detailMan.publish('', 'updateDetailPage', '" + asin + "');\">" + center.innerHTML;
			
			this.numberAsins++;
			
			newAsin.innerHTML = asinMarkup;
			row.appendChild(newAsin);
			
			if( this.totalSize >= this.size ) {
				$("left-image-" + this.name).style.display = "inline";
				$("right-image-" + this.name).style.display = "inline";
			}
			
			if (asin == this.anchorAsin){
				this.anchorAsinFound = true;
				this.anchorAsinIndex = this.numberAsins;
			}
			
		},
		
		_loadImage: function() {
				//var row = document.getElementById("content-" + this.name);
				//var asinImages = row.getElementsByTagName("img");
				var asinImages = this.getProdImages();
				for (var i=Math.max(0, $('lbound-' + this.name).innerHTML-this.anchorAsinSideSize); i<Math.min(this.numberAsins, $('ubound-' + this.name).innerHTML); i++){
					asinImage = asinImages[i];
					asinImage.src = asinImage.id;				
				}
		}, 
		
		getProdImages: function(){
			var row = document.getElementById("content-" + this.name);
			var allImages = row.getElementsByTagName("img");
			var prodImages = [];
			for (var i=0; i<allImages.length; i++){
				var image = allImages[i];
				if (image.className == 'prodImg cadre3'){
					prodImages.push(image);
				}
			}
			return prodImages;
		},

		queryToString : function( url ) {
			var qStr = "";
			qStr += "colors=" + this.query.colors;
			if( url ) {
				qStr += "&brands=" + this.query.brands;
				qStr += "&dept=" + this.query.dept;
				if( this.query.bv != "" ) {
					qStr += "&bv=" + this.query.bv;
				}
			} else { 
				if( this.query.overrideBrand == "" ) {
					qStr += "&brands=" + this.query.brands;
				} else {
					qStr += "&brands=" + this.query.overrideBrand;
				}
			}
			qStr += "&nodes=" + this.query.nodes;
			qStr += "&node=" + this.query.node;
			qStr += "&priceHigh=" + this.query.priceHigh;
			qStr += "&priceLow=" + this.query.priceLow;
			qStr += "&sort=" + this.query.sort;
			qStr += "&keywords=" + this.query.keywords;
			qStr += "&onsale=" + this.query.onsale;
			qStr += "&widths=" + this.query.widths;
			qStr += "&sizes=" + this.query.sizes;
			qStr += "&heelheights=" + this.query.heelheights.replace(/&/g, "%26");
			qStr += "&newarrivals=" + this.query.newarrivals;
			//if( url ) {
			if( this.query.overrideBrand == "" ) {
				qStr += "&page=" + this.query.page;
				qStr += "&size=" + this.query.size;
			} else {
				qStr += "&page=" + this.query.bpage;
				qStr += "&size=20";
			}
			//} else {
			//	qStr += "&size=" + this.queryPageSize;
			//}
			return qStr;
		},
		
		_onEvent: function(oSrcWidget, sEvent, oData){
			switch(sEvent){
				case "shop-" + this.name:
						window.location = "/s/ref=dp_csh/?" + this.queryToString(1);
				break;
			}
		}
		
	}, Control.CScroller.prototype);
	
Control.BrandScroller = Class.create();
Control.BrandScroller.prototype = Object.extend({ 
		initialize: function(sName, sHome) {
			var myMarkup = "";
			myMarkup += "<tr>";
			myMarkup += "<td id=\"logo-" + sName + "\" colspan='3'></td>";
			myMarkup += "</tr><tr>";
			myMarkup += "<td colspan='3'>";
			myMarkup += "<span class=\"contextAmount floatRight\" style=\"display: none;\" id=\"size-bar-" + sName + "\">showing <span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">5</span> of <span id=\"size-" + sName + "\"></span></span>";
			myMarkup += "<span class=\"contextLink\" onclick=\"scrollMan.publish('', 'shop-" + sName + "', '');\">shop this brand</span>";
			myMarkup += "</td></tr>";
			this._initialize(sName, sHome, myMarkup);
			this.request = null;
			this.itemWidth = 93;
			this.numberFilled = 0;
			this.numberAsins = 0;
			this.totalSize = 0;
			this.size = 6;
			this.fillAsins();
		},
		
		fillAsins: function() {
			this.numberFilled++;
			var postString = "";
			for (var i = 0; i < searchMan.widgets.length; i++){
					var oWidget = searchMan.widgets[i];
					var serial = oWidget.serialize();
					if (serial != "" && !(oWidget instanceof Control.Pager) && !(oWidget instanceof Control.Brands)){
						if(i != 0){ postString += "&" }
						 postString += serial;
					}
			}
			postString +="&brands="+escape(this.name);
			postString +="&page=" + this.numberFilled;
			postString +="&lite=1&size=20";

			if( $('hSearchCount').value == "" || $('hSearchCount').value == "1" ) {
				postString += "&sizes=" + sSizes;
				postString += "&widths=" + sWidths;
				postString += "&heelheights=" + sHeelHeights.replace(/&/g, "%26");
			}			

			// now we have a valid post string - fire off another search
			var opt = {
			method: 'post',
			postBody: postString,
			onSuccess: this.searchReturn.bind(this)
			};
			debgdiv('brand scroller: /searchliterequest?' + opt.postBody);
			if ((this.request)&&(this.callInProgress(this.request.transport))) {
				debgdiv("aborted previous call");
				this.request.transport.abort();
			}
			this.request = new Ajax.Request('/searchliterequest', opt); // search request - get initial result set
		},
		
		emptyAsins : function() {
			var row = document.getElementById("content-" + this.name);
			while( row.childNodes.length > 0 ) {
				row.removeChild( row.childNodes[0] );
			}
			this.numberFilled=0;
			this.numberAsins=0;
			this.totalSize=0;
			Element.hide('size-' + this.name);
			Element.hide('lbound-' + this.name);
			Element.hide('ubound-' + this.name);
			Element.hide('size-bar-' + this.name);
			$("left-image-" + this.name).style.display = "none";
			$("right-image-" + this.name).style.display = "none";
		},
		
		searchReturn: function(http_request) {
			var json_data = http_request.responseText;
			var resultSet = {}; 
			resultSet = eval( '(' + json_data + ')' );
			if( this.totalSize == 0 ) {
				this.totalSize = resultSet.numResults;
				if (this.totalSize == 0){
					Element.show('no-result-'+ this.name);
                                        Element.hide('size-' + this.name);
                                        Element.hide('lbound-' + this.name);
                                        Element.hide('ubound-' + this.name);
                                        Element.hide('size-bar-' + this.name);                  
                                        Element.hide('main-' + this.name);  
				}
				else{
					Element.hide('no-result-'+ this.name);
					Element.show('size-' + this.name);
					Element.show('lbound-' + this.name);
					Element.show('ubound-' + this.name);
					Element.show('size-bar-' + this.name);			
					Element.show('main-' + this.name);		
					$('size-' + this.name).innerHTML = resultSet.numResults;
					$('lbound-' + this.name).innerHTML = Math.min(1, resultSet.numResults);
					$('ubound-' + this.name).innerHTML = Math.min(this.size, resultSet.numResults);
				}
			}
			
			for( var i = 0; i < resultSet.asins.length; i++ ) {
				this.addAsin(resultSet.asins[i].asin, resultSet.asins[i].imgURL, resultSet.asins[i].title, resultSet.asins[i].listprice, resultSet.asins[i].price, resultSet.asins[i].outOfStock);
			}	
			if( this.numberFilled == 1 && typeof(resultSet.brandLogo) != 'undefined' && resultSet.brandLogo != "" ) {
				$('logo-' + this.name).innerHTML = resultSet.brandLogo;
			} else if( this.numberFilled == 1 ) {
				$('logo-' + this.name).innerHTML = unescape(this.name);
			}
		},
		
		addAsin: function( asin, image, title, listprice, price, outofstock ) {
			var row = document.getElementById("content-" + this.name);
			var newAsin = document.createElement("td");
			
			newAsin.className = "result";
			if( typeof previouscontextasin != "undefined" ) {
				if (asin == previouscontextasin)
					newAsin.className = "resultWithBorder";
			}
			newAsin.valign = "top";
			newAsin.id="contextasin"+asin;
			var asinMarkup = "";
			var myThingsMarkUp = this.getMyThingsMarkup(asin);
			var priceMarkup = "<span class='price'>Unavailable</span>";
			if( outofstock == 0 ) {
				priceMarkup = this.getPriceMarkup(listprice, price);
			}
			
			this.numberAsins++;
			
			var linkString = this.buildAsinLink(this.name, [asin, this.numberFilled], this.numberAsins);
			asinMarkup += "<a href=\"" + linkString + "\"><img class=\"prodImg cadre3\" src=\"" + image + "\"><br><span class=\"title\">" + title + "</span><br>" + myThingsMarkUp + priceMarkup + "</a>";
			
			newAsin.innerHTML = asinMarkup;
			row.appendChild(newAsin);

			if( this.totalSize >= this.size ) {
				$("left-image-" + this.name).style.display = "inline";
				$("right-image-" + this.name).style.display = "inline";
			}
		},	
		
		updateSearch : function() {
			$("main-" + this.name).scrollLeft = 0;
			$("left-image-" + this.name).src = jsImg.getImagePath("left_arrow_inactive");
			$("right-image-" + this.name).src = jsImg.getImagePath("right_arrow");
			this.emptyAsins();
			this.fillAsins();
		},
		
		buildAsinLink: function(oSrcWidget, oData, index){
			var postString = "/dp/" + oData[0] +"/ref=sr_bv_1-" + index + "/?";
			for (var i = 0; i < searchMan.widgets.length; i++){
					var oWidget = searchMan.widgets[i];
					var serial = oWidget.serialize();
					if (serial != "" && !(oWidget instanceof Control.Pager) ){
						 postString += "&";
						 postString += serial;
					}
			}
			postString +="&overrideBrand="+escape(oSrcWidget);
			postString +="&bv=1";
			postString +="&bpage="+oData[1];
			postString +="&fromPage=search";
			return postString;
		},
		
		_onEvent: function(oSrcWidget, sEvent, oData){
			switch(sEvent){
				case "updateSearch":
					this.updateSearch();
				break;
				case "click":
					var postString = "/dp/" + oData[0] +"?";
					for (var i = 0; i < searchMan.widgets.length; i++){
							var oWidget = searchMan.widgets[i];
							var serial = oWidget.serialize();
							if (serial != "" && !(oWidget instanceof Control.Pager) ){
								 postString += "&";
								 postString += serial;
							}
					}
					postString +="&overrideBrand="+escape(oSrcWidget);
					postString +="&bv=1";
					postString +="&bpage="+oData[1];
					postString +="&fromPage=search";
					window.location = postString;
					break;
				break;
				case "shop-" + this.name:
					var postString = "";
					for (var i = 0; i < searchMan.widgets.length; i++){
							var oWidget = searchMan.widgets[i];
							var serial = oWidget.serialize();
							if (serial != "" && !(oWidget instanceof Control.Pager) && !(oWidget instanceof Control.Brands)){
								if(i != 0){ postString += "&" }
								 postString += serial;
							}
					}
					postString +="&brands="+escape(escape(this.name));
					postString +="&boutique=1";
					if( typeof( $('mDept') ) != 'undefined' && typeof( $('mDept').innerHTML ) != 'undefined' && $('mDept').innerHTML.length > 0 ) {
						postString += "&dept=" + $('mDept').innerHTML;
					}
					window.location = "/s/ref=sr_bb/?" + postString;
				break;
				case "scroll-update-" + this.name:
					if( oData == ((this.numberFilled-1)*20)+5 && this.numberAsins < this.totalSize ) {
						this.fillAsins();
					}
				break;
			}
		},
		
		callInProgress: function(xmlhttp) {
			switch (xmlhttp.readyState) {
			case 1: case 2: case 3:
			return true;
			break;
			// Case 4 and 0
			default:
			return false;
			break;
			}
		}
		
	}, Control.CScroller.prototype);

Control.AsinListScroller = Class.create();
Control.AsinListScroller.prototype = Object.extend({ 
		initialize: function(sName, sHome, sSize) {
			var myMarkup = "";
			this.size = 6;
			if( sSize < 6 ) {
				this.size = sSize;
			}
			// on eléve le bouton
			//myMarkup += "<tr><td colspan='3' id=\"size-bar-" + this.name + "\"><span class=\"contextAmount floatRight\">"+unescape(sName)+" showing <span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">"+this.size+"</span> of <span id=\"size-" + sName + "\">"+sSize+"</span></span><a  class=\"contextLink\" href=\""+refpage+"\"><img src=\""+jsImg.getImagePath("continue_shopping")+"\"></a></td></tr>";
			
			//myMarkup += "<tr><td colspan='3' id=\"size-bar-" + this.name + "\"><span class=\"contextAmount floatRight\">"+unescape(sName)+" showing <span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">"+this.size+"</span> of <span id=\"size-" + sName + "\">"+sSize+"</span></span></td></tr>";
			
			myMarkup +="<div style='display:none'><span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">"+this.size+"</span> of <span id=\"size-" + sName + "\">"+sSize+"</span></div>";
				
			this._initialize(sName, sHome, myMarkup);
			this.itemWidth = 93;
			this.numberFilled = 0;
			this.numberAsins = 0;
			this.totalSize = sSize;	
			if( this.totalSize >= this.size ) {
				$("left-image-" + this.name).style.display = "inline";
				$("right-image-" + this.name).style.display = "inline";
			}
			this.fillAsins();
		},
		
		fillAsins : function() {
			if (typeof asinList != "undefined") {			
				for( var i = 0; i < asinList.length; i++ ) {
					this.addAsin(asinList[i].asin, asinList[i].thumbnailImageURL, asinList[i].listprice, asinList[i].buyingPrice); 
				}
			}
		},
		
		addAsin: function( asin, image, listprice, price ) {
			var row = document.getElementById("content-" + this.name);
			var newAsin = document.createElement("td");
			
			newAsin.className = "result";
			if( typeof previouscontextasin != "undefined" ) {
				if (asin == previouscontextasin)
					newAsin.className = "resultWithBorder";
			}
			newAsin.valign = "top";
			newAsin.id="contextasin"+asin;
			var asinMarkup = "";
			var myThingsMarkUp = this.getMyThingsMarkup(asin);
			var priceMarkup = this.getPriceMarkup(listprice, price);
			asinMarkup += "<div class='result' onclick=\"detailMan.publish('', 'updateDetailPage', '" + asin + "');\"><center><img class=\"prodImg cadre3\" src=\"" + image + "\"><br>" + myThingsMarkUp + priceMarkup + "</center>";
			
			this.numberAsins++;
			
			newAsin.innerHTML = asinMarkup;
			row.appendChild(newAsin);
			
		}
		
	}, Control.CScroller.prototype);

Control.MyThingsScroller = Class.create();
Control.MyThingsScroller.prototype = Object.extend({ 
		initialize: function(sName, sHome, sSize) {
			var myMarkup = "";
			this.size = 6;
			if( sSize < 6 ) {
				this.size = sSize;
			}
			myMarkup += "<tr><td colspan='3' id=\"size-bar-" + sName + "\"><span class=\"contextAmount floatRight\">"+unescape(sName)+" showing <span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">"+this.size+"</span> of <span id=\"size-" + sName + "\">" + sSize + "</span></span><a class=\"contextLink\" href=\"/mythings\"><img src=\""+jsImg.getImagePath("return_to_saved")+"\"></a></td></tr>";
			this._initialize(sName, sHome, myMarkup);
			this.itemWidth = 93;
			this.numberFilled = 0;
			this.numberAsins = 0;
			this.totalSize = sSize;
			
			if( this.totalSize > this.size ) {
				$("left-image-" + this.name).style.display = "inline";
				$("right-image-" + this.name).style.display = "inline";
			}
			this.fillAsins();
		},
		
		addAsin: function( asin, image, listprice, price ) {

			var row = document.getElementById("content-" + this.name);
			var newAsin = document.createElement("td");
			
			newAsin.className = "result";
			if( typeof previouscontextasin != "undefined" ) {
				if (asin == previouscontextasin)
					newAsin.className = "resultWithBorder";
			}
			newAsin.valign = "top";
			newAsin.id="asigne"+asin;
			var asinMarkup = "";
			var myThingsMarkUp = this.getMyThingsMarkup(asin);
			var priceMarkup = this.getPriceMarkup(listprice, price);
			asinMarkup += "<div class='result' onclick=\"detailMan.publish('http://dirinfo.com', 'updateDetailPage', '" + asin + "');\"><center><img class=\"prodImg cadre3\" src=\"" + image + "\"><br>" + priceMarkup + "</center>";

			this.numberAsins++;
			
			newAsin.innerHTML = asinMarkup;
			row.appendChild(newAsin);
			
		},

		fillAsins : function() {
			this.numberFilled++;
			for( var i = 0; i < mythingsResponse.items.length; i++ ) {
				this.addAsin(mythingsResponse.items[i].item, this.filterImage(mythingsResponse.items[i].image), mythingsResponse.items[i].listprice, mythingsResponse.items[i].price); 
			}				
		}	
		
	}, Control.CScroller.prototype);

Control.RecommendationScroller = Class.create();
Control.RecommendationScroller.prototype = Object.extend({

		initialize: function(sName, sHome, asins) {
			this.asins = asins;
			var wSize = 5;
			if( recommendationResponse.asinList.length < 5 )
				wSize = recommendationResponse.asinList.length;
			var myMarkup = "";
			myMarkup += "<tr><td colspan='3'  id=\"size-bar-" + sName + "\"><span class=\"contextAmount floatRight\">"+unescape(sName)+" showing <span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">" + wSize + "</span> of <span id=\"size-" + sName + "\">"+recommendationResponse.asinList.length+"</span></span></td></tr>";
			this._initialize(sName, sHome, myMarkup);
			this.itemWidth = 120;
			this.numberFilled = 0;
			this.numberAsins = 0;
			this.totalSize = recommendationResponse.asinList.length;
			this.size = wSize;
			if( this.totalSize > this.size ) {
				$("left-image-" + this.name).style.display = "inline";
				$("right-image-" + this.name).style.display = "inline";
			}
			this.fillAsins();
		},
		
		fillAsins : function() {
			this.numberFilled++;
			for( var i = 0; i < recommendationResponse.asinList.length; i++ ) {
				this.addAsin(recommendationResponse.asinList[i].asin, recommendationResponse.asinList[i].thumbnailImageURL, recommendationResponse.asinList[i].title, recommendationResponse.asinList[i].buyingPrice); 
			}		
		},
		
		addAsin: function( asin, image, title, price ) {
			var row = document.getElementById("content-" + this.name);
			var newAsin = document.createElement("td");
			
			newAsin.className = "result";
			if( typeof previouscontextasin != "undefined" ) {
				if (asin == previouscontextasin)
					newAsin.className = "resultWithBorder";
			}
			newAsin.valign = "top";
			newAsin.id="contextasin"+asin;
			var asinMarkup = "";
			var myThingsMarkUp = this.getMyThingsMarkup(asin);
			asinMarkup += "<div class='result' onclick=\"window.open('/dp/"+asin+"?fromPage=asinlist&contextTitle=Recommendation&asins="+this.asins+"','_self');\"><center><img class=\"prodImg cadre3\"  src=\"" + image + "\"><br>" + myThingsMarkUp + "<span class=\"title\">" + title + "</span><br><span class=\"price\">" + price + "</span></center>";
			
			this.numberAsins++;
			
			newAsin.innerHTML = asinMarkup;
			row.appendChild(newAsin);
			
		}
		
	}, Control.CScroller.prototype);
	
Control.AccessoryScroller = Class.create();
Control.AccessoryScroller.prototype = Object.extend({

		initialize: function(sName, sHome, asins) {
			this.asins = asins;
			this.itemWidth = 93;
			this.numberFilled = 0;
			this.numberAsins = 0;
			this.totalSize = jsonText.accessory.accessaries.length;
			var myMarkup = "";
			myMarkup += "<tr><td colspan='3' style=\"display: none;\" id=\"size-bar-" + sName + "\"><span style=\"display: none;\" id=\"lbound-" + sName + "\"></span><span style=\"display: none;\" id=\"ubound-" + sName + "\"></span><span style=\"display: none;\" id=\"size-" + sName + "\"></span></td></tr>";		
			this._initialize(sName, sHome, myMarkup);
			this.size = 3;
			if( this.totalSize >= this.size ) {
				$("left-image-" + this.name).style.display = "inline";
				$("right-image-" + this.name).style.display = "inline";
			}
			this.fillAsins();
		},
		
		fillAsins : function() {
			this.numberFilled++;		
			for( var i = 0; i < jsonText.accessory.accessaries.length; i++ ) {
				this.addAsin(jsonText.accessory.accessaries[i].asin, jsonText.accessory.accessaries[i].image, jsonText.accessory.accessaries[i].title, jsonText.accessory.accessaries[i].listprice); 
			}		
		
		},
		
		addAsin: function( asin, image, title, price ) {

			var row = document.getElementById("content-" + this.name);
			var newAsin = document.createElement("td");
			
			newAsin.className = "result";
			if( typeof previouscontextasin != "undefined" ) {
				if (asin == previouscontextasin)
					newAsin.className = "resultWithBorder";
			}
			newAsin.valign = "top";
			newAsin.id="contextasin"+asin;
			var asinMarkup = "";
			var myThingsMarkUp = this.getMyThingsMarkup(asin);
			
			asinMarkup += "<div class='result' onclick=\"window.open('/dp/"+asin+"/ref=dp_ymal_/?fromPage=asinlist&contextTitle=Accessory&asins="+this.asins+"&ref=" + detailController.jsonText.currentAsin +"','_self');\"><center><img class=\"prodImg cadre3\"  src=\"" + image + "\"><br>" + myThingsMarkUp + "<span class=\"title\">" + title + "</span><br><span class=\"price\">" + price + "</span></center>";
			
			this.numberAsins++;
			
			newAsin.innerHTML = asinMarkup;
			row.appendChild(newAsin);
			
		}
				
	}, Control.CScroller.prototype);
	
	Control.CartScroller = Class.create();
Control.CartScroller.prototype = Object.extend({ 
		initialize: function(sName, sHome, sSize) {
			var myMarkup = "";
			this.size = 6;
			if( sSize < 6 ) {
				this.size = sSize;
			}
			myMarkup += "<tr><td colspan='3' id=\"size-bar-" + sName + "\"><span class=\"contextAmount floatRight\">"+unescape(sName)+" showing <span id=\"lbound-" + sName + "\">1</span>-<span id=\"ubound-" + sName + "\">"+this.size+"</span> of <span id=\"size-" + sName + "\">" + sSize + "</span></span><a class=\"contextLink\" href=\"/shoppingcart\"><img src=\""+jsImg.getImagePath("return_to_cart")+"\"></a></td></tr>";
			this._initialize(sName, sHome, myMarkup);
			this.itemWidth = 93;
			this.numberFilled = 0;
			this.numberAsins = 0;
			this.totalSize = sSize;
			
			if( this.totalSize > this.size ) {
				$("left-image-" + this.name).style.display = "inline";
				$("right-image-" + this.name).style.display = "inline";
			}
			this.fillAsins();
		},
		
		addAsin: function( asin, image, listprice, price ) {

			var row = document.getElementById("content-" + this.name);
			var newAsin = document.createElement("td");
			
			newAsin.className = "result";
			if( typeof previouscontextasin != "undefined" ) {
				if (asin == previouscontextasin)
					newAsin.className = "resultWithBorder";
			}
			newAsin.valign = "top";
			newAsin.id="contextasin"+asin;
			var asinMarkup = "";
			var CartMarkUp = this.getMyThingsMarkup(asin);
			var priceMarkup;
			if ( listprice!=price) 
				priceMarkup = this.getPriceMarkup(listprice, price);
			else
				priceMarkup = "<span class='price'>$" + price + "</span>";
			asinMarkup += "<div class='result' onclick=\"detailMan.publish('', 'updateDetailPage', '" + asin + "');\"><center><img class=\"prodImg cadre3\" src=\"" + image + "\"><br>"+ CartMarkUp + priceMarkup + "</center>";		

			this.numberAsins++;
			
			newAsin.innerHTML = asinMarkup;
			row.appendChild(newAsin);
			
		},

		fillAsins : function() {
			this.numberFilled++;
			for( var i = 0; i < cartResponse.length; i++ ) {
				this.addAsin(cartResponse[i].asin, this.filterImage(cartResponse[i].image), cartResponse[i].listprice.toFixed(2), cartResponse[i].price.toFixed(2)); 
			}				
		}	
		
	}, Control.CScroller.prototype);

