/*  Prototype JavaScript framework, version 1.3.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
 *  against the source tree, available from the Prototype darcs repository. 
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.3.0',
  emptyFunction: function() {}
}

var Class = {
  create: function() {
    return function() { 
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}
/*
Object.prototype.extend = function(object) {
  return Object.extend.apply(this, [this, object]);
}
*/
Function.prototype.bind = function(object) {
  var __method = this;
  return function() {
    __method.apply(object, arguments);
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this;
  return function(event) {
    __method.call(object, event || window.event);
  }
}

Number.prototype.toColorPart = function() {
  var digits = this.toString(16);
  if (this < 16) return '0' + digits;
  return digits;
}

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try { 
        this.currentlyExecuting = true;
        this.callback(); 
      } finally { 
        this.currentlyExecuting = false;
      }
    }
  }
}

/*--------------------------------------------------------------------------*/

function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1) 
      return element;

    elements.push(element);
  }

  return elements;
}

if (!Array.prototype.push) {
  Array.prototype.push = function() {
		var startLength = this.length;
		for (var i = 0; i < arguments.length; i++)
      this[startLength + i] = arguments[i];
	  return this.length;
  }
}

if (!Function.prototype.apply) {
  // Based on code from http://www.youngpup.net/
  Function.prototype.apply = function(object, parameters) {
    var parameterStrings = new Array();
    if (!object)     object = window;
    if (!parameters) parameters = new Array();
    
    for (var i = 0; i < parameters.length; i++)
      parameterStrings[i] = 'parameters[' + i + ']';
    
    object.__apply__ = this;
    var result = eval('object.__apply__(' + 
      parameterStrings[i].join(', ') + ')');
    object.__apply__ = null;
    
    return result;
  }
}

Object.extend(String.prototype, {
  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  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].nodeValue;
  }
});

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      function() {return new XMLHttpRequest()}
    ) || false;
  }
}

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = Object.extend({
      method:       'post',
      asynchronous: true,
      parameters:   ''
    }, 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 {
      if (this.options.method == 'get')
        url += '?' + parameters;

      this.transport.open(this.options.method, 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) {
    }
  },

  setRequestHeaders: function() {
    var requestHeaders = 
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', Prototype.Version];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type', 
        'application/x-www-form-urlencoded');

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651. 
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];

    if (event == 'Complete')
      (this.options['on' + this.transport.status]
       || this.options['on' + this.responseIsSuccess ? 'Success' : 'Failure']
       || Prototype.emptyFunction)(this.transport);       

    (this.options['on' + event] || Prototype.emptyFunction)(this.transport);    
  }
});

Ajax.Updater = Class.create();
Ajax.Updater.ScriptFragment = '(?:<script.*?>)((\n|.)*?)(?:<\/script>)';

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() {
      this.updateContent();
      onComplete(this.transport);      
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.responseIsSuccess() ?
      this.containers.success : this.containers.failure;

    var match    = new RegExp(Ajax.Updater.ScriptFragment, 'img');
    var response = this.transport.responseText.replace(match, '');
    var scripts  = this.transport.responseText.match(match);

    if (receiver) {
      if (this.options.insertion) {
        new this.options.insertion(receiver, response);
      } else {
        receiver.innerHTML = response;
      }
    }

    if (this.responseIsSuccess()) {
      if (this.onComplete)
        setTimeout((function() {this.onComplete(
          this.transport)}).bind(this), 10);
    }

    if (this.options.evalScripts && scripts) {
      match = new RegExp(Ajax.Updater.ScriptFragment, 'im');
      setTimeout((function() {
        for (var i = 0; i < scripts.length; i++)
          eval(scripts[i].match(match)[1]);
      }).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 = 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 || Ajax.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ? 
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this), 
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});

document.getElementsByClassName = function(className) {
  var children = document.getElementsByTagName('*') || document.all;
  var elements = new Array();
  
  for (var i = 0; i < children.length; i++) {
    var child = children[i];
    var classNames = child.className.split(' ');
    for (var j = 0; j < classNames.length; j++) {
      if (classNames[j] == className) {
        elements.push(child);
        break;
      }
    }
  }
  
  return elements;
}

/*--------------------------------------------------------------------------*/

if (!window.Element) {
  var Element = new Object();
}

Object.extend(Element, {
  toggle: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = 
        (element.style.display == 'none' ? '' : 'none');
    }
  },

  hide: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = 'none';
    }
  },

  show: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = '';
    }
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
  },
   
  getHeight: function(element) {
    element = $(element);
    return element.offsetHeight; 
  },

  hasClassName: function(element, className) {
    element = $(element);
    if (!element)
      return;
    var a = element.className.split(' ');
    for (var i = 0; i < a.length; i++) {
      if (a[i] == className)
        return true;
    }
    return false;
  },

  addClassName: function(element, className) {
    element = $(element);
    Element.removeClassName(element, className);
    element.className += ' ' + className;
  },

  removeClassName: function(element, className) {
    element = $(element);
    if (!element)
      return;
    var newClassName = '';
    var a = element.className.split(' ');
    for (var i = 0; i < a.length; i++) {
      if (a[i] != className) {
        if (i > 0)
          newClassName += ' ';
        newClassName += a[i];
      }
    }
    element.className = newClassName;
  },
  
  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    var 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);
    }
  }
});

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;
    
    if (this.adjacency && this.element.insertAdjacentHTML) {
      this.element.insertAdjacentHTML(this.adjacency, this.content);
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.fragment = this.range.createContextualFragment(this.content);
      this.insertContent();
    }
  }
}

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() {
    this.element.parentNode.insertBefore(this.fragment, this.element);
  }
});

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() {  
    this.element.insertBefore(this.fragment, this.element.firstChild);
  }
});

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() {
    this.element.appendChild(this.fragment);
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },
  
  insertContent: function() {
    this.element.parentNode.insertBefore(this.fragment, 
      this.element.nextSibling);
  }
});

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).focus();
    $(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) {
    var form = $(form);
    var elements = new Array();

    for (tagName in Form.Element.Serializers) {
      var tagElements = form.getElementsByTagName(tagName);
      for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
    }
    return elements;
  },
  
  getInputs: function(form, typeName, name) {
    var 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 = '';
    }
  },

  focusFirstElement: function(form) {
    var form = $(form);
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      if (element.type != 'hidden' && !element.disabled) {
        Field.activate(element);
        break;
      }
    }
  },

  reset: function(form) {
    $(form).reset();
  }
}

Form.Element = {
  serialize: function(element) {
    var element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);
    
    if (parameter)
      return encodeURIComponent(parameter[0]) + '=' + 
        encodeURIComponent(parameter[1]);                   
  },
  
  getValue: function(element) {
    var 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) {
    var value = '';
    if (element.type == 'select-one') {
      var index = element.selectedIndex;
      if (index >= 0)
        value = element.options[index].value || element.options[index].text;
    } else {
      value = new Array();
      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':
          element.target = this;
          element.prev_onclick = element.onclick || Prototype.emptyFunction;
          element.onclick = function() {
            this.prev_onclick(); 
            this.target.onElementEvent();
          }
          break;
        case 'password':
        case 'text':
        case 'textarea':
        case 'select-one':
        case 'select-multiple':
          element.target = this;
          element.prev_onchange = element.onchange || Prototype.emptyFunction;
          element.onchange = function() {
            this.prev_onchange(); 
            this.target.onElementEvent();
          }
          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;
    }
  },

  // 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(Event.observers[i][0],Event.observers[i][1],Event.observers[i][2],Event.observers[i][3]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;
    
    if (name == 'keypress') {
      if (navigator.appVersion.indexOf('AppleWebKit') > 0) {
        this._observeAndCache(element, 'keydown', observer, useCapture);
        return;
      }
      this._observeAndCache(element, 'keypress', observer, useCapture);
    } else {
      this._observeAndCache(element, name, observer, useCapture);
    }
  },

  stopObserving: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;
    
    if (name == 'keypress') {
      if (navigator.appVersion.indexOf('AppleWebKit') > 0) {
        element.removeEventListener('keydown', observer, useCapture);
        return;
      }
      if (element.removeEventListener) {
        element.removeEventListener('keypress', observer, useCapture);
      } else if (element.detachEvent) {
        element.detachEvent('onkeydown', observer);
      }
    } else {
      if (element.removeEventListener) {
        element.removeEventListener(name, observer, useCapture);
      } else if (element.detachEvent) {
        element.detachEvent('on' + name, observer);
      }
    }
  }
});

// prevent memory leaks
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];
  },

  // 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';
  }
}



/****** sortable.js ******/
addEvent(window, "load", sortables_init);

var SORT_COLUMN_INDEX;

function sortables_init() {
    // Find all tables with class sortable and make them sortable
    if (!document.getElementsByTagName) return;
    tbls = document.getElementsByTagName("table");
    for (ti=0;ti<tbls.length;ti++) {
        thisTbl = tbls[ti];
        if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) {
            //initTable(thisTbl.id);
            ts_makeSortable(thisTbl);
        }
    }
}

function ts_makeSortable(table) {
    if (table.rows && table.rows.length > 0) {
        var firstRow = table.rows[0];
    }
    if (!firstRow) return;
    
    // We have a first row: assume it's the header, and make its contents clickable links
    for (var i=0;i<firstRow.cells.length;i++) {
        var cell = firstRow.cells[i];
        var txt = ts_getInnerText(cell);
        cell.innerHTML = '<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;">'+txt+'<span class="sortarrow">&nbsp;&nbsp;&nbsp;</span></a>';
    }
}

