var SERVICES_URL = "http://services.katharineberry.co.uk/mapapi/";
var X_MIN = "1083";
var X_MAX = "1180";
var Y_MIN = "976";
var Y_MAX = "1121";

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

var Prototype = {
  Version: '1.4.0',
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',

  emptyFunction: function() {},
  K: function(x) {return x}
}

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

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.inspect = function(object) {
  try {
    if (object == undefined) return 'undefined';
    if (object == null) return 'null';
    return object.inspect ? object.inspect() : object.toString();
  } catch (e) {
    if (e instanceof RangeError) return '...';
    throw e;
  }
}

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

// custom addition
Function.prototype.bindAsEventListener = function(object) {
  var __method = this;
  return function(event) {
    event = event? event:window.event;
    
    if(event && !event.target){
      event.target = event.srcElement;
    }
    
    __method.call(object, event);
  }
}

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

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  }
});

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

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

    return returnValue;
  }
}

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

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

    this.registerCallback();
  },

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

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

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

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

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

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

    elements.push(element);
  }

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

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(eval);
  },

  escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  },

  toQueryParams: function() {
    var pairs = this.match(/^\??(.*)$/)[1].split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair = pairString.split('=');
      params[pair[0]] = pair[1];
      return params;
    });
  },

  toArray: function() {
    return this.split('');
  },

  camelize: function() {
    var oStringList = this.split('-');
    if (oStringList.length == 1) return oStringList[0];

    var camelizedString = this.indexOf('-') == 0
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
      : oStringList[0];

    for (var i = 1, len = oStringList.length; i < len; i++) {
      var s = oStringList[i];
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }

    return camelizedString;
  },

  inspect: function() {
    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
  }
});

String.prototype.parseQuery = String.prototype.toQueryParams;

var $break    = new Object();
var $continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        try {
          iterator(value, index++);
        } catch (e) {
          if (e != $continue) throw e;
        }
      });
    } catch (e) {
      if (e != $break) throw e;
    }
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push(iterator(value, index));
    });
    return results;
  },

  detect: function (iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },

  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.collect(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value >= (result || value))
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value <= (result || value))
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator) {
    return this.collect(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.collect(Prototype.K);
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      iterator(value = collections.pluck(index));
      return value;
    });
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0; i < iterable.length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0; i < this.length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != undefined || value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0; i < this.length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  shift: function() {
    var result = this[0];
    for (var i = 0; i < this.length - 1; i++)
      this[i] = this[i + 1];
    this.length--;
    return result;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});
var Hash = {
  _each: function(iterator) {
    for (key in this) {
      var value = this[key];
      if (typeof value == 'function') continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $H(hash).inject($H(this), function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  toQueryString: function() {
    return this.map(function(pair) {
      return pair.map(encodeURIComponent).join('=');
    }).join('&');
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  }
}

function $H(object) {
  var hash = Object.extend({}, object || {});
  Object.extend(hash, Enumerable);
  Object.extend(hash, Hash);
  return hash;
}
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    do {
      iterator(value);
      value = value.succ();
    } while (this.include(value));
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

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

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responderToAdd) {
    if (!this.include(responderToAdd))
      this.responders.push(responderToAdd);
  },

  unregister: function(responderToRemove) {
    this.responders = this.responders.without(responderToRemove);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (responder[callback] && typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },

  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      parameters:   ''
    }
    Object.extend(this.options, options || {});
  },

  responseIsSuccess: function() {
    return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  responseIsFailure: function() {
    return !this.responseIsSuccess();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    var parameters = this.options.parameters || '';
    if (parameters.length > 0) parameters += '&_=';

    try {
      this.url = url;
      if (this.options.method == 'get' && parameters.length > 0)
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method, this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
      }

      this.setRequestHeaders();

      var body = this.options.postBody ? this.options.postBody : parameters;
      this.transport.send(this.options.method == 'post' ? body : null);

    } catch (e) {
      this.dispatchException(e);
    }
  },

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

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

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

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

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

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

  header: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) {}
  },

  evalJSON: function() {
    try {
      return eval(this.header('X-JSON'));
    } catch (e) {}
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (event == 'Complete') {
      try {
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + event, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.containers = {
      success: container.success ? $(container.success) : $(container),
      failure: container.failure ? $(container.failure) :
        (container.success ? null : $(container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, object) {
      this.updateContent();
      onComplete(transport, object);
    }).bind(this);

    this.request(url);
  },

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

    if (!this.options.evalScripts)
      response = response.stripScripts();

    if (receiver) {
      if (this.options.insertion) {
        new this.options.insertion(receiver, response);
      } else {
        Element.update(receiver, response);
      }
    }

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

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

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

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

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  return $A(children).inject([], function(elements, child) {
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      elements.push(child);
    return elements;
  });
}

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

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

Object.extend(Element, {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      Element[Element.visible(element) ? 'hide' : 'show'](element);
    }
  },

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

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

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

  update: function(element, html) {
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
  },

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

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).include(className);
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).add(className);
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).remove(className);
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    for (var i = 0; i < element.childNodes.length; i++) {
      var node = element.childNodes[i];
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        Element.remove(node);
    }
  },

  empty: function(element) {
    return $(element).innerHTML.match(/^\s*$/);
  },

  scrollTo: function(element) {
    element = $(element);
    var x = element.x ? element.x : element.offsetLeft,
        y = element.y ? element.y : element.offsetTop;
    window.scrollTo(x, y);
  },

  getStyle: function(element, style) {
    element = $(element);
    var value = element.style[style.camelize()];
    if (!value) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        var css = document.defaultView.getComputedStyle(element, null);
        value = css ? css.getPropertyValue(style) : null;
      } else if (element.currentStyle) {
        value = element.currentStyle[style.camelize()];
      }
    }

    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
      if (Element.getStyle(element, 'position') == 'static') value = 'auto';

    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style) {
    element = $(element);
    for (name in style)
      element.style[name.camelize()] = style[name];
  },

  getDimensions: function(element) {
    element = $(element);
    if (Element.getStyle(element, 'display') != 'none')
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = '';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = 'none';
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element._overflow = element.style.overflow;
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
  },

  undoClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element.style.overflow = element._overflow;
    element._overflow = undefined;
  }
});

var Toggle = new Object();
Toggle.display = Element.toggle;

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

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        if (this.element.tagName.toLowerCase() == 'tbody') {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

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

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});

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

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set(this.toArray().concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set(this.select(function(className) {
      return className != classNameToRemove;
    }).join(' '));
  },

  toString: function() {
    return this.toArray().join(' ');
  }
}

Object.extend(Element.ClassNames.prototype, Enumerable);
var Field = {
  clear: function() {
    for (var i = 0; i < arguments.length; i++)
      $(arguments[i]).value = '';
  },

  focus: function(element) {
    $(element).focus();
  },

  present: function() {
    for (var i = 0; i < arguments.length; i++)
      if ($(arguments[i]).value == '') return false;
    return true;
  },

  select: function(element) {
    $(element).select();
  },

  activate: function(element) {
    element = $(element);
    element.focus();
    if (element.select)
      element.select();
  }
}

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

var Form = {
  serialize: function(form) {
    var elements = Form.getElements($(form));
    var queryComponents = new Array();

    for (var i = 0; i < elements.length; i++) {
      var queryComponent = Form.Element.serialize(elements[i]);
      if (queryComponent)
        queryComponents.push(queryComponent);
    }

    return queryComponents.join('&');
  },

  getElements: function(form) {
    form = $(form);
    var elements = new Array();

    for (tagName in Form.Element.Serializers) {
      var tagElements = form.getElementsByTagName(tagName);
      for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
    }
    return elements;
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name)
      return inputs;

    var matchingInputs = new Array();
    for (var i = 0; i < inputs.length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) ||
          (name && input.name != name))
        continue;
      matchingInputs.push(input);
    }

    return matchingInputs;
  },

  disable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.blur();
      element.disabled = 'true';
    }
  },

  enable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.disabled = '';
    }
  },

  findFirstElement: function(form) {
    return Form.getElements(form).find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    Field.activate(Form.findFirstElement(form));
  },

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

Form.Element = {
  serialize: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter) {
      var key = encodeURIComponent(parameter[0]);
      if (key.length == 0) return;

      if (parameter[1].constructor != Array)
        parameter[1] = [parameter[1]];

      return parameter[1].map(function(value) {
        return key + '=' + encodeURIComponent(value);
      }).join('&');
    }
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter)
      return parameter[1];
  }
}

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'submit':
      case 'hidden':
      case 'password':
      case 'text':
        return Form.Element.Serializers.textarea(element);
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
    }
    return false;
  },

  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },

  textarea: function(element) {
    return [element.name, element.value];
  },

  select: function(element) {
    return Form.Element.Serializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = element.options[index];
      value = opt.value;
      if (!value && !('value' in opt))
        value = opt.text;
    }
    return [element.name, value];
  },

  selectMany: function(element) {
    var value = new Array();
    for (var i = 0; i < element.length; i++) {
      var opt = element.options[i];
      if (opt.selected) {
        var optValue = opt.value;
        if (!optValue && !('value' in opt))
          optValue = opt.text;
        value.push(optValue);
      }
    }
    return [element.name, value];
  }
}

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

var $F = Form.Element.getValue;

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

Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;

    this.lastValue = this.getValue();
    this.registerCallback();
  },

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

  onTimerEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

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

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    var elements = Form.getElements(this.element);
    for (var i = 0; i < elements.length; i++)
      this.registerCallback(elements[i]);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        case 'password':
        case 'text':
        case 'textarea':
        case 'select-one':
        case 'select-multiple':
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,

  element: function(event) {
    return event.target || event.srcElement;
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0; i < Event.observers.length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.attachEvent))
      name = 'keydown';

    this._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.detachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      element.detachEvent('on' + name, observer);
    }
  }
});

/* prevent memory leaks in IE */
Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  clone: function(source, target) {
    source = $(source);
    target = $(target);
    target.style.position = 'absolute';
    var offsets = this.cumulativeOffset(source);
    target.style.top    = offsets[1] + 'px';
    target.style.left   = offsets[0] + 'px';
    target.style.width  = source.offsetWidth + 'px';
    target.style.height = source.offsetHeight + 'px';
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent==document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      valueT -= element.scrollTop  || 0;
      valueL -= element.scrollLeft || 0;
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';;
    element.style.left   = left + 'px';;
    element.style.width  = width + 'px';;
    element.style.height = height + 'px';;
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
// 
// See scriptaculous.js for full license.  

/* ------------- element ext -------------- */  
 
// converts rgb() and #xxx to #xxxxxx format,  
// returns self (or first argument) if not convertable  
String.prototype.parseColor = function() {  
  var color = '#';  
  if(this.slice(0,4) == 'rgb(') {  
    var cols = this.slice(4,this.length-1).split(',');  
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  } else {  
    if(this.slice(0,1) == '#') {  
      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
      if(this.length==7) color = this.toLowerCase();  
    }  
  }  
  return(color.length==7 ? color : (arguments[0] || this));  
}

Element.collectTextNodes = function(element) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  }).flatten().join('');
}

Element.collectTextNodesIgnoreClass = function(element, className) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
        Element.collectTextNodes(node) : ''));
  }).flatten().join('');
}

Element.setStyle = function(element, style) {
  element = $(element);
  for(k in style) element.style[k.camelize()] = style[k];
}

Element.setContentZoom = function(element, percent) {  
  Element.setStyle(element, {fontSize: (percent/100) + 'em'});   
  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);  
}

Element.getOpacity = function(element){  
  var opacity;
  if (opacity = Element.getStyle(element, 'opacity'))  
    return parseFloat(opacity);  
  if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))  
    if(opacity[1]) return parseFloat(opacity[1]) / 100;  
  return 1.0;  
}

Element.setOpacity = function(element, value){  
  element= $(element);  
  if (value == 1){
    Element.setStyle(element, { opacity: 
      (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 
      0.999999 : null });
    if(/MSIE/.test(navigator.userAgent))  
      Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});  
  } else {  
    if(value < 0.00001) value = 0;  
    Element.setStyle(element, {opacity: value});
    if(/MSIE/.test(navigator.userAgent))  
     Element.setStyle(element, 
       { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
                 'alpha(opacity='+value*100+')' });  
  }   
}  
 