function ts_getInnerText(el) {
	if (typeof el == "string") return el;
	if (typeof el == "undefined") { return el };
	if (el.innerText) return el.innerText;	//Not needed but it is faster
	var str = "";
	
	var cs = el.childNodes;
	var l = cs.length;
	for (var i = 0; i < l; i++) {
		switch (cs[i].nodeType) {
			case 1: //ELEMENT_NODE
				str += ts_getInnerText(cs[i]);
				break;
			case 3:	//TEXT_NODE
				str += cs[i].nodeValue;
				break;
		}
	}
	return str;
}

function ts_resortTable(lnk) {
    // get the span
    var span;
    for (var ci=0;ci<lnk.childNodes.length;ci++) {
        if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') span = lnk.childNodes[ci];
    }
    var spantext = ts_getInnerText(span);
    var td = lnk.parentNode;
    var column = td.cellIndex;
    var table = getParent(td,'TABLE');
    
    // Work out a type for the column
    if (table.rows.length <= 1) return;
    var itm = ts_getInnerText(table.rows[1].cells[column]);
    sortfn = ts_sort_caseinsensitive;
    if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) sortfn = ts_sort_date;
    if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) sortfn = ts_sort_date;
    if (itm.match(/^[£$€]/)) sortfn = ts_sort_currency;
    if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric;
    // hack DLY 04/09/2006 17:18 : force the sort type ( can not detect euros )
    sortfn = ts_sort_currency
    SORT_COLUMN_INDEX = column;
    var firstRow = new Array();
    var newRows = new Array();
    for (i=0;i<table.rows[0].length;i++) { firstRow[i] = table.rows[0][i]; }
    for (j=1;j<table.rows.length;j++) { newRows[j-1] = table.rows[j]; }

    newRows.sort(sortfn);

    if (span.getAttribute("sortdir") == 'down') {
        ARROW = '&nbsp;&nbsp;&uarr;';
        newRows.reverse();
        span.setAttribute('sortdir','up');
    } else {
        ARROW = '&nbsp;&nbsp;&darr;';
        span.setAttribute('sortdir','down');
    }
    
    // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
    // don't do sortbottom rows
    for (i=0;i<newRows.length;i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) table.tBodies[0].appendChild(newRows[i]);}
    // do sortbottom rows only
    for (i=0;i<newRows.length;i++) { if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) table.tBodies[0].appendChild(newRows[i]);}
    
    // Delete any other arrows there may be showing
    var allspans = document.getElementsByTagName("span");
    for (var ci=0;ci<allspans.length;ci++) {
        if (allspans[ci].className == 'sortarrow') {
            if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us?
                allspans[ci].innerHTML = '&nbsp;&nbsp;&nbsp;';
            }
        }
    }
    // hack DLY : highlight the first row after sort 12/09/2006 00:33
   	table.rows[1].className = 'offer-on first';
    span.innerHTML = ARROW;
}

function getParent(el, pTagName) {
	if (el == null) return null;
	else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())	// Gecko bug, supposed to be uppercase
		return el;
	else
		return getParent(el.parentNode, pTagName);
}
function ts_sort_date(a,b) {
    // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
    if (aa.length == 10) {
        dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
    } else {
        yr = aa.substr(6,2);
        if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
        dt1 = yr+aa.substr(3,2)+aa.substr(0,2);
    }
    if (bb.length == 10) {
        dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
    } else {
        yr = bb.substr(6,2);
        if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
        dt2 = yr+bb.substr(3,2)+bb.substr(0,2);
    }
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
}

function ts_sort_currency(a,b) { 
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
    // HACK DLY for N.C. values transformed in .. which are not valid numeric values 12/09/2006 01:15
    if (aa=='..') aa = '1000000';
    if (bb=='..') bb = '1000000';
    return parseFloat(aa) - parseFloat(bb);
}

function ts_sort_numeric(a,b) { 
    aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));
    if (isNaN(aa)) aa = 0;
    bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])); 
    if (isNaN(bb)) bb = 0;
    return aa-bb;
}

function ts_sort_caseinsensitive(a,b) {
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase();
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase();
    if (aa==bb) return 0;
    if (aa<bb) return -1;
    return 1;
}

function ts_sort_default(a,b) {
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
    if (aa==bb) return 0;
    if (aa<bb) return -1;
    return 1;
}


function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
{
  if (elm.addEventListener){
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent){
    var r = elm.attachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be removed");
  }
} 


/* Nifty Corners Cube - rounded corners with CSS and Javascript
Copyright 2006 Alessandro Fulciniti (a.fulciniti@html.it)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

var niftyOk=(document.getElementById && document.createElement && Array.prototype.push);
var niftyCss=false;

String.prototype.find=function(what){
return(this.indexOf(what)>=0 ? true : false);
}

var oldonload=window.onload;
if(typeof(NiftyLoad)!='function') NiftyLoad=function(){};
if(typeof(oldonload)=='function')
    window.onload=function(){oldonload();AddCss();NiftyLoad()};
else window.onload=function(){AddCss();NiftyLoad()};

function AddCss(){
return true;
// disabled DLY 28/09/2006 23:13
niftyCss=true;
var l=CreateEl("link");
l.setAttribute("type","text/css");
l.setAttribute("rel","stylesheet");
l.setAttribute("href","http://static.zlio.com/users.zlio.com/v3/css/niftyCorners.css");
l.setAttribute("media","screen");
document.getElementsByTagName("head")[0].appendChild(l);
}

function Nifty(selector,options){
if(niftyOk==false) return;
if(niftyCss==false) AddCss();
var i,v=selector.split(","),h=0;
if(options==null) options="";
if(options.find("fixed-height"))
    h=getElementsBySelector(v[0])[0].offsetHeight;
for(i=0;i<v.length;i++)
    Rounded(v[i],options);
if(options.find("height")) SameHeight(selector,h);
}

function Rounded(selector,options){
var i,top="",bottom="",v=new Array();
if(options!=""){
    options=options.replace("left","tl bl");
    options=options.replace("right","tr br");
    options=options.replace("top","tr tl");
    options=options.replace("bottom","br bl");
    options=options.replace("transparent","alias");
    if(options.find("tl")){
        top="both";
        if(!options.find("tr")) top="left";
        }
    else if(options.find("tr")) top="right";
    if(options.find("bl")){
        bottom="both";
        if(!options.find("br")) bottom="left";
        }
    else if(options.find("br")) bottom="right";
    }
if(top=="" && bottom=="" && !options.find("none")){top="both";bottom="both";}
v=getElementsBySelector(selector);
for(i=0;i<v.length;i++){
    FixIE(v[i]);
    if(top!="") AddTop(v[i],top,options);
    if(bottom!="") AddBottom(v[i],bottom,options);
    }
}

function AddTop(el,side,options){
var d=CreateEl("b"),lim=4,border="",p,i,btype="r",bk,color;
d.style.marginLeft="-"+getPadding(el,"Left")+"px";
d.style.marginRight="-"+getPadding(el,"Right")+"px";
if(options.find("alias") || (color=getBk(el))=="transparent"){
    color="transparent";bk="transparent"; border=getParentBk(el);btype="t";
    }
else{
    bk=getParentBk(el); border=Mix(color,bk);
    }
d.style.background=bk;
d.className="niftycorners";
p=getPadding(el,"Top");
if(options.find("small")){
    d.style.marginBottom=(p-2)+"px";
    btype+="s"; lim=2;
    }
else if(options.find("big")){
    d.style.marginBottom=(p-10)+"px";
    btype+="b"; lim=8;
    }
else d.style.marginBottom=(p-5)+"px";
for(i=1;i<=lim;i++)
    d.appendChild(CreateStrip(i,side,color,border,btype));
el.style.paddingTop="0";
el.insertBefore(d,el.firstChild);
}

function AddBottom(el,side,options){
var d=CreateEl("b"),lim=4,border="",p,i,btype="r",bk,color;
d.style.marginLeft="-"+getPadding(el,"Left")+"px";
d.style.marginRight="-"+getPadding(el,"Right")+"px";
if(options.find("alias") || (color=getBk(el))=="transparent"){
    color="transparent";bk="transparent"; border=getParentBk(el);btype="t";
    }
else{
    bk=getParentBk(el); border=Mix(color,bk);
    }
d.style.background=bk;
d.className="niftycorners";
p=getPadding(el,"Bottom");
if(options.find("small")){
    d.style.marginTop=(p-2)+"px";
    btype+="s"; lim=2;
    }
else if(options.find("big")){
    d.style.marginTop=(p-10)+"px";
    btype+="b"; lim=8;
    }
else d.style.marginTop=(p-5)+"px";
for(i=lim;i>0;i--)
    d.appendChild(CreateStrip(i,side,color,border,btype));
el.style.paddingBottom=0;
el.appendChild(d);
}

function CreateStrip(index,side,color,border,btype){
var x=CreateEl("b");
x.className=btype+index;
x.style.backgroundColor=color;
x.style.borderColor=border;
if(side=="left"){
    x.style.borderRightWidth="0";
    x.style.marginRight="0";
    }
else if(side=="right"){
    x.style.borderLeftWidth="0";
    x.style.marginLeft="0";
    }
return(x);
}

function CreateEl(x){
return(document.createElement(x));
}

function FixIE(el){
if(el.currentStyle!=null && el.currentStyle.hasLayout!=null && el.currentStyle.hasLayout==false)
    el.style.display="inline-block";
}

function SameHeight(selector,maxh){
var i,v=selector.split(","),t,j,els=[],gap;
for(i=0;i<v.length;i++){
    t=getElementsBySelector(v[i]);
    els=els.concat(t);
    }
for(i=0;i<els.length;i++){
    if(els[i].offsetHeight>maxh) maxh=els[i].offsetHeight;
    els[i].style.height="auto";
    }
for(i=0;i<els.length;i++){
    gap=maxh-els[i].offsetHeight;
    if(gap>0){
        t=CreateEl("b");t.className="niftyfill";t.style.height=gap+"px";
        nc=els[i].lastChild;
        if(nc.className=="niftycorners")
            els[i].insertBefore(t,nc);
        else els[i].appendChild(t);
        }
    }
}

function getElementsBySelector(selector){
var i,j,selid="",selclass="",tag=selector,tag2="",v2,k,f,a,s=[],objlist=[],c;
if(selector.find("#")){ //id selector like "tag#id"
    if(selector.find(" ")){  //descendant selector like "tag#id tag"
        s=selector.split(" ");
        var fs=s[0].split("#");
        if(fs.length==1) return(objlist);
        f=document.getElementById(fs[1]);
        if(f){
            v=f.getElementsByTagName(s[1]);
            for(i=0;i<v.length;i++) objlist.push(v[i]);
            }
        return(objlist);
        }
    else{
        s=selector.split("#");
        tag=s[0];
        selid=s[1];
        if(selid!=""){
            f=document.getElementById(selid);
            if(f) objlist.push(f);
            return(objlist);
            }
        }
    }
if(selector.find(".")){      //class selector like "tag.class"
    s=selector.split(".");
    tag=s[0];
    selclass=s[1];
    if(selclass.find(" ")){   //descendant selector like tag1.classname tag2
        s=selclass.split(" ");
        selclass=s[0];
        tag2=s[1];
        }
    }
var v=document.getElementsByTagName(tag);  // tag selector like "tag"
if(selclass==""){
    for(i=0;i<v.length;i++) objlist.push(v[i]);
    return(objlist);
    }
for(i=0;i<v.length;i++){
    c=v[i].className.split(" ");
    for(j=0;j<c.length;j++){
        if(c[j]==selclass){
            if(tag2=="") objlist.push(v[i]);
            else{
                v2=v[i].getElementsByTagName(tag2);
                for(k=0;k<v2.length;k++) objlist.push(v2[k]);
                }
            }
        }
    }
return(objlist);
}

function getParentBk(x){
var el=x.parentNode,c;
while(el.tagName.toUpperCase()!="HTML" && (c=getBk(el))=="transparent")
    el=el.parentNode;
if(c=="transparent") c="#FFFFFF";
return(c);
}

function getBk(x){
var c=getStyleProp(x,"backgroundColor");
if(c==null || c=="transparent" || c.find("rgba(0, 0, 0, 0)"))
    return("transparent");
if(c.find("rgb")) c=rgb2hex(c);
return(c);
}

function getPadding(x,side){
var p=getStyleProp(x,"padding"+side);
if(p==null || !p.find("px")) return(0);
return(parseInt(p));
}

function getStyleProp(x,prop){
if(x.currentStyle)
    return(x.currentStyle[prop]);
if(document.defaultView.getComputedStyle)
    return(document.defaultView.getComputedStyle(x,'')[prop]);
return(null);
}

function rgb2hex(value){
var hex="",v,h,i;
var regexp=/([0-9]+)[, ]+([0-9]+)[, ]+([0-9]+)/;
var h=regexp.exec(value);
for(i=1;i<4;i++){
    v=parseInt(h[i]).toString(16);
    if(v.length==1) hex+="0"+v;
    else hex+=v;
    }
return("#"+hex);
}

function Mix(c1,c2){
var i,step1,step2,x,y,r=new Array(3);
if(c1.length==4)step1=1;
else step1=2;
if(c2.length==4) step2=1;
else step2=2;
for(i=0;i<3;i++){
    x=parseInt(c1.substr(1+step1*i,step1),16);
    if(step1==1) x=16*x+x;
    y=parseInt(c2.substr(1+step2*i,step2),16);
    if(step2==1) y=16*y+y;
    r[i]=Math.floor((x*50+y*50)/100);
    r[i]=r[i].toString(16);
    if(r[i].length==1) r[i]="0"+r[i];
    }
return("#"+r[0]+r[1]+r[2]);
}



/***** greybox,js ******/
/****
 Last Modified: 23/06/06 01:24:34

 GreyBox - Smart pop-up window
   Copyright Amir Salihefendic 2006
 AUTHOR
   4mir Salihefendic (http://amix.dk) - amix@amix.dk
 VERSION
	 3.2
 LICENSE
  GPL (read more in GPL.txt)
 SITE
  http://orangoo.com/labs/GreyBox/
****/
var GB_CURRENT = null;
var GB_ONLY_ONE = null;

function GreyBox() {
  //Use mutator functions (since the internal stuff may change in the future)
  this.type = "page";
  this.overlay_click_close = true;
  this.img_dir = "greybox/";
  this.overlay_color = "dark";

  this.center_window = false;

  this.g_window = null;
  this.g_container = null;
  this.iframe = null;
  this.overlay = null;
  this.timeout = null;

  this.defaultSize();

  this.url = "";
  this.caption = "";
}

////
// Configuration functions (the functions you can call)
////
/**
  Set the width and height of the GreyBox window.
  Images and notifications are auto-set.
  **/
GreyBox.prototype.setDimension = function(width, height) {
  this.height = height;
  this.width = width;
}

GreyBox.prototype.setFullScreen = function(bool) {
  this.full_screen = bool;
}

/**
  Type can be: page, image
  **/
GreyBox.prototype.setType = function(type) {
  this.type = type;
}

/**
  If bool is true the window will be centered vertically also
  **/
GreyBox.prototype.setCenterWindow = function(bool) {
  this.center_window = bool;
}

/**
  Set the path where images can be found.
  Can be relative: greybox/
  Or absolute: http://yoursite.com/greybox/
  **/
GreyBox.prototype.setImageDir = function(dir) {
  this.img_dir = dir;
}

/**
  If bool is true the grey overlay click will close greybox.
  **/
GreyBox.prototype.setOverlayCloseClick = function(bool) {
  this.overlay_click_close = bool;
}

/**
  Overlay can either be "light" or "dark".
  **/
GreyBox.prototype.setOverlayColor = function(color) {
  this.overlay_color = color;
}

/**
  Set a function that will be called when GreyBox closes
  **/
GreyBox.prototype.setCallback = function(fn) {
  this.callback_fn = fn;
}


////
// Show hide functions
////
/**
  Show the GreyBox with a caption and an url
  **/
GreyBox.prototype.show = function(caption, url) {
  GB_CURRENT = this;

  this.url = url;
  this.caption = caption;

  //Be sure that the old loader and dummy_holder are removed
  AJS.map(AJS.$bytc("div", "GB_dummy"), function(elm) { AJS.removeElement(elm) });
  AJS.map(AJS.$bytc("div", "GB_loader"), function(elm) { AJS.removeElement(elm) });
  
  //If ie, hide select, in others hide flash
  if(AJS.isIe())
    AJS.map(AJS.$bytc("select"), function(elm) {elm.style.visibility = "hidden"});
  AJS.map(AJS.$bytc("object"), function(elm) {elm.style.visibility = "hidden"});

  this.initOverlayIfNeeded();
  
  this.setOverlayDimension();
  AJS.showElement(this.overlay);
  this.setFullScreenOption();

  this.initIfNeeded();

  AJS.hideElement(this.g_window);

  if(this.type == "page")
    AJS.ACN(this.g_container, this.iframe);
  else {
    this.dummy_holder = AJS.DIV({'class': 'GB_dummy', 'style': 'width: 200px; height: 200px; background-color: #fff;'});
    AJS.ACN(this.g_container, this.dummy_holder);
  }

  if(caption == "")
    caption = "&nbsp;";
  this.div_caption.innerHTML = caption;

  AJS.showElement(this.g_window)

  this.setVerticalPosition();
  this.setTopNLeft();
  this.setWidthNHeight();


  this.showLoader();

  GB_CURRENT.startLoading();

  return false;
}

GreyBox.prototype.hide = function() {
  AJS.hideElement(this.g_window, this.overlay);

  try{ AJS.removeElement(this.iframe); }
  catch(e) {}

  this.iframe = null;

  if(this.type == "image") {
    this.width = 200;
    this.height = 200;
  }

  if(AJS.isIe()) 
    AJS.map(AJS.$bytc("select"), function(elm) {elm.style.visibility = "visible"});
  AJS.map(AJS.$bytc("object"), function(elm) {elm.style.visibility = "visible"});

  if(GB_CURRENT.callback_fn)
    GB_CURRENT.callback_fn();

  GB_CURRENT = null;
}

/** 
  If you only use one instance of GreyBox
  **/
GB_initOneIfNeeded = function() {
  if(!GB_ONLY_ONE) {
    GB_ONLY_ONE = new GreyBox();
    GB_ONLY_ONE.setImageDir(GB_IMG_DIR);
  }
}

GB_show = function(caption, url, /* optional */ height, width, callback_fn) {
  GB_ONLY_ONE.defaultSize();
  GB_ONLY_ONE.setFullScreen(false);
  GB_ONLY_ONE.setType("page");

  GB_ONLY_ONE.setCallback(callback_fn);
  GB_ONLY_ONE.setImageDir(GB_IMG_DIR);
  GB_ONLY_ONE.setDimension(width, height);
  GB_ONLY_ONE.show(caption, url);
  return false;
}