Element.getInlineOpacity = function(element){  
  return $(element).style.opacity || '';
}  

Element.childrenWithClassName = function(element, className) {  
  return $A($(element).getElementsByTagName('*')).select(
    function(c) { return Element.hasClassName(c, className) });
}

Array.prototype.call = function() {
  var args = arguments;
  this.each(function(f){ f.apply(this, args) });
}

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

var Effect = {
  tagifyText: function(element) {
    var tagifyStyle = 'position:relative';
    if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
    element = $(element);
    $A(element.childNodes).each( function(child) {
      if(child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            Builder.node('span',{style: tagifyStyle},
              character == ' ' ? String.fromCharCode(160) : character), 
              child);
        });
        Element.remove(child);
      }
    });
  },
  multiple: function(element, effect) {
    var elements;
    if(((typeof element == 'object') || 
        (typeof element == 'function')) && 
       (element.length))
      elements = element;
    else
      elements = $(element).childNodes;
      
    var options = Object.extend({
      speed: 0.1,
      delay: 0.0
    }, arguments[2] || {});
    var masterDelay = options.delay;

    $A(elements).each( function(element, index) {
      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
    });
  },
  PAIRS: {
    'slide':  ['SlideDown','SlideUp'],
    'blind':  ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },
  toggle: function(element, effect) {
    element = $(element);
    effect = (effect || 'appear').toLowerCase();
    var options = Object.extend({
      queue: { position:'end', scope:(element.id || 'global') }
    }, arguments[2] || {});
    Effect[Element.visible(element) ? 
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  }
};

var Effect2 = Effect; // deprecated

/* ------------- transitions ------------- */

Effect.Transitions = {}

Effect.Transitions.linear = function(pos) {
  return pos;
}
Effect.Transitions.sinoidal = function(pos) {
  return (-Math.cos(pos*Math.PI)/2) + 0.5;
}
Effect.Transitions.reverse  = function(pos) {
  return 1-pos;
}
Effect.Transitions.flicker = function(pos) {
  return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
}
Effect.Transitions.wobble = function(pos) {
  return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
}
Effect.Transitions.pulse = function(pos) {
  return (Math.floor(pos*10) % 2 == 0 ? 
    (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
}
Effect.Transitions.none = function(pos) {
  return 0;
}
Effect.Transitions.full = function(pos) {
  return 1;
}

/* ------------- core effects ------------- */

Effect.ScopedQueue = Class.create();
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
  initialize: function() {
    this.effects  = [];
    this.interval = null;
  },
  _each: function(iterator) {
    this.effects._each(iterator);
  },
  add: function(effect) {
    var timestamp = new Date().getTime();
    
    var position = (typeof effect.options.queue == 'string') ? 
      effect.options.queue : effect.options.queue.position;
    
    switch(position) {
      case 'front':
        // move unstarted effects after this effect  
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }
    
    effect.startOn  += timestamp;
    effect.finishOn += timestamp;
    this.effects.push(effect);
    if(!this.interval) 
      this.interval = setInterval(this.loop.bind(this), 40);
  },
  remove: function(effect) {
    this.effects = this.effects.reject(function(e) { return e==effect });
    if(this.effects.length == 0) {
      clearInterval(this.interval);
      this.interval = null;
    }
  },
  loop: function() {
    var timePos = new Date().getTime();
    this.effects.invoke('loop', timePos);
  }
});

Effect.Queues = {
  instances: $H(),
  get: function(queueName) {
    if(typeof queueName != 'string') return queueName;
    
    if(!this.instances[queueName])
      this.instances[queueName] = new Effect.ScopedQueue();
      
    return this.instances[queueName];
  }
}
Effect.Queue = Effect.Queues.get('global');

Effect.DefaultOptions = {
  transition: Effect.Transitions.sinoidal,
  duration:   1.0,   // seconds
  fps:        25.0,  // max. 25fps due to Effect.Queue implementation
  sync:       false, // true for combining
  from:       0.0,
  to:         1.0,
  delay:      0.0,
  queue:      'parallel'
}

Effect.Base = function() {};
Effect.Base.prototype = {
  position: null,
  start: function(options) {
    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn + (this.options.duration*1000);
    this.event('beforeStart');
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).add(this);
  },
  loop: function(timePos) {
    if(timePos >= this.startOn) {
      if(timePos >= this.finishOn) {
        this.render(1.0);
        this.cancel();
        this.event('beforeFinish');
        if(this.finish) this.finish(); 
        this.event('afterFinish');
        return;  
      }
      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
      var frame = Math.round(pos * this.options.fps * this.options.duration);
      if(frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  render: function(pos) {
    if(this.state == 'idle') {
      this.state = 'running';
      this.event('beforeSetup');
      if(this.setup) this.setup();
      this.event('afterSetup');
    }
    if(this.state == 'running') {
      if(this.options.transition) pos = this.options.transition(pos);
      pos *= (this.options.to-this.options.from);
      pos += this.options.from;
      this.position = pos;
      this.event('beforeUpdate');
      if(this.update) this.update(pos);
      this.event('afterUpdate');
    }
  },
  cancel: function() {
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).remove(this);
    this.state = 'finished';
  },
  event: function(eventName) {
    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
    if(this.options[eventName]) this.options[eventName](this);
  },
  inspect: function() {
    return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
  }
}

Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
  initialize: function(effects) {
    this.effects = effects || [];
    this.start(arguments[1]);
  },
  update: function(position) {
    this.effects.invoke('render', position);
  },
  finish: function(position) {
    this.effects.each( function(effect) {
      effect.render(1.0);
      effect.cancel();
      effect.event('beforeFinish');
      if(effect.finish) effect.finish(position);
      effect.event('afterFinish');
    });
  }
});

Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    // make this work on IE on elements without 'layout'
    if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
      Element.setStyle(this.element, {zoom: 1});
    var options = Object.extend({
      from: Element.getOpacity(this.element) || 0.0,
      to:   1.0
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    Element.setOpacity(this.element, position);
  }
});

Effect.Move = Class.create();
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Bug in Opera: Opera returns the "real" position of a static element or
    // relative element that does not have top/left explicitly set.
    // ==> Always set top and left for position relative elements in your stylesheets 
    // (to 0 if you do not need them) 
    Element.makePositioned(this.element);
    this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
    this.originalTop  = parseFloat(Element.getStyle(this.element,'top')  || '0');
    if(this.options.mode == 'absolute') {
      // absolute movement, so we need to calc deltaX and deltaY
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  update: function(position) {
    Element.setStyle(this.element, {
      left: this.options.x  * position + this.originalLeft + 'px',
      top:  this.options.y  * position + this.originalTop  + 'px'
    });
  }
});

// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
  return new Effect.Move(element, 
    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};

Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
  initialize: function(element, percent) {
    this.element = $(element)
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
      scaleFrom: 100.0,
      scaleTo:   percent
    }, arguments[2] || {});
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = Element.getStyle(this.element,'position');
    
    this.originalStyle = {};
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
    
    var fontSize = Element.getStyle(this.element,'font-size') || '100%';
    ['em','px','%'].each( function(fontSizeType) {
      if(fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));
    
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
    
    this.dims = null;
    if(this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if(this.options.scaleContent && this.fontSize)
      Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = {};
    if(this.options.scaleX) d.width = width + 'px';
    if(this.options.scaleY) d.height = height + 'px';
    if(this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if(this.elementPositioning == 'absolute') {
        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
      } else {
        if(this.options.scaleY) d.top = -topd + 'px';
        if(this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    Element.setStyle(this.element, d);
  }
});

Effect.Highlight = Class.create();
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Prevent executing on elements not in the layout flow
    if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
    // Disable background image during the effect
    this.oldStyle = {
      backgroundImage: Element.getStyle(this.element, 'background-image') };
    Element.setStyle(this.element, {backgroundImage: 'none'});
    if(!this.options.endcolor)
      this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
    if(!this.options.restorecolor)
      this.options.restorecolor = Element.getStyle(this.element, 'background-color');
    // init color calculations
    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
  },
  update: function(position) {
    Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
  },
  finish: function() {
    Element.setStyle(this.element, Object.extend(this.oldStyle, {
      backgroundColor: this.options.restorecolor
    }));
  }
});

Effect.ScrollTo = Class.create();
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    this.start(arguments[1] || {});
  },
  setup: function() {
    Position.prepare();
    var offsets = Position.cumulativeOffset(this.element);
    if(this.options.offset) offsets[1] += this.options.offset;
    var max = window.innerHeight ? 
      window.height - window.innerHeight :
      document.body.scrollHeight - 
        (document.documentElement.clientHeight ? 
          document.documentElement.clientHeight : document.body.clientHeight);
    this.scrollStart = Position.deltaY;
    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
  },
  update: function(position) {
    Position.prepare();
    window.scrollTo(Position.deltaX, 
      this.scrollStart + (position*this.delta));
  }
});

/* ------------- combination effects ------------- */

Effect.Fade = function(element) {
  var oldOpacity = Element.getInlineOpacity(element);
  var options = Object.extend({
  from: Element.getOpacity(element) || 1.0,
  to:   0.0,
  afterFinishInternal: function(effect) { with(Element) { 
    if(effect.options.to!=0) return;
    hide(effect.element);
    setStyle(effect.element, {opacity: oldOpacity}); }}
  }, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

Effect.Appear = function(element) {
  var options = Object.extend({
  from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
  to:   1.0,
  beforeSetup: function(effect) { with(Element) {
    setOpacity(effect.element, effect.options.from);
    show(effect.element); }}
  }, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

Effect.Puff = function(element) {
  element = $(element);
  var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
  return new Effect.Parallel(
   [ new Effect.Scale(element, 200, 
      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
     Object.extend({ duration: 1.0, 
      beforeSetupInternal: function(effect) { with(Element) {
        setStyle(effect.effects[0].element, {position: 'absolute'}); }},
      afterFinishInternal: function(effect) { with(Element) {
         hide(effect.effects[0].element);
         setStyle(effect.effects[0].element, oldStyle); }}
     }, arguments[1] || {})
   );
}

Effect.BlindUp = function(element) {
  element = $(element);
  Element.makeClipping(element);
  return new Effect.Scale(element, 0, 
    Object.extend({ scaleContent: false, 
      scaleX: false, 
      restoreAfterFinish: true,
      afterFinishInternal: function(effect) { with(Element) {
        [hide, undoClipping].call(effect.element); }} 
    }, arguments[1] || {})
  );
}

Effect.BlindDown = function(element) {
  element = $(element);
  var oldHeight = Element.getStyle(element, 'height');
  var elementDimensions = Element.getDimensions(element);
  return new Effect.Scale(element, 100, 
    Object.extend({ scaleContent: false, 
      scaleX: false,
      scaleFrom: 0,
      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
      restoreAfterFinish: true,
      afterSetup: function(effect) { with(Element) {
        makeClipping(effect.element);
        setStyle(effect.element, {height: '0px'});
        show(effect.element); 
      }},  
      afterFinishInternal: function(effect) { with(Element) {
        undoClipping(effect.element);
        setStyle(effect.element, {height: oldHeight});
      }}
    }, arguments[1] || {})
  );
}

Effect.SwitchOff = function(element) {
  element = $(element);
  var oldOpacity = Element.getInlineOpacity(element);
  return new Effect.Appear(element, { 
    duration: 0.4,
    from: 0,
    transition: Effect.Transitions.flicker,
    afterFinishInternal: function(effect) {
      new Effect.Scale(effect.element, 1, { 
        duration: 0.3, scaleFromCenter: true,
        scaleX: false, scaleContent: false, restoreAfterFinish: true,
        beforeSetup: function(effect) { with(Element) {
          [makePositioned,makeClipping].call(effect.element);
        }},
        afterFinishInternal: function(effect) { with(Element) {
          [hide,undoClipping,undoPositioned].call(effect.element);
          setStyle(effect.element, {opacity: oldOpacity});
        }}
      })
    }
  });
}

Effect.DropOut = function(element) {
  element = $(element);
  var oldStyle = {
    top: Element.getStyle(element, 'top'),
    left: Element.getStyle(element, 'left'),
    opacity: Element.getInlineOpacity(element) };
  return new Effect.Parallel(
    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
    Object.extend(
      { duration: 0.5,
        beforeSetup: function(effect) { with(Element) {
          makePositioned(effect.effects[0].element); }},
        afterFinishInternal: function(effect) { with(Element) {
          [hide, undoPositioned].call(effect.effects[0].element);
          setStyle(effect.effects[0].element, oldStyle); }} 
      }, arguments[1] || {}));
}

Effect.Shake = function(element) {
  element = $(element);
  var oldStyle = {
    top: Element.getStyle(element, 'top'),
    left: Element.getStyle(element, 'left') };
	  return new Effect.Move(element, 
	    { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
	  new Effect.Move(effect.element,
	    { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
	  new Effect.Move(effect.element,
	    { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
	  new Effect.Move(effect.element,
	    { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
	  new Effect.Move(effect.element,
	    { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
	  new Effect.Move(effect.element,
	    { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
        undoPositioned(effect.element);
        setStyle(effect.element, oldStyle);
  }}}) }}) }}) }}) }}) }});
}