GB_showFullScreen = function(caption, url, /* optional */ callback_fn) {
  GB_ONLY_ONE.defaultSize();
  GB_ONLY_ONE.setType("page");

  GB_ONLY_ONE.setCallback(callback_fn);
  GB_ONLY_ONE.setImageDir(GB_IMG_DIR);
  GB_ONLY_ONE.setFullScreen(true);
  GB_ONLY_ONE.show(caption, url);
  return false;
}

GB_showImage = function(caption, url) {
  GB_ONLY_ONE.defaultSize();
  GB_ONLY_ONE.setFullScreen(false);
  GB_ONLY_ONE.setType("image");

  GB_ONLY_ONE.setImageDir(GB_IMG_DIR);
  GB_ONLY_ONE.show(caption, url);
  return false;
}

GB_hide = function() {
  GB_CURRENT.hide();
}

/**
  Preload all the images used by GreyBox. Static function
  **/
GreyBox.preloadGreyBoxImages = function() {
  var pics = [];
  var fn = function(path) { 
    var pic = new Image();
    pic.src = GB_IMG_DIR + path;
    pics.push(pic);
  };
  AJS.map(['indicator.gif', 'blank.gif', 'close.gif', 'header_bg.gif', 'overlay_light.png', 'overlay_dark.png'], AJS.$b(fn, this));
}


////
// Internal functions
////
GreyBox.prototype.getOverlayImage = function() {
  return "overlay_" + this.overlay_color + ".png";
};

/**
  Init functions
  **/
GreyBox.prototype.initOverlayIfNeeded = function() {
  //Create the overlay
  this.overlay = AJS.DIV({'id': 'GB_overlay'});
  if(AJS.isIe()) {
    this.overlay.style.backgroundColor = "#000000";
    this.overlay.style.backgroundColor = "transparent";
    this.overlay.style.backgroundImage = "url("+ this.img_dir +"blank.gif)";
    this.overlay.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.img_dir + this.getOverlayImage() + "',sizingMethod='scale')";
  }
  else 
    this.overlay.style.backgroundImage = "url("+ this.img_dir + this.getOverlayImage() +")";

  if(this.overlay_click_close)
    AJS.AEV(this.overlay, "click", GB_hide);

  AJS.getBody().insertBefore(this.overlay, AJS.getBody().firstChild);
};

GreyBox.prototype.initIfNeeded = function() {
  this.init();
  this.setWidthNHeight = AJS.$b(this.setWidthNHeight, this);
  this.setTopNLeft = AJS.$b(this.setTopNLeft, this);
  this.setFullScreenOption = AJS.$b(this.setFullScreenOption, this);
  this.setOverlayDimension = AJS.$b(this.setOverlayDimension, this);

  GreyBox.addOnWinResize(this.setWidthNHeight, this.setTopNLeft, this.setFullScreenOption, this.setOverlayDimension);

  if(this.type == "page")
    this.g_container.style.marginBottom = "-3px";

  var fn = function() { 
    this.setOverlayDimension();
    this.setVerticalPosition(); 
    this.setTopNLeft();
    this.setWidthNHeight(); 
  };
  AJS.AEV(window, "scroll", AJS.$b(fn, this));

  if(!this.iframe) {
    var new_frame;
    var d = {'name': 'GB_frame', 'class': 'GB_frame', 'frameBorder': 0};
    if(this.type == "page") {
      new_frame = AJS.IFRAME(d);
      AJS.hideElement(new_frame);
    }
    else
     new_frame = new Image();

    this.iframe = new_frame;
  }
}

GreyBox.prototype.init = function() {
  //Create the window
  this.g_window = AJS.DIV({'id': 'GB_window'});

  //Create the table structure
  var table = AJS.TABLE({'class': 'GB_t_frame', 'frameborder': 0});
  var tbody = AJS.TBODY();
  AJS.ACN(table, tbody);

  //Midlle
  var td_middle_m = AJS.TD({'class': 'GB_content'});
  this.td_middle_m = td_middle_m;

  AJS.ACN(tbody, AJS.TR(td_middle_m));

  //Append caption and close
  var header = AJS.DIV({'class': 'GB_header'});
  this.header = header;

  var caption = AJS.DIV({'class': 'GB_caption'});
  this.div_caption = caption;

  var img_close = AJS.IMG({'src': this.img_dir + 'close.png'});
  var close = AJS.DIV({'class': 'GB_close'}, img_close, ""); //DLY Close non i18ned

  AJS.AEV(close, "click", GB_hide);

  header.style.backgroundImage = "url("+ this.img_dir +"header_bg_red.gif)";

  var dummy = AJS.SPAN();
  dummy.innerHTML = "&nbsp;";
  AJS.ACN(header, close, caption, dummy);
  AJS.ACN(td_middle_m, header);

  //Container
  this.g_container = AJS.DIV({'class': 'GB_container'});
  AJS.ACN(td_middle_m, this.g_container);

  AJS.ACN(this.g_window, table);

  AJS.getBody().insertBefore(this.g_window, this.overlay.nextSibling);
}

GreyBox.prototype.startLoading = function() {
  //Start preloading the object
  this.iframe.src = this.url;

  if(AJS.isIe()) {
    //IE the stupid bitch - needs custom code for this ARGH
    var check_state = function() {
      if(this.iframe.readyState == "complete")
        GreyBox.loaded();
      else
        AJS.callLater(AJS.$b(check_state, this), 30);
    };
    AJS.callLater(AJS.$b(check_state, this), 30);
  }
  //Safari AND opera has a bug with onload.. bah
  else if(AJS.isSafari() || AJS.isOpera() && this.type == "image") {
    AJS.callLater(GreyBox.loaded, 250);
  }
  else {
    this.iframe.onload = GreyBox.loaded;
  }
}

/**
  Loading functions
  **/
GreyBox.loaded = function() {
  var me = GB_CURRENT;

  if(me) {
    AJS.removeElement(me.loader);

    if(me.type == "page") {
      AJS.showElement(me.iframe);
      me.setIframeWidthNHeight();
    }

    if(me.type == "image") {
      var r_img = AJS.IMG({'src': me.url});

      var insert = function() {
        AJS.ACN(GB_CURRENT.g_container, r_img);
        GB_CURRENT.iframe = r_img;
      };
      var count = 0;

      var fn = function() {
        if(count > 10)
          return;
        this.width = this.iframe.width;
        this.height = this.iframe.height;

        if(this.width == 0 || this.height == 0) {
          count++;
          AJS.callLater(AJS.$b(fn, me), 100);
          return;
        }

        //Safari render bugfix
        if(AJS.isSafari())
          this.overlay.style.backgroundColor = "transparent";

        this.setTopNLeft();
        this.setWidthNHeight();
        AJS.removeElement(this.dummy_holder);

        AJS.callLater(AJS.$b(insert, me), 50);

        count++;
      };
      AJS.callLater(AJS.$b(fn, me), 100);
    }
  }
}

GreyBox.prototype.showLoader = function() {
  this.loader = AJS.DIV({'class': 'GB_loader'});
  
  AJS.setWidth(this.loader, this.width);
  AJS.setHeight(this.loader, this.height-3);

  var indicator = AJS.IMG({'src': this.img_dir + 'indicator.gif'});
  AJS.ACN(this.loader, AJS.BR(), indicator, AJS.BR(), AJS.BR(), AJS.SPAN("LOADING..."));

  if(this.type != "page") {
    AJS.RCN(this.dummy_holder, this.loader);
    AJS.setTop(this.loader, AJS.absolutePosition(this.dummy_holder).y);
  }
  else {
    AJS.ACN(this.g_container, this.loader);
    AJS.setTop(this.loader, AJS.absolutePosition(this.iframe).y);
    AJS.showElement(this.loader);
  }
}

/**
  Set dimension functions
  **/
GreyBox.prototype.setIframeWidthNHeight = function() {
  try{
    AJS.setWidth(this.iframe, this.width);
    AJS.setHeight(this.iframe, this.height-3);
  }
  catch(e) {
  }
}

GreyBox.prototype.setOverlayDimension = function() {
  var array_page_size = GreyBox.getWindowSize();
  if((navigator.userAgent.toLowerCase().indexOf("firefox") != -1))
   AJS.setWidth(this.overlay, "100%");
  else
   AJS.setWidth(this.overlay, array_page_size[0]);

  var max_height = Math.max(AJS.getScrollTop()+array_page_size[1], AJS.getScrollTop()+this.height);
  if(max_height < AJS.getScrollTop())
    AJS.setHeight(this.overlay, max_height);
  else
    AJS.setHeight(this.overlay, AJS.getScrollTop()+array_page_size[1]);
}

GreyBox.prototype.setWidthNHeight = function() {
  //Set size
  AJS.setWidth(this.g_window, this.width);
  AJS.setHeight(this.g_window, this.height);

  AJS.setWidth(this.g_container, this.width);
  AJS.setHeight(this.g_container, this.height);

  if(this.type == "page")
    this.setIframeWidthNHeight();

  //Set size on components
  AJS.setWidth(this.td_middle_m, this.width+10);
}

GreyBox.prototype.setTopNLeft = function() {
  var array_page_size = GreyBox.getWindowSize();
  AJS.setLeft(this.g_window, ((array_page_size[0] - this.width)/2)-13);

  if(this.center_window) {
    var fl = ((array_page_size[1] - this.height) /2) - 15;
    AJS.setTop(this.g_window, fl);
  }
  else {
    if(this.g_window.offsetHeight < array_page_size[1])
      AJS.setTop(this.g_window, AJS.getScrollTop());
  }
}