Effect.SlideDown = function(element) {
  element = $(element);
  Element.cleanWhitespace(element);
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
  var elementDimensions = Element.getDimensions(element);
  return new Effect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false, 
    scaleFrom: 0,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) { with(Element) {
      makePositioned(effect.element);
      makePositioned(effect.element.firstChild);
      if(window.opera) setStyle(effect.element, {top: ''});
      makeClipping(effect.element);
      setStyle(effect.element, {height: '0px'});
      show(element); }},
    afterUpdateInternal: function(effect) { with(Element) {
      setStyle(effect.element.firstChild, {bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
    afterFinishInternal: function(effect) { with(Element) {
      undoClipping(effect.element); 
      undoPositioned(effect.element.firstChild);
      undoPositioned(effect.element);
      setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
    }, arguments[1] || {})
  );
}
  
Effect.SlideUp = function(element) {
  element = $(element);
  Element.cleanWhitespace(element);
  var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
  return new Effect.Scale(element, 0, 
   Object.extend({ scaleContent: false, 
    scaleX: false, 
    scaleMode: 'box',
    scaleFrom: 100,
    restoreAfterFinish: true,
    beforeStartInternal: function(effect) { with(Element) {
      makePositioned(effect.element);
      makePositioned(effect.element.firstChild);
      if(window.opera) setStyle(effect.element, {top: ''});
      makeClipping(effect.element);
      show(element); }},  
    afterUpdateInternal: function(effect) { with(Element) {
      setStyle(effect.element.firstChild, {bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
    afterFinishInternal: function(effect) { with(Element) {
        [hide, undoClipping].call(effect.element); 
        undoPositioned(effect.element.firstChild);
        undoPositioned(effect.element);
        setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
   }, arguments[1] || {})
  );
}

// Bug in opera makes the TD containing this element expand for a instance after finish 
Effect.Squish = function(element) {
  return new Effect.Scale(element, window.opera ? 1 : 0, 
    { restoreAfterFinish: true,
      beforeSetup: function(effect) { with(Element) {
        makeClipping(effect.element); }},  
      afterFinishInternal: function(effect) { with(Element) {
        hide(effect.element); 
        undoClipping(effect.element); }}
  });
}

Effect.Grow = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransistion: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.full
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: Element.getInlineOpacity(element) };

  var dims = Element.getDimensions(element);    
  var initialMoveX, initialMoveY;
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      initialMoveX = initialMoveY = moveX = moveY = 0; 
      break;
    case 'top-right':
      initialMoveX = dims.width;
      initialMoveY = moveY = 0;
      moveX = -dims.width;
      break;
    case 'bottom-left':
      initialMoveX = moveX = 0;
      initialMoveY = dims.height;
      moveY = -dims.height;
      break;
    case 'bottom-right':
      initialMoveX = dims.width;
      initialMoveY = dims.height;
      moveX = -dims.width;
      moveY = -dims.height;
      break;
    case 'center':
      initialMoveX = dims.width / 2;
      initialMoveY = dims.height / 2;
      moveX = -dims.width / 2;
      moveY = -dims.height / 2;
      break;
  }
  
  return new Effect.Move(element, {
    x: initialMoveX,
    y: initialMoveY,
    duration: 0.01, 
    beforeSetup: function(effect) { with(Element) {
      hide(effect.element);
      makeClipping(effect.element);
      makePositioned(effect.element);
    }},
    afterFinishInternal: function(effect) {
      new Effect.Parallel(
        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
          new Effect.Scale(effect.element, 100, {
            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
        ], Object.extend({
             beforeSetup: function(effect) { with(Element) {
               setStyle(effect.effects[0].element, {height: '0px'});
               show(effect.effects[0].element); }},
             afterFinishInternal: function(effect) { with(Element) {
               [undoClipping, undoPositioned].call(effect.effects[0].element); 
               setStyle(effect.effects[0].element, oldStyle); }}
           }, options)
      )
    }
  });
}

Effect.Shrink = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransistion: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.none
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: Element.getInlineOpacity(element) };

  var dims = Element.getDimensions(element);
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      moveX = moveY = 0;
      break;
    case 'top-right':
      moveX = dims.width;
      moveY = 0;
      break;
    case 'bottom-left':
      moveX = 0;
      moveY = dims.height;
      break;
    case 'bottom-right':
      moveX = dims.width;
      moveY = dims.height;
      break;
    case 'center':  
      moveX = dims.width / 2;
      moveY = dims.height / 2;
      break;
  }
  
  return new Effect.Parallel(
    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
    ], Object.extend({            
         beforeStartInternal: function(effect) { with(Element) {
           [makePositioned, makeClipping].call(effect.effects[0].element) }},
         afterFinishInternal: function(effect) { with(Element) {
           [hide, undoClipping, undoPositioned].call(effect.effects[0].element);
           setStyle(effect.effects[0].element, oldStyle); }}
       }, options)
  );
}

Effect.Pulsate = function(element) {
  element = $(element);
  var options    = arguments[1] || {};
  var oldOpacity = Element.getInlineOpacity(element);
  var transition = options.transition || Effect.Transitions.sinoidal;
  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
  reverser.bind(transition);
  return new Effect.Opacity(element, 
    Object.extend(Object.extend({  duration: 3.0, from: 0,
      afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); }
    }, options), {transition: reverser}));
}

Effect.Fold = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height };
  Element.makeClipping(element);
  return new Effect.Scale(element, 5, Object.extend({   
    scaleContent: false,
    scaleX: false,
    afterFinishInternal: function(effect) {
    new Effect.Scale(element, 1, { 
      scaleContent: false, 
      scaleY: false,
      afterFinishInternal: function(effect) { with(Element) {
        [hide, undoClipping].call(effect.element); 
        setStyle(effect.element, oldStyle);
      }} });
  }}, arguments[1] || {}));
}