GreyBox.prototype.setVerticalPosition = function() {
  var array_page_size = GreyBox.getWindowSize();
  var st = AJS.getScrollTop();
  if(this.g_window.offsetWidth <= array_page_size[1] || st <= this.g_window.offsetTop) {
    AJS.setTop(this.g_window, st);
  }
}

GreyBox.prototype.setFullScreenOption = function() {
  if(this.full_screen) {
    var array_page_size = GreyBox.getWindowSize();

    overlay_h = array_page_size[1];

    this.width = Math.round(this.overlay.offsetWidth - (this.overlay.offsetWidth/100)*10);
    this.height = Math.round(overlay_h - (overlay_h/100)*10);
  }
}

GreyBox.prototype.defaultSize = function() {
  this.width = 300;
  this.height = 300;
}

////
// Misc.
////
GreyBox.getWindowSize = function() {
	var window_width, window_height;
	if (self.innerHeight) {	
		window_width = self.innerWidth;
		window_height = self.innerHeight;
	} else if (document.documentElement && document.documentElement.clientHeight) { 
		window_width = document.documentElement.clientWidth;
		window_height = document.documentElement.clientHeight;
	} else if (document.body) { 
		window_width = document.body.clientWidth;
		window_height = document.body.clientHeight;
	}	
	return [window_width, window_height];
}

GreyBox.addOnWinResize = function(funcs) {
  funcs = AJS.$A(funcs);
  AJS.map(funcs, function(fn) { AJS.AEV(window, "resize", fn); });
}

GB_ONLY_ONE = new GreyBox();


/*** Ami.js *****/
/*
Last Modified: 22/06/06 23:28:14

  AmiJs library
    A very small library with DOM and Ajax functions.
    For a much larger script look on http://www.mochikit.com/
  AUTHOR
    4mir Salihefendic (http://amix.dk) - amix@amix.dk
  LICENSE
    Copyright (c) 2006 Amir Salihefendic. All rights reserved.
    Copyright (c) 2005 Bob Ippolito. All rights reserved.
    http://www.opensource.org/licenses/mit-license.php
  VERSION
    2.91
  SITE
    http://amix.dk/projects/AmiJS
**/

var AJS = {
  BASE_URL: "",

////
// Accessor functions
////
  //Shortcut: AJS.$
  getElement: function(id) {
    if(typeof(id) == "string") 
      return document.getElementById(id);
    else
      return id;
  },

  //Shortcut: AJS.$$
  getElements: function(/*id1, id2, id3*/) {
    var elements = new Array();
      for (var i = 0; i < arguments.length; i++) {
        var element = this.getElement(arguments[i]);
        elements.push(element);
      }
      return elements;
  },

  getQueryArgument: function(var_name) {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (var i=0;i<vars.length;i++) {
      var pair = vars[i].split("=");
      if (pair[0] == var_name) {
        return pair[1];
      }
    }
    return null;
  },

  isIe: function() {
    return (navigator.userAgent.toLowerCase().indexOf("msie") != -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1);
  },
  isNetscape7: function() {
    return (navigator.userAgent.toLowerCase().indexOf("netscape") != -1 && navigator.userAgent.toLowerCase().indexOf("7.") != -1);
  },
  isSafari: function() {
    return (navigator.userAgent.toLowerCase().indexOf("khtml") != -1);
  },
  isOpera: function() {
    return (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
  },
  isMozilla: function() {
    return (navigator.userAgent.toLowerCase().indexOf("gecko") != -1 && navigator.productSub >= 20030210);
  },

  getBody: function() {
    return this.getElementsByTagAndClassName('body')[0] 
  },

  //Shortcut: AJS.$bytc
  getElementsByTagAndClassName: function(tag_name, class_name, /*optional*/ parent) {
    var class_elements = [];
    if(!this.isDefined(parent))
      parent = document;
    if(!this.isDefined(tag_name))
      tag_name = '*';

    var els = parent.getElementsByTagName(tag_name);
    var els_len = els.length;
    var pattern = new RegExp("(^|\\s)" + class_name + "(\\s|$)");

    for (i = 0, j = 0; i < els_len; i++) {
      if ( pattern.test(els[i].className) || class_name == null ) {
        class_elements[j] = els[i];
        j++;
      }
    }
    return class_elements;
  },

  nodeName: function(elm) {
    return elm.nodeName.toLowerCase();
  },

  isElementHidden: function(elm) {
    return elm.style.visibility == "hidden";
  },

  getLast: function(list) {
    if(list.length > 0)
      return list[list.length-1];
    else
      return null;
  },

  getFirst: function(list) {
    if(list.length > 0)
      return list[0];
    else
      return null;
  },


////
// Array functions
////
  //Shortcut: AJS.$A
  createArray: function(v) {
    if(this.isArray(v))
      return v;
    else if(!v)
      return [];
    else
      return [v];
  },

  map: function(list, fn,/*optional*/ start_index, end_index) {
    var i = 0, l = list.length;
    if(start_index)
       i = start_index;
    if(end_index)
       l = end_index;
    //From a mapped function this means AmiJS
    for(i; i < l; i++)
      fn.apply(this, [list[i]]);
  },

  isIn: function(str, list) {
    var ein = false;
    var fn = function(elm) {
      if(str == elm)
        ein = true;
    };
    this.map(list, fn);
    return ein;
  },


////
// DOM manipulation
////
  //Shortcut: AJS.ACN
  appendChildNodes: function(node/*, nodes...*/) {
    if(arguments.length >= 2) {
      AJS.map(arguments, function(n) { 
        if(this.isString(n))
          n = this.TN(n);
        if(this.isDefined(n))
          node.appendChild(n);
      }, 1);
    }
    return node;
  },

  //Shortcut: AJS.RCN
  replaceChildNodes: function(node/*, nodes...*/) {
    var child;
    while ((child = node.firstChild)) 
      node.removeChild(child);
    if (arguments.length < 2)
      return node;
    else
      return this.appendChildNodes.apply(this, arguments);
    return node;
  },

  insertAfter: function(node, referenceNode) {
    referenceNode.parentNode.insertBefore(node, referenceNode.nextSibling);
    return node;
  },
  
  insertBefore: function(node, referenceNode) {
    referenceNode.parentNode.insertBefore(node, referenceNode);
    return node;
  },
  
  showElement: function(/*elms...*/) {
    this.map(arguments, function(elm) { elm.style.display = ''});
  },
  
  hideElement: function(elm) {
    this.map(arguments, function(elm) { elm.style.display = 'none'});
  },
  
  swapDOM: function(dest, src) {
    dest = this.getElement(dest);
    var parent = dest.parentNode;
    if (src) {
      src = this.getElement(src);
      parent.replaceChild(src, dest);
    } else {
      parent.removeChild(dest);
    }
    return src;
  },

  removeElement: function(/*elm1, elm2...*/) {
    this.map(arguments, function(elm) { AJS.swapDOM(elm, null); });
  },

  createDOM: function(name, attrs) {
    var i=0, attr;
    elm = document.createElement(name);

    if(this.isDict(attrs[i])) {
      for(k in attrs[0]) {
        if(k == "style")
          elm.style.cssText = attrs[0][k];
        else if(k == "class")
          elm.className = attrs[0][k];
        else {
          attr = attrs[0][k];
          elm.setAttribute(k, attr);
        }
      }
      i++;
    }

    if(attrs[0] == null)
      i = 1;

    AJS.map(attrs, function(n) {
      if(this.isDefined(n)) {
        if(this.isString(n))
          n = this.TN(n);
        elm.appendChild(n);
      }
    }, i);
    return elm;
  },

  UL: function() { return this.createDOM.apply(this, ["ul", arguments]); },
  LI: function() { return this.createDOM.apply(this, ["li", arguments]); },
  TD: function() { return this.createDOM.apply(this, ["td", arguments]); },
  TR: function() { return this.createDOM.apply(this, ["tr", arguments]); },
  TH: function() { return this.createDOM.apply(this, ["th", arguments]); },
  TBODY: function() { return this.createDOM.apply(this, ["tbody", arguments]); },
  TABLE: function() { return this.createDOM.apply(this, ["table", arguments]); },
  INPUT: function() { return this.createDOM.apply(this, ["input", arguments]); },
  SPAN: function() { return this.createDOM.apply(this, ["span", arguments]); },
  B: function() { return this.createDOM.apply(this, ["b", arguments]); },
  A: function() { return this.createDOM.apply(this, ["a", arguments]); },
  DIV: function() { return this.createDOM.apply(this, ["div", arguments]); },
  IMG: function() { return this.createDOM.apply(this, ["img", arguments]); },
  BUTTON: function() { return this.createDOM.apply(this, ["button", arguments]); },
  H1: function() { return this.createDOM.apply(this, ["h1", arguments]); },
  H2: function() { return this.createDOM.apply(this, ["h2", arguments]); },
  H3: function() { return this.createDOM.apply(this, ["h3", arguments]); },
  BR: function() { return this.createDOM.apply(this, ["br", arguments]); },
  TEXTAREA: function() { return this.createDOM.apply(this, ["textarea", arguments]); },
  FORM: function() { return this.createDOM.apply(this, ["form", arguments]); },
  P: function() { return this.createDOM.apply(this, ["p", arguments]); },
  SELECT: function() { return this.createDOM.apply(this, ["select", arguments]); },
  OPTION: function() { return this.createDOM.apply(this, ["option", arguments]); },
  TN: function(text) { return document.createTextNode(text); },
  IFRAME: function() { return this.createDOM.apply(this, ["iframe", arguments]); },
  SCRIPT: function() { return this.createDOM.apply(this, ["script", arguments]); },
  CENTER: function() { return this.createDOM.apply(this, ["center", arguments]); },

  getCssDim: function(dim) {
    if(this.isString(dim))
      return dim;
    else
      return dim + "px";
  },

  setWidth: function(/*elm1, elm2..., width*/) {
    var w = this.getLast(arguments);
    this.map(arguments, function(elm) { elm.style.width = this.getCssDim(w)}, 0, arguments.length-1);
  }, 
  setHeight: function(/*elm1, elm2..., height*/) {
    var h = this.getLast(arguments);
    this.map(arguments, function(elm) { elm.style.height = this.getCssDim(h)}, 0, arguments.length-1);
  }, 
  setLeft: function(/*elm1, elm2..., left*/) {
    var l = this.getLast(arguments);
    this.map(arguments, function(elm) { elm.style.left = this.getCssDim(l)}, 0, arguments.length-1);
  }, 
  setTop: function(/*elm1, elm2..., top*/) {
    var t = this.getLast(arguments);
    this.map(arguments, function(elm) { elm.style.top = this.getCssDim(t)}, 0, arguments.length-1);
  }, 

////
// Ajax functions
////
  getXMLHttpRequest: function() {
    var try_these = [
      function () { return new XMLHttpRequest(); },
      function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
      function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
      function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
      function () { throw "Browser does not support XMLHttpRequest"; }
    ];
    for (var i = 0; i < try_these.length; i++) {
      var func = try_these[i];
      try {
        return func();
      } catch (e) {
      }
    }
  },
  
  doSimpleXMLHttpRequest: function(url) {
    var req = this.getXMLHttpRequest();
    if(url.indexOf("http://") == -1)
      url = AJS.BASE_URL + url;
    req.open("GET", url, true);
    return this.sendXMLHttpRequest(req);
  },

  getRequest: function(url, data) {
    var req = this.getXMLHttpRequest();
    if(url.indexOf("http://") == -1)
      url = AJS.BASE_URL + url;
    req.open("POST", url, true);
    req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    return this.sendXMLHttpRequest(req);
  },

  sendXMLHttpRequest: function(req, data) {
    var d = new AJSDeferred(req);

    var onreadystatechange = function () {
      if (req.readyState == 4) {
        try {
          status = req.status;
        }
        catch(e) {};
        if(status == 200 || status == 304 || req.responseText == null) {
          d.callback(req, data);
        }
        else {
          d.errback();
        }
      }
    }
    req.onreadystatechange = onreadystatechange;
    return d;
  },
  
  reprString: function(o) {
    return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
    ).replace(/[\f]/g, "\\f"
    ).replace(/[\b]/g, "\\b"
    ).replace(/[\n]/g, "\\n"
    ).replace(/[\t]/g, "\\t"
    ).replace(/[\r]/g, "\\r");
  },
  
  serializeJSON: function(o) {
    var objtype = typeof(o);
    if (objtype == "undefined") {
      return "undefined";
    } else if (objtype == "number" || objtype == "boolean") {
      return o + "";
    } else if (o === null) {
      return "null";
    }
    if (objtype == "string") {
      return AJS.reprString(o);
    }
    var me = arguments.callee;
    var newObj;
    if (typeof(o.__json__) == "function") {
      newObj = o.__json__();
      if (o !== newObj) {
        return me(newObj);
      }
    }
    if (typeof(o.json) == "function") {
      newObj = o.json();
      if (o !== newObj) {
        return me(newObj);
      }
    }
    if (objtype != "function" && typeof(o.length) == "number") {
      var res = [];
      for (var i = 0; i < o.length; i++) {
        var val = me(o[i]);
        if (typeof(val) != "string") {
          val = "undefined";
        }
        res.push(val);
      }
      return "[" + res.join(",") + "]";
    }
    res = [];
    for (var k in o) {
      var useKey;
      if (typeof(k) == "number") {
        useKey = '"' + k + '"';
      } else if (typeof(k) == "string") {
        useKey = AJS.reprString(k);
      } else {
        // skip non-string or number keys
        continue;
      }
      val = me(o[k]);
      if (typeof(val) != "string") {
        // skip non-serializable values
        continue;
      }
      res.push(useKey + ":" + val);
    }
    return "{" + res.join(",") + "}";
  },

  loadJSONDoc: function(url) {
    var d = this.getRequest(url);
    var eval_req = function(req) {
      var text = req.responseText;
      if(text == "Error")
        d.errback(req);
      else
        return eval('(' + text + ')');
    };
    d.addCallback(eval_req);
    return d;
  },

  evalScriptTags: function(html) {
    var script_data = html.match(/<script.*?>((\n|\r|.)*?)<\/script>/g);
    if(script_data != null) {
      for(var i=0; i < script_data.length; i++) {
        var script_only = script_data[i].replace(/<script.*?>/g, "");
        script_only = script_only.replace(/<\/script>/g, "");
        eval(script_only);
      }
    }
  },
  
  
////
// Position
////
  getMousePos: function(e) {
    var posx = 0;
    var posy = 0;
    if (!e) var e = window.event;
    if (e.pageX || e.pageY)
    {
      posx = e.pageX;
      posy = e.pageY;
    }
    else if (e.clientX || e.clientY)
    {
      posx = e.clientX + document.body.scrollLeft;
      posy = e.clientY + document.body.scrollTop;
    }
    return [posx, posy];
  },

  findPosX: function(obj) {
    var curleft = 0;
    if (obj.offsetParent) {
      while (obj.offsetParent) {
        curleft += obj.offsetLeft
        obj = obj.offsetParent;
      }
    }
    else if (obj.x)
      curleft += obj.x;
    return curleft;
  },

  findPosY: function(obj) {
    var curtop = 0;
    if (obj.offsetParent) {
      while (obj.offsetParent) {
        curtop += obj.offsetTop
        obj = obj.offsetParent;
      }
    }
    else if (obj.y)
      curtop += obj.y;
    return curtop;
  },

  getScrollTop: function() {
    //From: http://www.quirksmode.org/js/doctypes.html
    var t;
    if (document.documentElement && document.documentElement.scrollTop)
        t = document.documentElement.scrollTop;
    else if (document.body)
        t = document.body.scrollTop;
    return t;
  },

  absolutePosition: function(elm) {
    var posObj = {'x': elm.offsetLeft, 'y': elm.offsetTop};
    if(elm.offsetParent) {
      var temp_pos =	this.absolutePosition(elm.offsetParent);
      posObj.x += temp_pos.x;
      posObj.y += temp_pos.y;
    }
    return posObj;
  },


////
// Events
////
  getEventElm: function(e) {
    if(e && !e.type && !e.keyCode)
      return e
    var targ;
    if (!e) var e = window.event;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) // defeat Safari bug
      targ = targ.parentNode;
    return targ;
  },

  //Shortcut: AJS.GRS
  getRealScope: function(fn, /*optional*/ extra_args, dont_send_event) {
    var scope = window;
    extra_args = this.$A(extra_args);
    if(fn._cscope)
      scope = fn._cscope;

    return function() {
      //Append all the orginal arguments + extra_args
      var args = [];
      var i = 0;
      if(dont_send_event)
        i = 1;

      AJS.map(arguments, function(arg) { args.push(arg) }, i);
      args = args.concat(extra_args);
      return fn.apply(scope, args);
    };
  },

  unloadListeners: function() {
    if(AJS.listeners)
      AJS.map(AJS.listeners, function(elm, type, fn) {AJS.removeEventListener(elm, type, fn)});
    AJS.listeners = [];
  },

  //Shortcut: AJS.REV
  removeEventListener: function(elm, type, fn) {
    if(elm.removeEventListener)
      elm.removeEventListener(type, fn, false);
    else if(elm.detachEvent)
      elm.detachEvent("on" + type, fn);
  },

  //Shortcut: AJS.AEV
  addEventListener: function(elm, type, fn, listen_once) {
    var elms = this.$A(elm);
    this.map(elms, function(elmz) {
      if(listen_once) 
        fn = this.listenOnce(elmz, type, fn);

      if(AJS.isIn(type, ['submit', 'load', 'scroll', 'resize'])) {
        var old = elm['on' + type];
        elm['on' + type] = function() {
          if(old) {
            fn(arguments);
            return old(arguments);
          }
          else
            return fn(arguments);
        };
        return;
      }
      if (elmz.attachEvent)
        elmz.attachEvent("on" + type, fn);
      else if(elmz.addEventListener)
        elmz.addEventListener(type, fn, false);

      this.listeners = AJS.$A(this.listeners);
      this.listeners.push([elmz, type, fn]);
    });
  },

  //Shortcut: AJS.$b
  bind: function(fn, bind_to, /*optional*/ extra_args, dont_send_event) {
    fn._cscope = bind_to;
    return AJS.GRS(fn, extra_args, dont_send_event);
  },

  listenOnce: function(elm, type, fn) {
    var r_fn = function() { 
      AJS.removeEventListener(elm, type, r_fn);
      fn(arguments);
    }
    return r_fn;
  },

  callLater: function(fn, interval) { 
    var fn_no_send = function() {
      fn();
    };
    window.setTimeout(fn_no_send, interval); 
  },


////
// Effects
////