function SLJS($0h,$0i,$0j,$0k,$0l){function $a($0m,$0n){this.$3n=function(){return $G();};this.$3o=function(){var $0o=$0p.x-($0q.width/2);var $0r=$0p.x+($0q.width/2);var $0s=$0p.y+($0q.height/2);var $0t=$0p.y-($0q.height/2);var $0u=$0v.$3p(new $01($0o,$0s),$0w);var $0x=$0v.$3p(new $01($0r,$0t),$0w);return new $02($0u.x,$0x.x,$0u.y,$0x.y);};this.$3q=function($0y,$0z){var $0A=this.$3o();if($0A.isInRange($0y)){if($0z){var $0B=$0v.$3r($0y,$0w);var $0C=$0p.x-$0B.x;var $0D=$0p.y-$0B.y;$0E.$3s($0F,$0D,$0C);}}else{this.$3t($0y,$0w);}};this.$3u=function($0G,$0y){var $0H=$b($0y);$0G.simpleWindow=new $M($0I,$0H.top,$0H.left,$0G.text,$0G.options);$0G.simpleWindow.$3v();$0G.slCoord=$0y;$0J.push($0G);};this.$3w=function($0G){if($0G.simpleWindow){$0G.simpleWindow.$3x();}};function $b($0y){var $0B=$0v.$3r($0y,$0w);var $0K=$0v.$3y();var $0L=$0M.$3z(0,0).img;var $0N=$0B.x-($0O.x*$0K)+$0L.tileLeft;var top=$0B.y-($0O.y*$0K)+$0L.tileTop;return new $03(top,$0N);};function $c($0P){var $0Q=$0P.target.marker;$0Q.options.onMouseOverHandler($0Q);};function $d($0P){var $0Q=$0P.target.marker;$0Q.options.onMouseOutHandler($0Q);};function $e($0P,$0R){function $f(){if($0Q.view){$0Q.view.$3A($0Q.top,$0Q.left);$0Q.view.$3v();}else{$0Q.view=new $M($0I,$0Q.top,$0Q.left,$0G.text,$0G.options);$0Q.view.$3v();};if($0Q.view.$3B().onlyOneOpen){for(var i=0;i<$0J.length;i++){v=$0J[i];if(v.simpleWindow!=$0Q.view){if(v.simpleWindow.$3B().windowClass==$0G.options.windowClass){v.simpleWindow.$3C();}}};for(var i=0;i<$0S.length;i++){m=$0S[i];if(m.view){if(m.view!=$0Q.view){if(m.view.$3B().windowClass==$0G.options.windowClass){m.view.$3C();}}}}}};var $0Q=$0R?$0R:$0P.target.marker;if($0Q.options.clickHandler){$0E.$3D($0P);$0Q.options.clickHandler($0Q);return;};var $0G=$0Q.mapWindow;if($0Q.options.centerOnClick){$0C=$0p.x-$0Q.x-$0G.options.width/2;$0D=$0p.y-$0Q.y-$0G.options.height/2;new $0E.$3s($0F,$0D,$0C,$f.bindAsEventListener(this));}else if($0Q.options.autopanOnClick){var $0T=$0Q.options.autopanPadding;$0U=$0Q.x+$0G.options.width+$0T;$0V=$0Q.y+$0G.options.height+$0T;$0W=$0p.x+($0q.width/2);$0X=$0p.y+($0q.height/2);$0Y=$0p.x-($0q.width/2)+$0T;$0Z=$0p.y-($0q.height/2)+$0T;if(($0U>$0W)&&($0V>$0X)){new $0E.$3s($0F,$0X-$0V,$0W-$0U,$f.bindAsEventListener(this));}else if(($0Q.x<$0Y)&&($0Q.y<$0Z)){new $0E.$3s($0F,$0Z-$0Q.y,$0Y-$0Q.x,$f.bindAsEventListener(this));}else if(($0U>$0W)&&($0Q.y<$0Z)){new $0E.$3s($0F,$0Z-$0Q.y,$0W-$0U,$f.bindAsEventListener(this));}else if(($0Q.x<$0Y)&&($0V>$0X)){new $0E.$3s($0F,$0X-$0V,$0Y-$0Q.x,$f.bindAsEventListener(this));}else if($0U>$0W){new $0E.$3s($0F,0,$0W-$0U,$f.bindAsEventListener(this));}else if($0V>$0X){new $0E.$3s($0F,$0X-$0V,0,$f.bindAsEventListener(this));}else if($0Q.x<$0Y){new $0E.$3s($0F,0,$0Y-$0Q.x,$f.bindAsEventListener(this));}else if($0Q.y<$0Z){new $0E.$3s($0F,$0Z-$0Q.y,0,$f.bindAsEventListener(this));}else{$f();}}else{$f();}};this.$3E=function($0Q){this.$3q($0Q.slCoord);$e(null,$0Q);};this.$3F=function($0Q,$0G){var $10=$0S;var $0B=$0v.$3r($0Q.slCoord,$0w);$0Q.x=$0B.x;$0Q.y=$0B.y;var $11=$0Q.icons[$0w-1];var $0L=$0M.$3z(0,0).img;var $0K=$0v.$3y();$0Q.left=$0Q.x-($0O.x*$0K)+$0L.tileLeft;$0Q.top=$0Q.y-($0O.y*$0K)+$0L.tileTop;if($0Q.options.horizontalAlign=="center"){$12=-$11.mainImg.width/2;}else if($0Q.options.horizontalAlign=="right"){$12=-$11.mainImg.width;}else{$12=0;}if($0Q.options.verticalAlign=="middle"){$13=-$11.mainImg.height/2;}else if($0Q.options.verticalAlign=="bottom"){$13=-$11.mainImg.height;}else{$13=0;};var $14=$0E.$3G($11.mainImg.URL,$11.mainImg.width,$11.mainImg.height,null,null,null,$11.mainImg.isAlpha());$14.marker=$0Q;var $15=document.createElement("a");$15.style.zIndex=5000+$0Q.options.zLayer;$15.onmousedown=function(){return false;};$15.style.position="absolute";$15.style.left=$0E.$3H($0Q.left+$12);$15.style.top=$0E.$3H($0Q.top+$13);$15.appendChild($14);if($0G||$0Q.options.clickHandler){$0Q.mapWindow=$0G;if($16.$3I('ie')){$0E.$3J($15,"hand");}else{$15.href="javascript:void(0)";};Event.observe($15,"click",$e.bindAsEventListener(this));Event.observe($15,"mousedown",function($0P){$0E.$3D($0P);return false;});};if($0Q.options.onMouseOutHandler){Event.observe($15,"mouseout",$d.bindAsEventListener(this));};if($0Q.options.onMouseOverHandler){Event.observe($15,"mouseover",$c.bindAsEventListener(this));};$0I.appendChild($15);if($11.hasShadow()){var $17=$0E.$3G($11.shadowImg.URL,$11.shadowImg.width,$11.shadowImg.height,$0Q.left+$12,$0Q.top+$13,4000,$11.shadowImg.isAlpha());$17.onmousedown=function(){return false;};$0I.appendChild($17);$0Q.shadowImg=$17;}else{$0Q.shadowImg=null;};$0Q.img=$15;$10.push($0Q);};/*this.$3K=function(marker,remote){function $g(new_view){__hideLoading();new_view.loading=false;if(new_view.$3B().onlyOneOpen){for(var i=0;i<__views.length;i++){v=__views[i];if(v!=new_view){if(v.$3B().windowClass==marker.windowOptions.windowClass){v.$3C();}}}}};function $e(newEvent){var marker=newEvent.target.marker;leftd=__centerMapImageCoord.x-marker.x-marker.windowOptions.width/2;topd=__centerMapImageCoord.y-marker.y-marker.windowOptions.height/2;rightd=marker.x+marker.windowOptions.width+40;bottomd=marker.y+marker.windowOptions.height+40;maxRight=__centerMapImageCoord.x+(__viewportSize.width/2);maxBottom=__centerMapImageCoord.y+(__viewportSize.height/2);if((rightd>maxRight)&&(bottomd>maxBottom)){new $Helper.$3s(__dragController,maxBottom-bottomd,maxRight-rightd);}else if(rightd>maxRight){new $Helper.$3s(__dragController,0,maxRight-rightd);}else if(bottomd>maxBottom){new $Helper.$3s(__dragController,maxBottom-bottomd,0);};if(!(__isLoadingVisible())){__showLoading();};if(marker.view){if(!(marker.view.loading)){marker.view.$3A(marker.top,marker.left);marker.view.$3v();_onCompleteHandler(marker.view);}}else{var view=new $InfoWindow(__divobject,marker.URL,_onCompleteHandler.bindAsEventListener(self),false,marker.top,marker.left,marker.windowOptions);marker.view=view;marker.view.loading=true;}};function $c(newEvent){var marker=newEvent.target.marker;marker.options.onMouseOverHandler(marker);};function $d(newEvent){var marker=newEvent.target.marker;marker.options.onMouseOutHandler(marker);};var markers=__markers;if(remote){markers=__remoteMarkers;};var pixelCoord=__mapType.$3r(marker.slCoord,__zoomLevel);marker.x=pixelCoord.x;marker.y=pixelCoord.y;var icon=marker.icons[__zoomLevel-1];var topLeftImage=__tileMatrix.$3z(0,0).img;var tileSize=__mapType.$3y();marker.left=marker.x-(__topLeftTile.x*tileSize)+topLeftImage.tileLeft;marker.top=marker.y-(__topLeftTile.y*tileSize)+topLeftImage.tileTop;markerOffsetLeft=-icon.mainImg.width/2;markerOffsetTop=-icon.mainImg.height/2;var newImg=$Helper.$3G(icon.mainImg.URL,icon.mainImg.width,icon.mainImg.height,null,null,null,icon.mainImg.isAlpha());newImg.marker=marker;var newMarker=document.createElement("a");newMarker.style.zIndex=5000;newMarker.onmousedown=function(){return false;};newMarker.style.position="absolute";newMarker.style.left=$Helper.$3H(marker.left+markerOffsetLeft);newMarker.style.top=$Helper.$3H(marker.top+markerOffsetTop);newMarker.appendChild(newImg);if(!marker.windowOptions.doNothing==true){newMarker.href="javascript:void(0)";Event.observe(newMarker,"click",_onMarkerClickHandler.bindAsEventListener(this));Event.observe(newMarker,"mousedown",function(newEvent){$Helper.$3D(newEvent);return false;});Event.observe(newMarker,"mouseover",_onMarkerMouseOver.bindAsEventListener(this));Event.observe(newMarker,"mouseout",_onMarkerMouseOut.bindAsEventListener(this));};__divobject.appendChild(newMarker);if(icon.hasShadow()){var imgShadow=$Helper.$3G(icon.shadowImg.URL,icon.shadowImg.width,icon.shadowImg.height,marker.left,marker.top,4000,icon.shadowImg.isAlpha());imgShadow.onmousedown=function(){return false;};__divobject.appendChild(imgShadow);marker.shadowImg=imgShadow;}else{marker.shadowImg=null;};marker.img=newMarker;markers.push(marker);};*/this.$3L=function($0Q){var $10=$0S;for(var i=0;i<$10.length;i++){m=$10[i];if(m==$0Q){if(m.view){m.view.$3x();}try{$0I.removeChild(m.img);if(m.shadowImg){$0I.removeChild(m.shadowImg);}$10.splice(i,1);}catch(e){alert("couldn't remove "+id);}}}};this.$3M=function(){var $10=$0S;for(var i=0;i<$10.length;i++){m=$10[i];if(m.view){m.view.$3x();}try{$0I.removeChild(m.img);if(m.shadowImg){$0I.removeChild(m.shadowImg);}}catch(e){alert("couldn't remove "+id);}}$0S=new Array();};this.$3t=function($0y,$18){$19=new $01($0y.x,$0y.y);$k($18);var $1a=$0v.$3r($19,$0w);$E($1a);$1b=true;$s();};this.$3N=function(){$0F.$3O();};this.$3P=function(){$0F.$3Q();};this.$3R=function(){this.$3S($0w-1);};this.$3T=function(){this.$3S($0w+1);};this.$3S=function($18){var $1c=$G();$k($18);self.$3t($1c,$18);};this.$3U=function(){return $0w;};this.$3V=function(){$0E.$3s($0F,0,Math.floor($0q.width/2));};this.$3W=function(){$0E.$3s($0F,0,-Math.floor($0q.width/2));};this.$3X=function(){$0E.$3s($0F,Math.floor($0q.height/2),0);};this.$3Y=function(){$0E.$3s($0F,-Math.floor($0q.height/2),0);};function $h(){$1d--;if($1d==0){Element.hide($1e);}};function $i(){$1d++;if($1d==1){Element.show($1e);}};function $j(){if($1d==0){return false;}else{return true;}};function $k($1f){if(($1g<=$1f)&&($1f<=$1h)){$0w=$1f;if($1i.hasZoomControls){if($0w==$1h){$1j.removeChild($1j.firstChild);$1j.appendChild($1j.disabled_img);}if($0w==$1g){$1k.removeChild($1k.firstChild);$1k.appendChild($1k.disabled_img);}if($0w!=$1h){$1j.removeChild($1j.firstChild);$1j.appendChild($1j.active_img);}if($0w!=$1g){$1k.removeChild($1k.firstChild);$1k.appendChild($1k.active_img);}}}}function $l($1l){var $0K=$0v.$3y();$1l.img=$0E.$3G(null,$0K,$0K,null,null,1000);$1l.img.style.position="absolute";$0I.appendChild($1l.img);$C($1l.img,$1l.x,$1l.y);if($1i.overlaySpec){$1l.img.overlay=$0E.$3G(null,$0K,$0K,null,null,1001,$1i.overlaySpec.usePNG);$1l.img.overlay.style.position="absolute";$0I.appendChild($1l.img.overlay);$C($1l.img.overlay,$1l.x,$1l.y,true);}};function $m($1l){$0I.removeChild($1l.img);if($1i.overlaySpec){$0I.removeChild($1l.img.overlay)}};function $n($1l){$0I.removeChild($1l.img);$C($1l.img,$1l.x,$1l.y);$0I.appendChild($1l.img);if($1i.overlaySpec){$0I.removeChild($1l.img.overlay);$C($1l.img.overlay,$1l.x,$1l.y,true);$0I.appendChild($1l.img.overlay);}};function $o(){if($0q.width!=$1m.offsetWidth||$0q.height!=$1m.offsetHeight){$w();$0M.$3Z($1n);$E($0p);if($1i.hasPanningControls){$A();}$s();}};function $p($0P){if($1i.singleClickHandler){var $1c=$r($0P);$1i.singleClickHandler($1c.x,$1c.y);}};function $q($0P){if($1i.doubleClickHandler){var $1c=$r($0P);$1i.doubleClickHandler($1c.x,$1c.y);}};function $r($0P){var $1a=new $01();var $1o=new $01();if($16.$3I('ie')){var $1p=$0P.target||$0P.srcElement;var $1q=$0E.$40($1p,$1m);$1o.x=$0P.offsetX+$1q.x;$1o.y=$0P.offsetY+$1q.y;}else{var $1q=$0E.$41($1m);$1o.x=$0P.pageX-$1q.x;$1o.y=$0P.pageY-$1q.y;}$1a.x=$0p.x-($0q.width/2)+$1o.x;$1a.y=$0p.y-($0q.height/2)+$1o.y;return $0v.$3p($1a,$0w);}function $s(){if($1i.onStateChangedHandler){$1i.onStateChangedHandler();}};function $t(){if($1b){$19=null;var $0K=$0v.$3y();$0p.x=($0O.x*$0K)+Math.floor($0q.width/2)+$1r.width-$D().width;$0p.y=($0O.y*$0K)+Math.floor($0q.height/2)+$1r.height-$D().height;while($D().width<-$1r.width/2){$1s.width++;$0O.x++;$0M.$42();};while($D().width>$1r.width/2){$1s.width--;$0O.x--;$0M.$43();}while($D().height<-$1r.height/2){$1s.height++;$0O.y++;$0M.$44();};while($D().height>$1r.height/2){$1s.height--;$0O.y--;$0M.$45();}}};function $u(){for(var i=0;i<$0J.length;i++){v=$0J[i];v.simpleWindow.$46();}for(var i=0;i<$0S.length;i++){m=$0S[i];if(m.view){m.view.$46();}}};function $v(){$s();};function $w(){var $0K=$0v.$3y();$0q.width=$1m.offsetWidth,$0q.height=$1m.offsetHeight;$1n.width=3+Math.ceil($0q.width/$0K);$1n.height=3+Math.ceil($0q.height/$0K);$1r.width=Math.floor(($1n.width*$0K-$0q.width)/2);$1r.height=Math.floor(($1n.height*$0K-$0q.height)/2);};function $x(){$1t=document.createElement("div");$1t.style.zIndex=7000;$1t.style.position="absolute";$1t.style.margin="5px";$1t.style.padding="5px";$1t.style.bottom=$0E.$3H(10);$1t.style.left=$0E.$3H(10);$1t.style.backgroundColor="#D8E8ED";$1t.style.fontSize=$0E.$3H(11);$1t.style.fontWeight="bold";$1t.unselectable="on";$1t.style.MozUserSelect="none";$1u=document.createElement("img");$1u.src=$0h+"images/loading.gif";$1u.style.marginRight=$0E.$3H(5);$1v=document.createElement("span");$1v.innerHTML="Loading";$1t.appendChild($1u);$1t.appendChild($1v);$1e=$1t;$1m.appendChild($1t);$1d=1;$h();};function $y($0P){$0E.$3D($0P);return false;};function $z(){$1w=$0E.$3G($0h+"/images/b_pan_l.png",17,17,null,null,null,true);$1x=$0E.$3G($0h+"/images/b_pan_r.png",17,17,null,null,null,true);$1y=$0E.$3G($0h+"/images/b_pan_u.png",17,17,null,null,null,true);$1z=$0E.$3G($0h+"/images/b_pan_d.png",17,17,null,null,null,true);$1z.style.position="relative";$1y.style.position="relative";$1w.style.position="relative";$1x.style.position="relative";$1A=document.createElement("a");$1B=document.createElement("a");$1C=document.createElement("a");$1D=document.createElement("a");$1A.href="javascript:void(0)";$1B.href="javascript:void(0)";$1C.href="javascript:void(0)";$1D.href="javascript:void(0)";$1A.appendChild($1w);$1B.appendChild($1x);$1C.appendChild($1y);$1D.appendChild($1z);$A();if($16.$3I('ie')){$0E.$3J($1w,"hand");Event.observe($1A,"click",$y);$0E.$3J($1x,"hand");Event.observe($1B,"click",$y);$0E.$3J($1y,"hand");Event.observe($1C,"click",$y);$0E.$3J($1z,"hand");Event.observe($1D,"click",$y);}Event.observe($1A,"click",self.$3V.bindAsEventListener(self));Event.observe($1B,"click",self.$3W.bindAsEventListener(self));Event.observe($1C,"click",self.$3X.bindAsEventListener(self));Event.observe($1D,"click",self.$3Y.bindAsEventListener(self));$1m.appendChild($1A);$1m.appendChild($1B);$1m.appendChild($1C);$1m.appendChild($1D);};function $A(){$1A.style.position="absolute";$1A.style.zIndex=8000;$1A.style.top=$0E.$3H(Math.floor($0q.height/2));$1A.style.left=$0E.$3H(10);$1B.style.position="absolute";$1B.style.zIndex=8000;$1B.style.top=$0E.$3H(Math.floor($0q.height/2));$1B.style.right=$0E.$3H(10);$1C.style.position="absolute";$1C.style.zIndex=8000;$1C.style.top=$0E.$3H(10);$1C.style.left=$0E.$3H(Math.floor($0q.width/2));$1D.style.position="absolute";$1D.style.zIndex=8000;$1D.style.bottom=$0E.$3H(10);$1D.style.left=$0E.$3H(Math.floor($0q.width/2));}function $B(){$1E=document.createElement("div");$1E.style.zIndex=8000;$1E.style.position="absolute";$1E.style.bottom=$0E.$3H(10);$1E.style.right=$0E.$3H(10);$1E.style.margin=$0E.$3H(0);$1E.style.padding=$0E.$3H(0);$1E.style.textAlign="center";$1k=document.createElement("a");$1k.href="javascript:void(0)";$1k.style.textDecoration="none";$1k.style.marginRight="5px";$1k.active_img=$0E.$3G($0h+"/images/b_zoom_in.png",17,17,null,null,null,true);$1k.active_img.style.position="relative";$1k.active_img.style.padding="0px";$1k.active_img.style.margin="0px";$1k.disabled_img=$0E.$3G($0h+"/images/b_zoom_in_gray.png",17,17,null,null,null,true);$1k.disabled_img.style.position="relative";$1k.disabled_img.style.padding="0px";$1k.disabled_img.style.margin="0px";$1j=document.createElement("a");$1j.href="javascript:void(0)";$1j.style.textDecoration="none";$1j.style.marginLeft="5px";$1j.active_img=$0E.$3G($0h+"/images/b_zoom_out.png",17,17,null,null,null,true);$1j.active_img.style.position="relative";$1j.active_img.style.padding="0px";$1j.active_img.style.margin="0px";$1j.disabled_img=$0E.$3G($0h+"/images/b_zoom_out_gray.png",17,17,null,null,null,true);$1j.disabled_img.style.position="relative";$1j.disabled_img.style.padding="0px";$1j.disabled_img.style.margin="0px";$1k.appendChild($1k.active_img);$1j.appendChild($1j.active_img);if($16.$3I('ie')){$0E.$3J($1k.active_img,"hand");Event.observe($1k,"click",$y);$0E.$3J($1j.active_img,"hand");Event.observe($1j,"click",$y);}Event.observe($1k,"click",self.$3R.bindAsEventListener(self));Event.observe($1j,"click",self.$3T.bindAsEventListener(self));$1E.appendChild($1k);$1E.appendChild($1j);$1m.appendChild($1E);};function $C($1F,x,y,$1G){var $1H=$1G?$1i.overlaySpec:$0v;if(!$0O){$1F.src=$0v.$47();}else{var $1I=$0O.x+x;var $1J=$0O.y+y;if($1H.isTileWithinRange($0v.$48($1I,$1J,$0w))){var $1K=$1H.getTileURL($1I,$1J,$0w);if($16.$3I('ie')&&$1H.usePNG){$1F.style.filter='';$1F.loader.src=$1K;}else{$1F.src=$1H.getEmptyTileUrl();$1F.src=$1K;}}else{$1F.src=$1H.getOutOfBoundsTileUrl($1I,$1J,$0w);}}var $0K=$0v.$3y();var top=($1s.height+y)*$0K-$1r.height;var $0N=($1s.width+x)*$0K-$1r.width;$1F.onmousedown=function(){return false};$1F.style.top=$0E.$3H(top);$1F.style.left=$0E.$3H($0N);$1F.tileTop=top;$1F.tileLeft=$0N;};function $D(){var $0K=$0v.$3y();return new $04($0F.$49()+$1s.width*$0K,$0F.$4a()+$1s.height*$0K);};function $E($0y){$0p.x=$0y.x;$0p.y=$0y.y;if(!$0O){$0O=new $01();}var $1L=$0y.x-($1r.width+Math.floor($0q.width/2));var $1M=$0y.y-($1r.height+Math.floor($0q.height/2));var $0K=$0v.$3y();$0O.x=Math.floor($1L/$0K);$0O.y=Math.floor($1M/$0K);var $1N=($0O.x*$0K)-$1L;var $1O=($0O.y*$0K)-$1M;if($1N<-$1r.width/2){$0O.x++;$1N+=$0K}else if($1N>$1r.width/2){$0O.x;$1N-=$0K}if($1O<-$1r.height/2){$0O.y++;$1O+=$0K}else if($1O>$1r.height/2){$0O.y--;$1O-=$0K}$1s.width=0;$1s.height=0;$F();$J();$0F.$4b($1O,$1N);};function $F(){if($0M.$4c()){return}var $1P=$0M.$4d();var $1Q=$0M.$4e();var $1R=new Array();for(var x=0;x<$1P;x++){for(var y=0;y<$1Q;y++){$1S=$0M.$3z(x,y).img;$1S.coordX=x;$1S.coordY=y;var $1T=Math.min(x,$1P-x-1);var $1U=Math.min(y,$1Q-y-1);if($1T==0||$1U==0){$1S.priority=0}else{$1S.priority=$1T+$1U}$1R.push($1S)}}$1R.sort(function(a,b){return b.priority-a.priority});for(var i=0;i<$1R.length;i++){var $1S=$1R[i];if($16.$3I('ie')){$0I.removeChild($1S)}$C($1S,$1S.coordX,$1S.coordY);if($16.$3I('ie')){$0I.appendChild($1S)}if($1i.overlaySpec){if($16.$3I('ie')){$0I.removeChild($1S.overlay)}$C($1S.overlay,$1S.coordX,$1S.coordY,true);if($16.$3I('ie')){$0I.appendChild($1S.overlay)}}}};function $G(){if($19){return $19}else{return $0v.$3p($0p,$0w)}/*if(self.lastLatLng){var ea=self.spec.getBitmapCoordinate(self.lastLatLng.y,self.lastLatLng.x,__zoomLevel);if(ea.equals(self.centerBitmap)){slCoord.x=self.lastLatLng.x;slCoord.y=self.lastLatLng.y;return slCoord}}*/};function $H($1V){if($1V){for(var i=0;i<$1V.length;i++){m=$1V[i];$0I.removeChild(m.img);if(m.shadowImg){$0I.removeChild(m.shadowImg);}}}};function $I(){for(var j=0;j<$0J.length;j++){$0J[j].simpleWindow.$3x();}}function $J(){var $1W=$0S;var $1X=$0J;$H($0S);$0S=new Array();for(var i=0;i<$1W.length;i++){m=$1W[i];if(m.mapWindow){self.$3F(m,m.mapWindow);}else{self.$3F(m);}if(m.view){m.view.$3A(m.top,m.left);}}for(var j=0;j<$1X.length;j++){v=$1X[j];$0H=$b(v.slCoord);v.simpleWindow.$3A($0H.top,$0H.left);}};/*function $K(){_deleteMarkers(__remoteMarkers);__remoteMarkers=new Array();_showRemoteMarkers();};function $L(){if(__mapType.$4f()){new Ajax.Request(__mapType.$4g(),{asynchronous:true,onComplete:function(req){eval(req.responseText)}});}};*/var self=this;var $1b=false;var $1m=$0m;$1m.style.padding=$0E.$3H(0);if($1m.style.position!="absolute"){$1m.style.position="relative"};$1m.style.overflow="hidden";var $0I=document.createElement("div");$1m.appendChild($0I);$1m.align="left";$0I.id="map";$0I.style.position="absolute";$0I.style.top="0px";$0I.style.left="0px";$0I.zIndex=1000;var $0S=new Array();var $1Y=new Array();var $0J=new Array();var $0v=new $S();var $1s=new $04();var $0p=new $01();var $1n=new $04();var $1r=new $04();var $0q=new $04();var $0O=null;var $19=null;var $1d,$1e;var $0F=new $V($0I,$t.bindAsEventListener(this),$u.bindAsEventListener(this),$v.bindAsEventListener(this),$p.bindAsEventListener(this));$w();var $1i=new $0a($0n);var $1A,$1B,$1D,$1C;var $1k,$1j;var $0w=1;var $1g=($1i.zoomMax<$0v.zoomMax)?$0v.zoomMax:$1i.zoomMax;var $1h=($1i.zoomMin>$0v.zoomMin)?$0v.zoomMin:$1i.zoomMin;if($1i.hasZoomControls){$B();}if($1i.hasPanningControls){$z();}var $0M=new $0f($1n,$l.bindAsEventListener(this),$m.bindAsEventListener(this),$n.bindAsEventListener(this));if($1i.doubleClickHandler){$0I.ondblclick=$q.bindAsEventListener(this);}Event.observe(window,"resize",$o.bindAsEventListener(this));this.centerAndZoomAtSLCoord=this.$3t;this.addMarker=this.$3F;this.removeMarker=this.$3L;this.removeMapWindow=this.$3w;this.removeAllMarkers=this.$3M;this.addMapWindow=this.$3u;this.setCurrentZoomLevel=this.$3S;this.getCurrentZoomLevel=this.$3U;this.zoomIn=this.$3R;this.zoomOut=this.$3T;this.panLeft=this.$3V;this.panRight=this.$3W;this.panUp=this.$3X;this.panDown=this.$3Y;this.disableDragging=this.$3N;this.enableDragging=this.$3P;this.getViewportBounds=this.$3o;this.panOrRecenterToSLCoord=this.$3q;this.getMapCenter=this.$3n;this.clickMarker=this.$3E;this.notifyResize=$o;};function $M($0m,top,$0N,$1Z,$20){this.$3A=function(top,$0N){$21.style.top=$0E.$3H(top);$21.style.left=$0E.$3H($0N);$22.style.top=$0E.$3H(top);$22.style.left=$0E.$3H($0N);};this.$3B=function(){return $23;};this.$3v=function(){$R();$Q();if($23.noEffect){Element.show($21);Element.show($22);}else{$0E.$4h($21);$0E.$4h($22);}};function $N(){if($23.noEffect){Element.hide($21);Element.hide($22);$R();$Q();}else{$0E.$4i($21);$0E.$4i($22);}};this.$46=function(){if($23.closeOnMove){this.$3C();}};this.$3C=function($0P){$N();};this.$3x=function(){$R();};function $O($0P){$0E.$3D($0P);};function $P($0P){if($23.bringToTop){$R();$Q();}if($23.closeOnClick){$N();}};function $Q(){$1m.appendChild($21);$1m.appendChild($22);};function $R(){$1m.removeChild($21);$1m.removeChild($22);};var self=this;var $1m=$0m;var $21=document.createElement("div");if($20){var $23=$20;}else{var $23=new $09();}if($23.alwaysOnTop){var $24=7000;}else{var $24=6000;}$21.style.zIndex=$24;$21.style.width=$0E.$3H($23.width);$21.style.height=$0E.$3H($23.height);$21.style.border=" 1px solid black";$21.style.backgroundColor="white";$21.style.position="absolute";$21.style.margin=$0E.$3H(0);$21.style.marginTop=$0E.$3H(9);$21.style.padding=$0E.$3H(0);$21.unselectable="on";$21.style.MozUserSelect="none";var $22=document.createElement("img");$22.style.zIndex=$24;$22.src=$0h+"images/corner_vert.gif";$22.style.position="absolute";$22.style.padding=$0E.$3H(0);$22.style.margin=$0E.$3H(0);$22.width=10;$22.height=10;var $25=document.createElement("img");$25.src=$0h+"images/close_new.gif";$25.style.border=$0E.$3H(0);$25.width=9;$25.height=9;var $26=document.createElement("a");$26.href="javascript:void(0)";$26.style.textDecoration="none";$26.appendChild($25);$26.style.position="absolute";$26.style.right=$0E.$3H(5);$26.style.top=$0E.$3H(5);if($23.allowGoThere==true){var $27=document.createElement("img");$27.src=$0h+"images/go_there.gif";$27.style.border=$0E.$3H(0);var $28=document.createElement("a");$28.href="javascript:void(0)";$28.style.textDecoration="none";$28.appendChild($27);$28.style.position="absolute";$28.style.right=$0E.$3H(18);$28.style.top=$0E.$3H(5);$21.appendChild($28);}Event.observe($26,"click",this.$3C.bindAsEventListener(this));Event.observe($21,"mousedown",$O.bindAsEventListener(this));Event.observe($21,"click",$P.bindAsEventListener(this));var $29=document.createElement("div");$29.style.padding=$0E.$3H($23.padding);$29.style.margin=$0E.$3H(0);Element.update($29,$1Z);$21.appendChild($29);$21.appendChild($26);$1m.appendChild($21);$1m.appendChild($22);this.$3A(top,$0N);Element.hide($21);Element.hide($22);};function $S(){function $T($18){return $2a*2/Math.pow(2,$18);};function $U($18){return Math.pow(2,$18-1);};this.$48=function(x,y,$18){var $2b=$U($18);var $2c=x*$2b;var $2d=$2c+($2b-1);var $2e=$2f-y*$2b;var $2g=$2e-($2b-1);return new $02($2c,$2d,$2g,$2e);};this.$4j=function($0A){if(((($0i<=$0A.xMin)&&($0A.xMin<=$0j))||(($0i<=$0A.xMax)&&($0A.xMax<=$0j)))&&((($0k<=$0A.yMin)&&($0A.yMin<=$0l))||(($0k<=$0A.yMax)&&($0A.yMax<=$0l)))){return true;}else{return false;};/*if(($XMIN<=top_left_slcoord_x)&&(top_left_slcoord_x<=$XMAX)&&($YMIN<=top_left_slcoord_y)&&(top_left_slcoord_y<=$YMAX)){return true;}else if};*/};this.$47=function(){return $2h.src;};this.$4k=function(x,y,$18){return $2i.src;};this.$3y=function(){return $2a;};this.$3r=function($0y,$18){var $2j=$T($18);var x=$0y.x*$2j;var y=($2f-$0y.y)*$2j;return new $01(x,y);};this.$3p=function($0y,$18){var $2j=$T($18);var x=$0y.x/$2j;var y=(-$0y.y/$2j)+$2f;return new $01(x,y);};this.$4l=function(x,y,$18){var imagesource="http://services.katharineberry.co.uk/mapapi/";
;return imagesource+"grid/map_image/"+x+"-"+y+"-"+$18+"-0";};this.$4g=function(){return $2l;};var $2a=256;var $2k=$0h+"grid/map_image";var $2f=1280;var $2m=1100;var $2n=960;var $2o=1100;var $2p=945;var $2h=new Image(256,256);$2h.src=$0h+"images/white.jpg";var $2i=new Image(256,256);$2i.src=$0h+"images/ocean.jpg";this.usePNG=false;this.getTileURL=this.$4l;this.isTileWithinRange=this.$4j;this.getEmptyTileUrl=this.$47;this.getOutOfBoundsTileUrl=this.$4k;this.zoomMax=1;this.zoomMin=7;};function $V(element,$2q,$2r,$2s,$2t){this.$49=function(){return this.left;};this.$4a=function(){return this.top;};this.$3O=function(){$2u=true;};this.$3Q=function(){$2u=false;};this.$4b=function(top,$0N){this.left=$0N;this.top=top;$21.style.left=$0E.$3H(this.left);$21.style.top=$0E.$3H(this.top);if(this.$4m){this.$4m();}};function $O($0P){if(!$2u){$2v=true;$2w.x=$0P.screenX;$2w.y=$0P.screenY;Event.observe($2x,"mousemove",$2y);Event.observe($2x,"mouseup",$2z);if($21.setCapture){$21.setCapture()}$2A.x=$0P.screenX;$2A.y=$0P.screenY;if(self.$4n){self.$4n($0P);}return false;}};function $W($0P){if(!$2u){if($21.style.cursor!="move"){$0E.$3J($21,"move");}var $2B=self.left+($0P.screenX-$2w.x);var $2C=self.top+($0P.screenY-$2w.y);$2w.x=$0P.screenX;$2w.y=$0P.screenY;self.$4b($2C,$2B);return false;}};function $X($0P){if(!$2u&&$2v){Event.stopObserving($2x,"mousemove",$2y);Event.stopObserving($2x,"mouseup",$2z);$0E.$3J($21,"");if(document.releaseCapture){document.releaseCapture()}if(!($2A.x==$0P.screenX&&$2A.y==$0P.screenY)){if(self.$4o){self.$4o($0P);}}else{self.$4p($0P);}$2v=false;return false;}else if($2v){self.$4p($0P);}};function $Y($0P){if(!$2u){if(!$0P.relatedTarget){$2z($0P)}}};var self=this;var $21=element;var $2w=new $01();var $2A=new $01();var $2u=false;var $2v=false;this.$4b(0,0);var $2D=$O.bindAsEventListener(this);var $2y=$W.bindAsEventListener(this);var $2z=$X.bindAsEventListener(this);var $2E=$Y.bindAsEventListener(this);this.$4m=$2q;this.$4o=$2s;this.$4n=$2r;this.$4p=$2t;var $2x=$21.setCapture?$21:window;if($16.$3I('gecko')){Event.observe(window,"mouseout",$Y.bindAsEventListener(this))}Event.observe($21,"mousedown",$O.bindAsEventListener(this));}/*ViewFrame=Class.create();ViewFrame.prototype={initialize:function(container,src,slmap,draggable,options){this.container=container;this.slmap=slmap;var iframe=document.createElement("iframe");iframe.style.height="400px";iframe.style.border="none";if(src){iframe.src=this.iframesrc;};this.iframe=iframe;viewframe=this;Event.observe(this.iframe,"load",function(){viewframe.onload()});var topbar=document.createElement("div");topbar.style.backgroundColor="gray";topbar.style.padding="10px";var framediv=document.createElement("div");framediv.style.position="absolute";framediv.appendChild(topbar);framediv.appendChild(iframe);this.framediv=framediv;Object.extend(this.framediv.style,options);if(src){this.refresh(src);};this.container.appendChild(framediv);if(draggable)this.dragController=new $Draggable(this.framediv);},$updatePosition:function(top,left){this.framediv.style.top=$Helper.$3H(top);this.framediv.style.left=$Helper.$3H(left);},refresh:function(src){Element.hide(this.framediv);this.slmap.$4q();if(src){this.iframe.src=src;}else{this.iframe.src=this.iframe.src;}},$showUrl:function(url){if(this.framediv.style.display=="none"){this.framediv.style.display='';};this.refresh(url);},onViewClose:function(event){Element.toggle(this.iframe);},onload:function(){if(this.slmap.$4r()){this.slmap.$4s()};Element.show(this.framediv);slmap.$K();},hide:function(){}};*/var $2F=new Array();var $2G=false;/*function $Z(container,src,onCompleteHandler,draggable,top,left,windowOptions){this.$3A=function(top,left){__divObject.style.top=$Helper.$3H(top);__divObject.style.left=$Helper.$3H(left);__corner.style.top=$Helper.$3H(top);__corner.style.left=$Helper.$3H(left);};this.$3B=function(){return __windowOps;};this.$3v=function(){_remove();_add();if(__windowOps.noEffect){Element.show(__divObject);Element.show(__corner);}else{$Helper.$4h(__divObject);$Helper.$4h(__corner);}};this.$4t=function(URL){if(!URL){URL=__targetUrl;};if($ajaxLocked==true){$ajaxQueue.push(this);}else{$ajaxLocked=true;new Ajax.Updater(__divcontent,URL,{method:'get',asynchronous:true,evalScripts:true,onComplete:_onComplete.bind(this)});}};this.$46=function(){if(__windowOps.closeOnMove){this.$3C();}};this.$3C=function(newEvent){_hide();};function $N(){if(__windowOps.noEffect){Element.hide(__divObject);Element.hide(__corner);_remove();_add();}else{$Helper.$4i(__divObject);$Helper.$4i(__corner);}};function $O(newEvent){$Helper.$3D(newEvent);};function $P(newEvent){if(__windowOps.bringToTop){_remove();_add();};if(__windowOps.closeOnClick){_hide();}};function $00(newEvent){this.$3v();if(__onCompleteHandler){__onCompleteHandler(self);};$ajaxLocked=false;if($ajaxQueue.length>0){obj=$ajaxQueue.shift();obj.$4t();}};function $Q(){__container.appendChild(__divObject);__container.appendChild(__corner);};function $R(){__container.removeChild(__divObject);__container.removeChild(__corner);};var self=this;var __container=container;var __targetUrl=src;if(onCompleteHandler){var __onCompleteHandler=onCompleteHandler;};var __divObject=document.createElement("div");if(windowOptions){var __windowOps=windowOptions;}else{var __windowOps=new $WindowOptions();};if(__windowOps.alwaysOnTop){var __zIndex=7000;}else{var __zIndex=6000;};__divObject.style.zIndex=__zIndex;__divObject.style.width=$Helper.$3H(__windowOps.width);__divObject.style.height=$Helper.$3H(__windowOps.height);__divObject.style.border=" 1px solid black";__divObject.style.backgroundColor="white";__divObject.style.position="absolute";__divObject.style.margin=$Helper.$3H(0);__divObject.style.marginTop=$Helper.$3H(9);__divObject.style.padding=$Helper.$3H(0);__divObject.unselectable="on";__divObject.style.MozUserSelect="none";var __corner=document.createElement("img");__corner.style.zIndex=__zIndex;__corner.src=$SERVICES_URL+"images/corner_vert.gif";__corner.style.position="absolute";__corner.style.padding=$Helper.$3H(0);__corner.style.margin=$Helper.$3H(0);var closeButtonImg=document.createElement("img");closeButtonImg.src=$SERVICES_URL+"images/close_new.gif";closeButtonImg.style.border=$Helper.$3H(0);var closeButton=document.createElement("a");closeButton.href="javascript:void(0)";closeButton.style.textDecoration="none";closeButton.appendChild(closeButtonImg);closeButton.style.position="absolute";closeButton.style.right=$Helper.$3H(5);closeButton.style.top=$Helper.$3H(5);if(__windowOps.allowGoThere==true){var goThereButtonImg=document.createElement("img");goThereButtonImg.src=$SERVICES_URL+"images/go_there.gif";goThereButtonImg.style.border=$Helper.$3H(0);var goThereButton=document.createElement("a");goThereButton.href="javascript:void(0)";goThereButton.style.textDecoration="none";goThereButton.appendChild(goThereButtonImg);goThereButton.style.position="absolute";goThereButton.style.right=$Helper.$3H(18);goThereButton.style.top=$Helper.$3H(5);__divObject.appendChild(goThereButton);};Event.observe(closeButton,"click",this.$3C.bindAsEventListener(this));Event.observe(__divObject,"mousedown",_onMouseDown.bindAsEventListener(this));Event.observe(__divObject,"click",_onClick.bindAsEventListener(this));var __divcontent=document.createElement("div");__divcontent.style.padding=$Helper.$3H(0);__divcontent.style.margin=$Helper.$3H(0);__divObject.appendChild(closeButton);__divObject.appendChild(__divcontent);__container.appendChild(__divObject);__container.appendChild(__corner);this.$3A(top,left);Element.hide(__divObject);Element.hide(__corner);this.$4t(__targetUrl);};*/function $01(x,y){if(x){this.x=x;}else{this.x=0;};if(y){this.y=y;}else{this.y=0;}};function $02($0o,$0r,$0s,$0t){this.isInRange=function($0y){if(($0o<=$0y.x)&&($0y.x<=$0r)&&($0s<=$0y.y)&&($0y.y<=$0t)){return true;}else{return false;}};this.xMin=$0o;this.xMax=$0r;this.yMin=$0s;this.yMax=$0t;};function $03(top,$0N){this.top=top;this.left=$0N;};function $04($2H,$2I){if($2H){this.width=$2H;}else{this.width=0;};if($2I){this.height=$2I;}else{this.height=0;}};function $05($2J,$1c,$2K,id,$20){this.icons=$2J;this.slCoord=$1c;this.URL=$2K;this.id=id;if($20){this.windowOptions=$20;}else{this.windowOptions=new $09();}};function $06($2J,$1c,$2L){this.icons=$2J;this.slCoord=$1c;this.options=new $08($2L);};function $07($2M,$2L){this.text=$2M;this.options=new $09($2L);};function $08($2L){this.clickHandler=false;this.onMouseOverHandler=false;this.onMouseOutHandler=false;this.centerOnClick=false;this.autopanOnClick=true;this.autopanPadding=45;this.verticalAlign="middle";this.horizontalAlign="center";this.zLayer=0;Object.extend(this,$2L);};function $09($2L){this.windowClass='GENERAL';this.alwaysOnTop=false;this.noEffect=false;this.onlyOneOpen=false;this.closeOnMove=false;this.bringToTop=false;this.closeOnClick=false;this.allowGoThere=false;this.doNothing=false;this.width=252;this.height=236;this.padding=10;Object.extend(this,$2L);};function $0a($2L){this.doubleClickHandler=null;this.hasZoomControls=true;this.hasPanningControls=true;this.onStateChangedHandler=null;this.overlaySpec=null;this.zoomMax=1;this.zoomMin=6;Object.extend(this,$2L);};function $0b($2N,$2O){this.hasShadow=function(){if(this.shadowImg){return true;}else{return false;}};this.mainImg=$2N;if($2O){this.shadowImg=$2O;}};function $0c($2K,$2H,$2I,$2P){this.isAlpha=function(){return this.alpha};this.URL=$2K;this.width=$2H;this.height=$2I;if($2P){this.alpha=true;}else{this.alpha=false;}};function $0d(){this.$3I=function($2Q){return($2Q==$2R)};$2S=navigator.userAgent.toLowerCase();if($2S.indexOf("msie")!=-1){var $2R='ie'}else if($2S.indexOf("mozilla")!=-1){var $2R='gecko'}};$16=new $0d();function $0e(x,y){this.x=x;this.y=y;};function $0f($2T,$2U,$2V,$2W){this.$3Z=function($2T){var $2X=$2T.width;var $2Y=$2T.height;while($2Z.length<$2X){$30=new Array();$2Z.push($30);x=$2Z.length-1;for(y=0;y<$2Y;y++){$1l=new $0e(x,y);$30.push($1l);if($2U){$2U($1l);}}};while($2Z.length>$2X){$31=$2Z.pop();for(y=0;y<$31.length;y++){if($2V){$2V($31[y])}}};for(c=0;c<$2Z.length;c++){$31=$2Z[c];while($31.length<$2Y){var $32=new $0e(c,$31.length-1);$31.push($32);if($2U){$2U($32);}};while($31.length>$2Y){$1l=$31.pop();if($2V){$2V($1l);}}}};this.$4c=function(){if($2Z.length==0){return true;}else{return false;}};this.$4e=function(){return $2Z[0].length;};this.$4d=function(){return $2Z.length;};this.$43=function(){var $33=$2Z.pop();$2Z.unshift($33);for(y=0;y<$33.length;y++){$1l=$33[y];$1l.x=0;$1l.y=y;if($2W){$2W($1l);}}};this.$42=function(){var $34=$2Z.shift();$2Z.push($34);for(y=0;y<$34.length;y++){$1l=$34[y];$1l.x=$2Z.length-1;$1l.y=y;if($2W){$2W($1l);}}};this.$45=function(){for(x=0;x<$2Z.length;x++){$35=$2Z[x].pop();$2Z[x].unshift($35);$35.x=x;$35.y=0;if($2W){$2W($35);}}};this.$44=function(){for(x=0;x<$2Z.length;x++){$36=$2Z[x].shift();$2Z[x].push($36);$36.x=x;$36.y=$2Z[x].length-1;if($2W){$2W($36);}}};this.$3z=function(x,y){return $2Z[x][y];};var self=this;var $2Z=new Array();this.$3Z($2T);};var $0E=new Object();$0E.$3J=function(element,style){element.style.cursor=style};$0E.$3H=function(x){return x+"px";};$0E.$41=function($37){var $38=new $01();while($37){$38.x+=$37.offsetLeft;$38.y+=$37.offsetTop;$37=$37.offsetParent};return $38;};$0E.$40=function($37,$39){var $38=new $01();while($37&&$37!=$39){$38.x+=$37.offsetLeft;$38.y+=$37.offsetTop;$37=$37.offsetParent};return $38;};$0E.$3G=function($3a,$2H,$2I,$0N,top,$3b,$3c){var $3d;if(($3c)&&($16.$3I('ie'))){$3d=document.createElement("span");$3d.loader=document.createElement("img");$3d.loader.style.visibility="hidden";$3d.loader.onload=function(){$3d.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+$3a+"',sizingMethod='crop')";$3d.src=this.src;};if($3a){$3d.loader.src=$3a;}}else{$3d=document.createElement("img");if($3a){$3d.src=$3a;}};$3d.style.border=$0E.$3H(0);$3d.style.position="absolute";if($2H){$3d.style.width=$0E.$3H($2H);$3d.width=$2H};if($2I){$3d.style.height=$0E.$3H($2I);$3d.height=$2I};if(top||top==0){$3d.style.top=$0E.$3H(top)};if($0N||$0N==0){$3d.style.left=$0E.$3H($0N)};if($3b||$3b==0){$3d.style.zIndex=$3b};$3d.oncontextmenu=function(){return false};if($16.$3I('ie')){if(!$3c){$3d.unselectable="on";$3d.galleryimg="no";}};if($16.$3I('gecko')){$3d.style.MozUserSelect="none"};return $3d;};$0E.$4i=function(element,$2L){new Effect.Fade(element,Object.extend({duration:.4},$2L));};$0E.$4h=function(element,$2L){new Effect.Appear(element,Object.extend({duration:.2},$2L));};$0E.$3D=function($0P){if($16.$3I('ie')){$0P.cancelBubble=true;}else{$0P.stopPropagation();}};$0E.$3s=function($3e,$3f,$3g,$3h){this.update=function($3i){var $0D=$3j*$3i+$3k;var $0C=$3l*$3i+$3m;$0g($0D,$0C);};this.before=function(){if($0F.$4n){$0F.$4n()}};this.finish=function(){if($0F.$4o){$0F.$4o()};if($3h){$3h();}};function $0g($0D,$0C){$0F.$4b($0D,$0C);};var $0F=$3e;var $3k=$0F.$4a();var $3m=$0F.$49();var $3j=$3f;var $3l=$3g;Object.extend(this,Effect.Base.prototype);this.before();this.start(arguments[3]);};window.SLMap=$a;window.Marker=$06;window.Icon=$0b;window.Img=$0c;window.XYPoint=$01;window.WindowOptions=$09;window.MapWindow=$07;window.MapOptions=$0a;window.Bounds=$02;window.createImage=$0E.$3G;window.isBrowser=$16.$3I;};SLJS(SERVICES_URL,X_MIN,X_MAX,Y_MIN,Y_MAX);