////
// Misc.
////
  keys: function(obj) {
    var rval = [];
    for (var prop in obj) {
      rval.push(prop);
    }
    return rval;
  },

  urlencode: function(str) {
    return encodeURIComponent(str.toString());
  },

  isDefined: function(o) {
    return (o != "undefined" && o != null)
  },
  
  isArray: function(obj) {
    try { 
      if(this.isDefined(obj[0]))
        return true;
      else
        return false;
    }
    catch(e){ 
      return false; 
    }
  },

  isString: function(obj) {
    return (typeof obj == 'string'); 
  },

  isObject: function(obj) {
    return (typeof obj == 'object');
  },

  isDict: function(o) {
    var str_repr = String(o);
    return str_repr.indexOf(" Object") != -1;
  },

  exportToGlobalScope: function() {
    for(e in AJS)
      eval(e + " = this." + e);
  }
}

//Shortcuts
AJS.$ = AJS.getElement;
AJS.$$ = AJS.getElement;
AJS.$b = AJS.bind;
AJS.$A = AJS.createArray;
AJS.ACN = AJS.appendChildNodes;
AJS.RCN = AJS.replaceChildNodes;
AJS.AEV = AJS.addEventListener;
AJS.REV = AJS.removeEventListener;
AJS.GRS = AJS.getRealScope;
AJS.$bytc = AJS.getElementsByTagAndClassName;

AJSDeferred = function(req) {
  this.callbacks = [];
  this.req = req;

  this.callback = function (res) {
    while (this.callbacks.length > 0) {
      var fn = this.callbacks.pop();
      res = fn(res);
    }
  };

  this.errback = function(e){
    alert("Error encountered:\n" + e);
  };

  this.addErrback = function(fn) {
    this.errback = fn;
  };

  this.addCallback = function(fn) {
    this.callbacks.unshift(fn);
  };

  this.addCallbacks = function(fn1, fn2) {
    this.addCallback(fn1);
    this.addErrback(fn2);
  };

  this.sendReq = function(data) {
    if(AJS.isObject(data)) {
      var post_data = [];
      for(k in data) {
        post_data.push(k + "=" + AJS.urlencode(data[k]));
      }
      post_data = post_data.join("&");
      this.req.send(post_data);
    }
    else if(AJS.isDefined(data))
      this.req.send(data);
    else {
      this.req.send("");
    }
  };
};
AJSDeferred.prototype = new AJSDeferred();

//Prevent memory-leaks
AJS.addEventListener(window, 'unload', AJS.unloadListeners);


/*** hotkeys.js *****/
/*==============================================================================
Author:     John Gardner
Date:       September 2004

Note that some of the techniques here have been picked up from Chapter 9 of 
"JavaScript and DHTML Cookbook", by Danny Goodman, published by O'Reilly.

==============================================================================*/

function hotKeys (event) {
  event = (event) ? event : ((window.event) ? event : null);
  
  if (event) {   
    
    if (event.ctrlKey || event.altKey || event.metaKey) {
      var charCode = (event.charCode) ? event.charCode : ((event.which) ? event.which : event.keyCode);   
      var myChar = String.fromCharCode (charCode).toLowerCase();
      if (event.shiftKey) {myChar = myChar.toUpperCase();}
      
      for (var i = 0; i < keyActions.length; i++) {
         
        if (keyActions[i].character == myChar) { 
      
          var action;
          
          if (keyActions[i].actionType.toLowerCase() == "link") {
            action = new Function ('location.href  ="' + keyActions[i].param + '"');
          }
         
          else if (keyActions[i].actionType.toLowerCase()  == "code") {
            action = new Function (keyActions[i].param);
          }
           
          else {
            alert ('Hotkey Function Error: Action should be "link" or "code"');
            break;
          }
           
          action ();
        
          break;
        }
      }
    }
  }
}
/*============================================================================*/
// DLY 20070504
					

/***** functions.js ******/

function toggleRow(rowElement) {
	if (rowElement.className=='offer' || rowElement.className=='offer-on first') {
		rowElement.className = 'offer-on';
	} else {
		rowElement.className = 'offer';
	}
}

function zoom(imageUrl) {
	$('zoomDiv').innerHTML = '<img src="'+imageUrl+'" onclick="Element.hide(\'zoomDiv\')"/>';
	Element.show('zoomDiv');
}

zlioGetCurrencyString = function (currency) {
	switch(currency) {
		case "EUR":
			return "&#8364;";
		case "USD":
			return "&#36;";
	}
}

function strtrim() {
    return this.replace(/^\s+/,'').replace(/\s+$/,'');
}
String.prototype.trim = strtrim;

function goProduct(url){
	document.location=url;
}
function getposOffset(overlayInfo, offsettype){
	var totaloffset=(offsettype=="left")? overlayInfo.offsetLeft : overlayInfo.offsetTop;
	var parentEl=overlayInfo.offsetParent;


	while (parentEl!=null){
		totaloffset=(offsettype=="left")? totaloffset+parentEl.offsetLeft : totaloffset+parentEl.offsetTop;
		parentEl=parentEl.offsetParent;
	}
	return totaloffset;
}
function tooltipInfo(curobj, subobjstr, opt_position, kind, nbCat){
	for(var z=1;z<=nbCat;z++){
		catobj = document.getElementById(kind+'-subcategory-cnt-'+z);
		if(catobj){
			catobj.style.display = 'none';
		}
	}
	if (document.getElementById){
		var subobj=document.getElementById(subobjstr)
		if(subobj){
			subobj.style.display=(subobj.style.display!="block")? "block" : "none"
			var xpos=getposOffset(curobj, "left")+((typeof opt_position!="undefined" && opt_position.indexOf("right")!=-1)? -(subobj.offsetWidth-curobj.offsetWidth) : 0) 
			var ypos=getposOffset(curobj, "top")+((typeof opt_position!="undefined" && opt_position.indexOf("bottom")!=-1)? curobj.offsetHeight : 0)
			subobj.style.left=xpos+"px"
			subobj.style.top=ypos+"px"
			return false
		}else{
			return true
		}
	}else
	return true
}
function tooltipClose(kind, nbCat){
	//alert(kind+' et '+nbCat);
	for(var y=1;y<=nbCat;y++){
		objet2=document.getElementById(kind+'-subcategory-cnt-'+y);
		if(objet2){
		objet2.style.display="none"
		}
	}	
}
function tooltipInfoProduct(curobj, productID, opt_position){
  var subobjstr = 'product-info-'+productID;
	if (document.getElementById){
		var subobj=document.getElementById(subobjstr);
		if(subobj){
		  $('popup-image-'+productID).src = 'http://images.zlio.com/product/large/' + productID + '.jpg';
			subobj.style.display=(subobj.style.display!="block")? "block" : "none"
			var xpos=getposOffset(curobj, "left")+((typeof opt_position!="undefined" && opt_position.indexOf("right")!=-1)? -(subobj.offsetWidth-curobj.offsetWidth) : 0) 
			var ypos=getposOffset(curobj, "top")+((typeof opt_position!="undefined" && opt_position.indexOf("bottom")!=-1)? curobj.offsetHeight : 0)
			subobj.style.left=xpos+"px"
			subobj.style.top=ypos+"px"
			return false
		}else{
			return true
		}
	}else{	
		return true
	}
}
function tooltipCloseProduct(productID){
	objet2=document.getElementById('product-info-'+productID);
	if(objet2){
		objet2.style.display="none"
	}
}
////////////////////////////tooltipInfoProductV2/////////////////////////////////
var disappeardelay=250  //tooltip disappear delay (in miliseconds)
var verticaloffset=0 //vertical offset of tooltip from anchor link, if any
var enablearrowhead=0 //0 or 1, to disable or enable the arrow image
var arrowheadimg=["arrowdown.gif", "arrowup.gif"] //path to down and up arrow images
var arrowheadheight=11 //height of arrow image (amount to reveal)
var ie=document.all
var ns6=document.getElementById&&!document.all
verticaloffset=(enablearrowhead)? verticaloffset+arrowheadheight : verticaloffset
function showhide(obj, e){
	dropmenuobj.style.left=dropmenuobj.style.top="-500px"
	if (e.type=="mouseover")
	//dropmenuobj.style.visibility="visible"
	delayAppear=setTimeout("dropmenuobj.style.visibility='visible'",500)
}
function iecompattest(){
	return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
}
function clearbrowseredge(obj, whichedge){
	if (whichedge=="rightedge"){
		edgeoffsetx=0
		var windowedge=ie && !window.opera? iecompattest().scrollLeft+iecompattest().clientWidth-15 : window.pageXOffset+window.innerWidth-15
		dropmenuobj.contentmeasure=dropmenuobj.offsetWidth
		if (windowedge-dropmenuobj.x < dropmenuobj.contentmeasure)
		edgeoffsetx=dropmenuobj.contentmeasure-obj.offsetWidth
		return edgeoffsetx
	}
	else{
		edgeoffsety=0
		var topedge=ie && !window.opera? iecompattest().scrollTop : window.pageYOffset
		var windowedge=ie && !window.opera? iecompattest().scrollTop+iecompattest().clientHeight-15 : window.pageYOffset+window.innerHeight-18
		dropmenuobj.contentmeasure=dropmenuobj.offsetHeight
		if (windowedge-dropmenuobj.y < dropmenuobj.contentmeasure) //move up?
		edgeoffsety=dropmenuobj.contentmeasure+obj.offsetHeight+(verticaloffset*2)
		return edgeoffsety
	}
}
function displayballoontip(obj, e){ //main ballooon tooltip function
if (window.event) event.cancelBubble=true
else if (e.stopPropagation) e.stopPropagation()
if (typeof dropmenuobj!="undefined") //hide previous tooltip?
	dropmenuobj.style.visibility="hidden"
	clearhidemenu()
	//obj.onmouseout=delayhidemenu();
	dropmenuobj=document.getElementById(obj.getAttribute("rel"))
	relValue=obj.getAttribute("rel");
	relTot=relValue.length;
	productID=relValue.substring(13,relTot);
	$('popup-image-'+productID).src = 'http://images.zlio.com/product/large/' + productID + '.jpg';
	//showhide(dropmenuobj.style, e)
	showhide(dropmenuobj, e)
	dropmenuobj.x=getposOffset(obj, "left")
	dropmenuobj.y=getposOffset(obj, "top")+verticaloffset
	dropmenuobj.style.left=dropmenuobj.x-clearbrowseredge(obj, "rightedge")+"px"
	dropmenuobj.style.top=dropmenuobj.y-clearbrowseredge(obj, "bottomedge")+obj.offsetHeight+"px"
}
function delayhidemenu(){
	delayhide=setTimeout("dropmenuobj.style.visibility='hidden'; dropmenuobj.style.left=0; if (enablearrowhead) tiparrow.style.visibility='hidden'",disappeardelay)
	clearTimeout(delayAppear)
}
function clearhidemenu(){
	if (typeof delayhide!="undefined")
	clearTimeout(delayhide)
}
function reltoelement(linkobj){ //tests if a link has "rel" defined and it's the ID of an element on page
	var relvalue=linkobj.getAttribute("rel")
	return (relvalue!=null && relvalue!="" && document.getElementById(relvalue)!=null && document.getElementById(relvalue).className=="product-info2")? true : false
}
function initalizetooltip(){
	var all_links=document.getElementsByTagName("a")
	if (enablearrowhead){
		tiparrow=document.createElement("img")
		tiparrow.setAttribute("src", arrowheadimg[0])
		tiparrow.setAttribute("id", "arrowhead")
		document.body.appendChild(tiparrow)
	}
	for (var i=0; i<all_links.length; i++){
		if (reltoelement(all_links[i])){ //if link has "rel" defined and it's the ID of an element on page
			all_links[i].onmouseover=function(e){
				var evtobj=window.event? window.event : e
				displayballoontip(this, evtobj)
			}
			all_links[i].onmouseout=delayhidemenu
		}
	}
}
if (window.addEventListener)
	window.addEventListener("load", initalizetooltip, false)