//<script>
var lh = new Object(); var rlh = new Object(); var o;

function SLPoint (name, local_x, local_y) {
  if(!local_x) { local_x = 0; }
  if(!local_y) { local_y = 0; }
  var downcased_name = name.toLowerCase();
  this.x = lh[downcased_name].x + (local_x / 256);
  this.y = lh[downcased_name].y + (local_y / 256);
}

function gotoSLURL(x,y) {
  // alert($SERVICES_URL + "asset/link?x=" + x + "&y=" + y);
  // $('ifrmxxx').src = $SERVICES_URL + "asset/link?x=" + x + "&y=" + y;
  var int_x = Math.floor(x);
  var int_y = Math.floor(y);
  
  var local_x = Math.round((x - int_x) * 256);
  var local_y = Math.round((y - int_y) * 256);

  var url = "secondlife://" + rlh[int_x + "-" + int_y].replace(/\s/, "_") + "/" + local_x + "/" + local_y;
  document.location = url;
}

function getRegionName(x,y) {
  return rlh[Math.floor(x)+"-"+Math.floor(y)];
}
lh['acceleratenation 1']={x:1156,y:990};rlh['1156-990']='AccelerateNation 1';
lh['acceleratenation 4']={x:1156,y:989};rlh['1156-989']='AccelerateNation 4';
lh['gk machinima island']={x:1155,y:994};rlh['1155-994']='GK Machinima Island';
lh['acceleratenation 2']={x:1157,y:990};rlh['1157-990']='AccelerateNation 2';
lh['reggiano']={x:1176,y:990};rlh['1176-990']='Reggiano';
lh['mizithra']={x:1177,y:991};rlh['1177-991']='Mizithra';
lh['lappi']={x:1176,y:991};rlh['1176-991']='Lappi';
lh['bleu']={x:1175,y:991};rlh['1175-991']='Bleu';
lh['danbo']={x:1176,y:992};rlh['1176-992']='Danbo';
lh['tenshi']={x:1175,y:992};rlh['1175-992']='Tenshi';
lh['tsl weapons testing sandbox']={x:1156,y:1008};rlh['1156-1008']='TSL Weapons Testing Sandbox';
lh['matrix learning']={x:1165,y:986};rlh['1165-986']='Matrix Learning';
lh['foobar salad']={x:1169,y:1000};rlh['1169-1000']='Foobar Salad';
lh['oz island']={x:1162,y:992};rlh['1162-992']='Oz Island';
lh['leviathan']={x:1171,y:1002};rlh['1171-1002']='Leviathan';
lh['schome park']={x:1160,y:987};rlh['1160-987']='Schome Park';
lh['tutorial island']={x:1161,y:1004};rlh['1161-1004']='Tutorial Island';
lh['pacrimx00']={x:1168,y:988};rlh['1168-988']='PacRimX00';
lh['pacrimx01']={x:1169,y:988};rlh['1169-988']='PacRimX01';
lh['pacrimx02']={x:1169,y:987};rlh['1169-987']='PacRimX02';
lh['teen help island']={x:1161,y:1006};rlh['1161-1006']='Teen Help Island';
lh['orientation island tg']={x:1159,y:1008};rlh['1159-1008']='Orientation Island TG';
lh['orientation island 5']={x:1159,y:1006};rlh['1159-1006']='Orientation Island 5';
lh['summertech island']={x:1162,y:990};rlh['1162-990']='SummerTech Island';
lh['rockland']={x:1167,y:977};rlh['1167-977']='Rockland';
lh['eye4you alliance']={x:1164,y:995};rlh['1164-995']='Eye4You Alliance';
lh['suffern']={x:1166,y:978};rlh['1166-978']='Suffern';
lh['ramapo']={x:1166,y:977};rlh['1166-977']='Ramapo';
lh['kids connect']={x:1162,y:994};rlh['1162-994']='Kids Connect';
lh['digital underground']={x:1160,y:993};rlh['1160-993']='Digital Underground';
lh['ohio steam']={x:1160,y:991};rlh['1160-991']='Ohio STEAM';
lh['learnway']={x:1160,y:989};rlh['1160-989']='LearnWay';
lh['youtopia']={x:1162,y:988};rlh['1162-988']='YouTopia';
lh['education station']={x:1159,y:1004};rlh['1159-1004']='Education Station';
lh['svecia']={x:1175,y:993};rlh['1175-993']='Svecia';
lh['gk serious gaming']={x:1156,y:995};rlh['1156-995']='GK Serious Gaming';
lh['kenafa']={x:1174,y:992};rlh['1174-992']='Kenafa';
lh['shasta']={x:1179,y:989};rlh['1179-989']='Shasta';
lh['appalachia']={x:1179,y:988};rlh['1179-988']='Appalachia';
lh['cascade']={x:1178,y:990};rlh['1178-990']='Cascade';
lh['rainier']={x:1178,y:989};rlh['1178-989']='Rainier';
lh['lewis']={x:1162,y:1001};rlh['1162-1001']='Lewis';
lh['oasis']={x:1162,y:1000};rlh['1162-1000']='Oasis';
lh['andretti']={x:1162,y:999};rlh['1162-999']='Andretti';
lh['earnhardt']={x:1162,y:998};rlh['1162-998']='Earnhardt';
lh['card']={x:1161,y:1002};rlh['1161-1002']='Card';
lh['pullman']={x:1161,y:1001};rlh['1161-1001']='Pullman';
lh['adams']={x:1161,y:1000};rlh['1161-1000']='Adams';
lh['loki']={x:1160,y:1002};rlh['1160-1002']='Loki';
lh['hippoden']={x:1160,y:1001};rlh['1160-1001']='Hippoden';
lh['hyperion']={x:1159,y:1002};rlh['1159-1002']='Hyperion';
lh['ni']={x:1159,y:1001};rlh['1159-1001']='Ni';
lh['midway battlegrounds']={x:1156,y:1006};rlh['1156-1006']='Midway Battlegrounds';
lh['lexington']={x:1156,y:1004};rlh['1156-1004']='Lexington';
lh['bannockburn']={x:1155,y:1006};rlh['1155-1006']='Bannockburn';
lh['no mans land']={x:1155,y:1004};rlh['1155-1004']='No Mans Land';
lh['sandbox island (tg)']={x:1156,y:1002};rlh['1156-1002']='Sandbox Island (TG)';
lh['sandbox island 2 (tg)']={x:1156,y:1001};rlh['1156-1001']='Sandbox Island 2 (TG)';
lh['concord']={x:1154,y:1004};rlh['1154-1004']='Concord';
lh['sandbox island 3 (tg)']={x:1155,y:1002};rlh['1155-1002']='Sandbox Island 3 (TG)';
lh['sandbox island 4 (tg)']={x:1155,y:1001};rlh['1155-1001']='Sandbox Island 4 (TG)';
lh['tahoe']={x:1177,y:990};rlh['1177-990']='Tahoe';
lh['zaius']={x:1168,y:997};rlh['1168-997']='Zaius';
lh['bull']={x:1169,y:995};rlh['1169-995']='Bull';
lh['alcove']={x:1167,y:1002};rlh['1167-1002']='Alcove';
lh['sierra']={x:1177,y:989};rlh['1177-989']='Sierra';
lh['pop']={x:1174,y:994};rlh['1174-994']='Pop';
lh['opera']={x:1174,y:993};rlh['1174-993']='Opera';
lh['tremelo']={x:1173,y:994};rlh['1173-994']='Tremelo';
lh['camden']={x:1172,y:996};rlh['1172-996']='Camden';
lh['yarmouth']={x:1172,y:997};rlh['1172-997']='Yarmouth';
lh['arpeggio']={x:1173,y:993};rlh['1173-993']='Arpeggio';
lh['huntingdon']={x:1172,y:995};rlh['1172-995']='Huntingdon';
lh['brighton']={x:1172,y:994};rlh['1172-994']='Brighton';
lh['coda']={x:1172,y:993};rlh['1172-993']='Coda';
lh['nailsworth']={x:1171,y:997};rlh['1171-997']='Nailsworth';
lh['swansea']={x:1171,y:996};rlh['1171-996']='Swansea';
lh['warwick']={x:1170,y:997};rlh['1170-997']='Warwick';
lh['derby']={x:1171,y:995};rlh['1171-995']='Derby';
lh['lancashire']={x:1171,y:994};rlh['1171-994']='Lancashire';
lh['scarborough']={x:1170,y:996};rlh['1170-996']='Scarborough';
lh['boscombe']={x:1170,y:995};rlh['1170-995']='Boscombe';
lh['teen campus north']={x:1159,y:998};rlh['1159-998']='Teen Campus North';
lh['lodestone']={x:1169,y:997};rlh['1169-997']='Lodestone';
lh['eden']={x:1168,y:1002};rlh['1168-1002']='Eden';
lh['gordon']={x:1163,y:998};rlh['1163-998']='Gordon';
lh['stewart']={x:1163,y:999};rlh['1163-999']='Stewart';
lh['coelacanth']={x:1163,y:1000};rlh['1163-1000']='Coelacanth';
lh['behemoth']={x:1164,y:997};rlh['1164-997']='Behemoth';
lh['martin']={x:1164,y:998};rlh['1164-998']='Martin';
lh['biffle']={x:1164,y:999};rlh['1164-999']='Biffle';
lh['architeuthis']={x:1164,y:1000};rlh['1164-1000']='Architeuthis';
lh['dougall']={x:1165,y:997};rlh['1165-997']='Dougall';
lh['crustacea']={x:1165,y:998};rlh['1165-998']='Crustacea';
lh['delphinidae']={x:1165,y:999};rlh['1165-999']='Delphinidae';
lh['meiji west']={x:1166,y:997};rlh['1166-997']='Meiji West';
lh['carroll']={x:1166,y:998};rlh['1166-998']='Carroll';
lh['rowling']={x:1167,y:996};rlh['1167-996']='Rowling';
lh['meiji east']={x:1167,y:997};rlh['1167-997']='Meiji East';
lh['tolkien']={x:1167,y:998};rlh['1167-998']='Tolkien';
lh['pinkwater']={x:1168,y:995};rlh['1168-995']='Pinkwater';
lh['snicket']={x:1168,y:996};rlh['1168-996']='Snicket';
lh['ohio teen']={x:1164,y:988};rlh['1164-988']='Ohio Teen';
lh['global kids']={x:1155,y:995};rlh['1155-995']='Global Kids';
lh['unreal']={x:1165,y:1002};rlh['1165-1002']='Unreal';
lh['focus']={x:1084,y:1120};rlh['1084-1120']='Focus';
lh['nix']={x:1162,y:1002};rlh['1162-1002']='Nix';
lh['alloy']={x:1169,y:996};rlh['1169-996']='Alloy';
lh['acceleratenation 3']={x:1157,y:989};rlh['1157-989']='AccelerateNation 3';
lh['eclivian']={x:1171,y:1000};rlh['1171-1000']='Eclivian';
lh['teen campus']={x:1159,y:997};rlh['1159-997']='Teen Campus';
lh['britishcouncil isle']={x:1166,y:993};rlh['1166-993']='BritishCouncil Isle';
lh['financial island']={x:1166,y:988};rlh['1166-988']='Financial Island';
lh['teen help island 2']={x:1161,y:1008};rlh['1161-1008']='Teen Help Island 2';
lh['britishcouncil isle2']={x:1167,y:993};rlh['1167-993']='BritishCouncil Isle2';
lh['dernier cri']={x:1167,y:1000};rlh['1167-1000']='Dernier Cri';
lh['britishcouncil isle3']={x:1167,y:992};rlh['1167-992']='BritishCouncil Isle3';
lh['tech savvy isle']={x:1157,y:979};rlh['1157-979']='Tech Savvy Isle';
lh['p21 island']={x:1162,y:984};rlh['1162-984']='P21 Island';
lh['digischool']={x:1162,y:986};rlh['1162-986']='Digischool';
lh['evolve']={x:1173,y:1000};rlh['1173-1000']='Evolve';
lh['oakland heights']={x:1173,y:1002};rlh['1173-1002']='Oakland Heights';
lh['dunoon grammar school']={x:1160,y:983};rlh['1160-983']='Dunoon Grammar School';
lh['bailey']={x:1160,y:985};rlh['1160-985']='Bailey';
lh['sawnee island']={x:1164,y:984};rlh['1164-984']='Sawnee Island';
lh['skoolaborate']={x:1151,y:983};rlh['1151-983']='Skoolaborate';
lh['onecleveland tg']={x:1164,y:993};rlh['1164-993']='OneCleveland TG';
lh['airmont']={x:1167,y:978};rlh['1167-978']='Airmont';
lh['harriman']={x:1168,y:977};rlh['1168-977']='Harriman';
lh['indian rock']={x:1168,y:978};rlh['1168-978']='Indian Rock';
lh['civitas']={x:1170,y:1002};rlh['1170-1002']='Civitas';
lh['be the game']={x:1164,y:982};rlh['1164-982']='Be The Game';
lh['piercetg']={x:1150,y:990};rlh['1150-990']='PierceTG';
lh['westheimer']={x:1151,y:990};rlh['1151-990']='Westheimer';
lh['allentg']={x:1152,y:990};rlh['1152-990']='AllenTG';
lh['bissonnet']={x:1153,y:990};rlh['1153-990']='Bissonnet';
lh['ecpat']={x:1164,y:980};rlh['1164-980']='ECPAT';
lh['michigan tech tg']={x:1162,y:980};rlh['1162-980']='Michigan Tech TG';
lh['dunstonia']={x:1166,y:984};rlh['1166-984']='Dunstonia';
lh['ctrl z']={x:1152,y:1001};rlh['1152-1001']='CTRL Z';
lh['shift']={x:1152,y:1002};rlh['1152-1002']='Shift';
lh['alt']={x:1153,y:1001};rlh['1153-1001']='Alt';
lh['tron']={x:1153,y:1002};rlh['1153-1002']='TrOn';
lh['credit union']={x:1166,y:982};rlh['1166-982']='Credit Union';
lh['elysia']={x:1167,y:1004};rlh['1167-1004']='Elysia';
lh['skoolaborate 2']={x:1151,y:982};rlh['1151-982']='Skoolaborate 2';
lh['the didi initiative']={x:1154,y:995};rlh['1154-995']='The DIDI Initiative';
lh['kenict eiland west']={x:1156,y:982};rlh['1156-982']='Kenict Eiland West';
lh['kenict eiland oost']={x:1157,y:982};rlh['1157-982']='Kenict Eiland Oost';
lh['abel tg']={x:1161,y:978};rlh['1161-978']='ABEL TG';
lh['tec island']={x:1163,y:978};rlh['1163-978']='TEC Island';
lh['tsl volunteer island']={x:1159,y:1004};rlh['1159-1004']='TSL Volunteer Island';
lh['okarthel']={x:1165,y:1004};rlh['1165-1004']='Okarthel';
lh['carthago']={x:1165,y:1006};rlh['1165-1006']='Carthago';
lh['red llama island']={x:1168,y:982};rlh['1168-982']='Red Llama Island';
lh['selfcity']={x:1168,y:984};rlh['1168-984']='SelfCity';
lh['furry plateau']={x:1169,y:1004};rlh['1169-1004']='Furry Plateau';
lh['greenbush education']={x:1170,y:982};rlh['1170-982']='Greenbush Education';
lh['hulahoop']={x:1173,y:1002};rlh['1173-1002']='Hulahoop';
//</script>