else if (window.attachEvent)
	window.attachEvent("onload", initalizetooltip)
else if (document.getElementById)
	window.onload=initalizetooltip
	
///////////////////////////////////////////////


function show(id_cache, id_block){
	var objet_cache=$(id_cache);
	var etat_cache = objet_cache.style.display;
	
	var objet_block=$(id_block);
	var etat_block = objet_block.style.display;
	
	if ( etat_cache == 'block' || etat_cache == '') {
		objet_cache.style.display = 'none';
		objet_block.style.display = 'block';
	}
	else {
		objet_cache.style.display = 'block';
		objet_block.style.display = 'none';
	}
}
function viewDescription (id, id2){
	var objet=$(id);
	objet.style.display = 'block';
	var objet=$(id2);
	objet.style.display = 'none';
}

function goTop(){
	document.location="#top";
}
function pushArrayOffer(tableOffer, tableOfferZoom, tableOfferCompare){
	var objetOriginal=$(tableOffer);
	var objetZoom=$(tableOfferZoom);
	var objetCompare=$(tableOfferCompare);
	objetZoom.innerHTML=objetOriginal.innerHTML;
	objetCompare.innerHTML=objetOriginal.innerHTML;
}

function showSubcategories(id, kind){
	var d = document.getElementById(id);
		for (var i = 1; i<=10; i++) {
			if (document.getElementById(kind+'-subcategory-cnt-'+i)) {
				document.getElementById(kind+'-subcategory-cnt-'+i).style.display='none';
			}
		}
	if (d) {
		d.style.display='block';
	}
}

function showCatBg(id, kind){
	if(kind=='in'){
		document.getElementById(id).className="cat-inline-in";
	}else{
		if(kind=='out'){
			document.getElementById(id).className="cat-inline";
		}
	}					
}
function showSearch(){
	var objet_cache=document.getElementById('search-block-id');
	if(objet_cache){
		objet_cache.style.display = 'block';
	}
}

function displayThumbnails(){
	ttImg = document.images.length;
	ttImg = ttImg+5;
	for(var m=0; m<=ttImg; m++){
		for(var inc=0; inc<=nbr; inc++){		
			if(document.images[m]){
				if(document.images[m].name == 'imgIn_'+inc){
					h = document.images[m].height;
					w = document.images[m].width;
					altImg = document.images[m].alt;
					$('imgIn_'+inc).style.display = 'none'
					//alert(h+' et '+w);
					if(inc==0){
						var output ='<a href="#top" rel="photo" class="lbOn"><img style="border:none" alt="'+altImg+'" title="'+altImg+'" src="';
					}else{
						var output ='<a><img style="border:none;" alt="'+altImg+'" title="'+altImg+'" src="';
					}
					if(h < w){
						output += document.images[m].src+'" width="100px"';
					}else{
						output += document.images[m].src+'" height="100px"';
					}
					output += '/></a>' ;
					$('imgOut_'+inc).innerHTML = output;
				}
			}
		}
	}
}
function displayThumbnailsPara(listID){
	ttImg = document.images.length;
	ttImg = ttImg+30;
	var reg=new RegExp("[ ,;]+", "g");
	var tab=listID.split(reg);
	//alert(listID);

	for(var m=0; m<=ttImg; m++){
		for (var inc=0; inc<tab.length; inc++) {

			if(document.images[m]){
				if(document.images[m].name == 'imgIn_'+tab[inc]){
					h = document.images[m].height;
					w = document.images[m].width;
					//alert('height : '+h+' | width : '+w+' | id : '+tab[inc]);
					altImg = document.images[m].alt;
					$('imgIn_'+tab[inc]).style.display = 'none'
					var output ='<a><img style="border:none" alt="'+altImg+'" title="'+altImg+'" src="';
					if(h < w){
						output += document.images[m].src+'" width="80px"';
					}else{
						output += document.images[m].src+'" height="80px"';
					}
					output += '/></a>' ;
					$('imgOut_'+tab[inc]).innerHTML = output;
				}
			}
		}	
	}
}

var pageOffer = '';

function displayOffer(){
	var tabOffer = $('tableOffer');
	var currentTR = tabOffer.getElementsByTagName('tr');
	var curLen = currentTR.length;
	pageOffer = curLen;
	for ( j=17; j<curLen; j++ ) {
		currentTR[j].style.display = 'none';
	}
}

function displayMoreOffersButton(){
	if(pageOffer>16){
		$('see-more-offer').style.display = 'block';
	}
}

function displayOfferAll(){
	var max = pageOffer;
	var tabOffer = document.getElementById('tableOffer');
	var current = tabOffer.getElementsByTagName('tr');
	var curLen = current.length;

	if(navigator.appName == "Microsoft Internet Explorer"){
		for ( i=1; i<curLen; i++ ) {
			current[i].style.display = 'inline';
		}
	}else{	
		for ( y=1; y<curLen; y++ ){
			current[y].style.display = 'table-row';
		}	
	}
	$('see-more-offer').style.display = 'none';
}

function showSubcat(pos){
	var state = $('subcat_'+pos).style.display;
	if ( state == 'block' || state == '') {
		$('subcat_'+pos).style.display = 'none';
	}
	else {
		$('subcat_'+pos).style.display = 'block';
	}
}
function aff_cache(id, id2){
	
	var objet=document.getElementById(id);
	var etat = objet.style.display;
	
	var objet2=document.getElementById(id2);
	
	if ( etat == 'block' || etat == '') {
		objet.style.display = 'none';
		objet2.innerHTML = 'En savoir +';
	}
	else {
		objet.style.display = 'block';
		objet2.innerHTML = 'Cacher le d&eacute;tail';
		
		}
}

function fadeProduct(id){
	$('switch-' + id).className = "btn-switch-module-latestproduct";
	new Effect.Fade('prod-'+id, {duration : 0.5});
}
function appearProduct(id){
	$('switch-' + id).className = "btn-switch-module-latestproduct-in";
	id2 = id;	
	new Effect.Appear('prod-'+id, {duration : 0.5});
	fade = setTimeout("fadeProduct(id2)",9200);
}
function appearProduct2(id){
	$('switch-' + id).className = "btn-switch-module-latestproduct-in";
	new Effect.Appear('prod-'+id, {duration : 0.5});
}
function effectProduct(inc){
	var product = $('prod-2');
	if(product){
		$('switch-module-latestproduct').style.display="block";
		if(inc==nbr){inc=1;}
		i = inc;
		appearProduct(inc);
		i+=1;	
		appear = setTimeout("effectProduct(i)",10000)
	}else{
		if($('prod-1')){
			$('prod-1').style.display="block";
		}
	}
}
function effectStop(id){
	id2 = id;
	for(var m=1;m<=nb2;m++){
		if(m!=id){
			fadeProduct(m);
		}
	}
	window.clearTimeout(fade);
	window.clearTimeout(appear);
	setTimeout("appearProduct2(id2)",700);
}

var GB_IMG_DIR = "http://images.zlio.com/www.zlio.com/images/greybox/";
//GreyBox.preloadGreyBoxImages();
shopRollAdd = function(shopID) {
			GB_ONLY_ONE.setOverlayCloseClick(true);
			GB_ONLY_ONE.setOverlayColor('dark');
			var url = 'http://www.zlio.com/?page=app:shopRollAddEntryStandalone&entryShopID='+shopID;
			return GB_show('ShopRoll', url, 520, 780); 
} 

